git.delta.rocks / jrsonnet / refs/commits / cf33b6edf3e1

difftreelog

source

crates/jrsonnet-evaluator/src/arr/mod.rs4.6 KiBsourcehistory
1use std::{2	any::Any,3	fmt::{self},4	num::NonZeroU32,5	rc::Rc,6};78use jrsonnet_gcmodule::{Cc, cc_dyn};910use crate::{Context, Result, Thunk, Val, analyze::LExpr, function::NativeFn, typed::IntoUntyped};1112mod spec;13pub use spec::{ArrayLike, *};1415cc_dyn!(16	#[doc = "Represents a Jsonnet array value."]17	#[derive(Clone)]18	ArrValue,19	ArrayLike,20	pub fn new() {...}21);22impl fmt::Debug for ArrValue {23	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {24		self.0.fmt(f)25	}26}2728pub trait ArrayLikeIter<T>: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator {}29impl<I, T> ArrayLikeIter<T> for I where30	I: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator31{32}3334impl ArrValue {35	pub fn empty() -> Self {36		Self::new(())37	}3839	pub fn expr(ctx: Context, exprs: Rc<Vec<LExpr>>) -> Self {40		Self::new(ExprArray::new(ctx, exprs))41	}4243	pub fn repeated(data: Self, repeats: u32) -> Option<Self> {44		Some(Self::new(RepeatedArray::new(data, repeats)?))45	}4647	pub fn make(len: u32, cb: NativeFn!((u32,)->Val)) -> Self {48		Self::new(MakeArray::new(len, cb))49	}5051	#[must_use]52	pub fn map(self, mapper: NativeFn!((Val) -> Val)) -> Self {53		Self::new(<MappedArray>::new(self, ArrayMapper::Plain(mapper)))54	}5556	#[must_use]57	pub fn map_with_index(self, mapper: NativeFn!((u32, Val) -> Val)) -> Self {58		Self::new(<MappedArray>::new(self, ArrayMapper::WithIndex(mapper)))59	}6061	pub fn filter(self, filter: NativeFn!((Thunk<Val>) -> bool)) -> Result<Self> {62		// TODO: ArrValue::Picked(inner, indexes) for large arrays63		'eager: {64			let mut out = Vec::new();65			for i in self.iter() {66				let Ok(i) = i else {67					break 'eager;68				};69				if filter.call(IntoUntyped::into_lazy_untyped(i.clone()))? {70					out.push(i);71				}72			}73			return Ok(Self::new(out));74		};7576		let mut out = Vec::new();77		for i in self.iter_lazy() {78			if filter.call(i.clone())? {79				out.push(i);80			}81		}82		Ok(Self::new(out))83	}8485	pub fn extended(a: Self, b: Self) -> Option<Self> {86		Some(if a.is_empty() {87			b88		} else if b.is_empty() {89			a90		} else {91			Self::new(ExtendedArray::new(a, b)?)92		})93	}9495	pub fn range_exclusive(a: i32, b: i32) -> Self {96		Self::new(RangeArray::new_exclusive(a, b))97	}98	pub fn range_inclusive(a: i32, b: i32) -> Self {99		Self::new(RangeArray::new_inclusive(a, b))100	}101102	#[must_use]103	pub fn slice(self, index: Option<i32>, end: Option<i32>, step: Option<NonZeroU32>) -> Self {104		let get_idx = |pos: Option<i32>, len: u32, default| match pos {105			#[expect(106				clippy::cast_sign_loss,107				reason = "abs value is used, len is limited to u31"108			)]109			Some(v) if v < 0 => len.saturating_add_signed(v),110			#[expect(clippy::cast_sign_loss, reason = "abs value is used")]111			Some(v) => (v as u32).min(len),112			None => default,113		};114		let index = get_idx(index, self.len(), 0);115		let end = get_idx(end, self.len(), self.len());116		let step = step.unwrap_or_else(|| NonZeroU32::new(1).expect("1 != 0"));117118		if index >= end {119			return Self::empty();120		}121122		Self::new(SliceArray {123			inner: self,124			#[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")]125			from: index as u32,126			#[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")]127			to: end as u32,128			step: step.get(),129		})130	}131132	/// Array length.133	pub fn len(&self) -> u32 {134		self.0.len()135	}136137	/// Is array contains no elements?138	pub fn is_empty(&self) -> bool {139		self.0.is_empty()140	}141142	pub fn is_cheap(&self) -> bool {143		self.0.is_cheap()144	}145146	/// Get array element by index, evaluating it, if it is lazy.147	///148	/// Returns `None` on out-of-bounds condition.149	pub fn get(&self, index: u32) -> Result<Option<Val>> {150		self.0.get(index)151	}152153	/// Get array element by index, without evaluation.154	///155	/// Returns `None` on out-of-bounds condition.156	pub fn get_lazy(&self, index: u32) -> Option<Thunk<Val>> {157		self.0.get_lazy(index)158	}159160	pub fn iter(&self) -> impl ArrayLikeIter<Result<Val>> + '_ {161		(0..self.len()).map(|i| self.get(i).transpose().expect("length checked"))162	}163164	/// Iterate over elements, returning lazy values.165	pub fn iter_lazy(&self) -> impl ArrayLikeIter<Thunk<Val>> + '_ {166		(0..self.len()).map(|i| self.get_lazy(i).expect("length checked"))167	}168169	/// Return a reversed view on current array.170	#[must_use]171	pub fn reversed(self) -> Self {172		Self::new(ReverseArray(self))173	}174175	pub fn ptr_eq(a: &Self, b: &Self) -> bool {176		Cc::ptr_eq(&a.0, &b.0)177	}178179	pub fn as_any(&self) -> &dyn Any {180		&self.0181	}182}183impl<T> From<T> for ArrValue184where185	T: ArrayLike,186{187	fn from(value: T) -> Self {188		Self::new(value)189	}190}191impl<I> FromIterator<I> for ArrValue192where193	Vec<I>: ArrayLike,194{195	fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {196		Self::new(iter.into_iter().collect::<Vec<_>>())197	}198}