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

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::{11	Context, Result, Thunk, Val,12	analyze::{ClosureShape, LExpr},13	function::NativeFn,14	typed::IntoUntyped,15};1617mod spec;18pub use spec::{ArrayLike, *};1920cc_dyn!(21	#[doc = "Represents a Jsonnet array value."]22	#[derive(Clone)]23	ArrValue,24	ArrayLike,25	pub fn new() {...}26);27impl fmt::Debug for ArrValue {28	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {29		self.0.fmt(f)30	}31}3233pub trait ArrayLikeIter<T>: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator {}34impl<I, T> ArrayLikeIter<T> for I where35	I: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator36{37}3839impl ArrValue {40	pub fn empty() -> Self {41		Self::new(())42	}4344	pub fn expr(ctx: Context, shape: &ClosureShape, exprs: Rc<Vec<LExpr>>) -> Self {45		Self::new(ExprArray::new(ctx, shape, exprs))46	}4748	pub fn repeated(data: Self, repeats: u32) -> Option<Self> {49		Some(Self::new(RepeatedArray::new(data, repeats)?))50	}5152	pub fn make(len: u32, cb: NativeFn!((u32,)->Val)) -> Self {53		Self::new(MakeArray::new(len, cb))54	}5556	#[must_use]57	pub fn map(self, mapper: NativeFn!((Val) -> Val)) -> Self {58		Self::new(<MappedArray>::new(self, ArrayMapper::Plain(mapper)))59	}6061	#[must_use]62	pub fn map_with_index(self, mapper: NativeFn!((u32, Val) -> Val)) -> Self {63		Self::new(<MappedArray>::new(self, ArrayMapper::WithIndex(mapper)))64	}6566	pub fn filter(self, filter: NativeFn!((Thunk<Val>) -> bool)) -> Result<Self> {67		// TODO: ArrValue::Picked(inner, indexes) for large arrays68		'eager: {69			let mut out = Vec::new();70			for i in self.iter() {71				let Ok(i) = i else {72					break 'eager;73				};74				if filter.call(IntoUntyped::into_lazy_untyped(i.clone()))? {75					out.push(i);76				}77			}78			return Ok(Self::new(out));79		};8081		let mut out = Vec::new();82		for i in self.iter_lazy() {83			if filter.call(i.clone())? {84				out.push(i);85			}86		}87		Ok(Self::new(out))88	}8990	pub fn extended(a: Self, b: Self) -> Option<Self> {91		Some(if a.is_empty() {92			b93		} else if b.is_empty() {94			a95		} else {96			Self::new(ExtendedArray::new(a, b)?)97		})98	}99100	pub fn range_exclusive(a: i32, b: i32) -> Self {101		Self::new(RangeArray::new_exclusive(a, b))102	}103	pub fn range_inclusive(a: i32, b: i32) -> Self {104		Self::new(RangeArray::new_inclusive(a, b))105	}106107	#[must_use]108	pub fn slice(self, index: Option<i32>, end: Option<i32>, step: Option<NonZeroU32>) -> Self {109		let get_idx = |pos: Option<i32>, len: u32, default| match pos {110			#[expect(111				clippy::cast_sign_loss,112				reason = "abs value is used, len is limited to u31"113			)]114			Some(v) if v < 0 => len.saturating_add_signed(v),115			#[expect(clippy::cast_sign_loss, reason = "abs value is used")]116			Some(v) => (v as u32).min(len),117			None => default,118		};119		let index = get_idx(index, self.len(), 0);120		let end = get_idx(end, self.len(), self.len());121		let step = step.unwrap_or_else(|| NonZeroU32::new(1).expect("1 != 0"));122123		if index >= end {124			return Self::empty();125		}126127		Self::new(SliceArray {128			inner: self,129			#[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")]130			from: index as u32,131			#[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")]132			to: end as u32,133			step: step.get(),134		})135	}136137	/// Array length.138	pub fn len(&self) -> u32 {139		self.0.len()140	}141142	/// Is array contains no elements?143	pub fn is_empty(&self) -> bool {144		self.0.is_empty()145	}146147	pub fn is_cheap(&self) -> bool {148		self.0.is_cheap()149	}150151	/// Get array element by index, evaluating it, if it is lazy.152	///153	/// Returns `None` on out-of-bounds condition.154	pub fn get(&self, index: u32) -> Result<Option<Val>> {155		self.0.get(index)156	}157158	/// Get array element by index, without evaluation.159	///160	/// Returns `None` on out-of-bounds condition.161	pub fn get_lazy(&self, index: u32) -> Option<Thunk<Val>> {162		self.0.get_lazy(index)163	}164165	pub fn iter(&self) -> impl ArrayLikeIter<Result<Val>> + '_ {166		(0..self.len()).map(|i| self.get(i).transpose().expect("length checked"))167	}168169	/// Iterate over elements, returning lazy values.170	pub fn iter_lazy(&self) -> impl ArrayLikeIter<Thunk<Val>> + '_ {171		(0..self.len()).map(|i| self.get_lazy(i).expect("length checked"))172	}173174	/// Return a reversed view on current array.175	#[must_use]176	pub fn reversed(self) -> Self {177		Self::new(ReverseArray(self))178	}179180	pub fn ptr_eq(a: &Self, b: &Self) -> bool {181		Cc::ptr_eq(&a.0, &b.0)182	}183184	pub fn as_any(&self) -> &dyn Any {185		&self.0186	}187}188impl<T> From<T> for ArrValue189where190	T: ArrayLike,191{192	fn from(value: T) -> Self {193		Self::new(value)194	}195}196impl<I> FromIterator<I> for ArrValue197where198	Vec<I>: ArrayLike,199{200	fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {201		Self::new(iter.into_iter().collect::<Vec<_>>())202	}203}