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

difftreelog

source

crates/jrsonnet-evaluator/src/arr/mod.rs7.1 KiBsourcehistory
1use jrsonnet_gcmodule::{Cc, Trace};2use jrsonnet_interner::IBytes;3use jrsonnet_parser::LocExpr;45use crate::{function::FuncVal, Context, Result, Thunk, Val};67mod spec;8use spec::*;910/// Represents a Jsonnet array value.11#[derive(Debug, Clone, Trace)]12// may contrain other ArrValue13#[trace(tracking(force))]14pub enum ArrValue {15	/// Layout optimized byte array.16	Bytes(BytesArray),17	/// Every element is lazy evaluated.18	Lazy(LazyArray),19	/// Every element is defined somewhere in source code20	Expr(ExprArray),21	/// Every field is already evaluated.22	Eager(EagerArray),23	/// Concatenation of two arrays of any kind.24	Extended(Cc<ExtendedArray>),25	/// Represents a integer array in form `[start, start + 1, ... end - 1, end]`.26	/// This kind of arrays is generated by `std.range(start, end)` call, and used for loops.27	Range(RangeArray),28	/// Sliced array view.29	Slice(Cc<SliceArray>),30	/// Reversed array view.31	/// Returned by `std.reverse(other)` call32	Reverse(Cc<ReverseArray>),33	/// Returned by `std.map` call34	Mapped(MappedArray),35	/// Returned by `std.repeat` call36	Repeated(RepeatedArray),37}3839pub trait ArrayLikeIter<T>: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator {}40impl<I, T> ArrayLikeIter<T> for I where41	I: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator42{43}4445impl ArrValue {46	pub fn empty() -> Self {47		Self::Range(RangeArray::empty())48	}4950	pub fn expr(ctx: Context, exprs: impl IntoIterator<Item = LocExpr>) -> Self {51		Self::Expr(ExprArray::new(ctx, exprs))52	}5354	pub fn lazy(thunks: Cc<Vec<Thunk<Val>>>) -> Self {55		Self::Lazy(LazyArray(thunks))56	}5758	pub fn eager(values: Vec<Val>) -> Self {59		Self::Eager(EagerArray(Cc::new(values)))60	}6162	pub fn repeated(data: ArrValue, repeats: usize) -> Option<Self> {63		Some(Self::Repeated(RepeatedArray::new(data, repeats)?))64	}6566	pub fn bytes(bytes: IBytes) -> Self {67		Self::Bytes(BytesArray(bytes))68	}6970	#[must_use]71	pub fn map(self, mapper: FuncVal) -> Self {72		Self::Mapped(MappedArray::new(self, mapper))73	}7475	pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {76		// TODO: ArrValue::Picked(inner, indexes) for large arrays77		let mut out = Vec::new();78		for i in self.iter() {79			let i = i?;80			if filter(&i)? {81				out.push(i);82			};83		}84		Ok(Self::eager(out))85	}8687	pub fn extended(a: ArrValue, b: ArrValue) -> Self {88		// TODO: benchmark for an optimal value, currently just a arbitrary choice89		const ARR_EXTEND_THRESHOLD: usize = 100;9091		if a.is_empty() {92			b93		} else if b.is_empty() {94			a95		} else if a.len() + b.len() > ARR_EXTEND_THRESHOLD {96			Self::Extended(Cc::new(ExtendedArray::new(a, b)))97		} else if let (Some(a), Some(b)) = (a.iter_cheap(), b.iter_cheap()) {98			let mut out = Vec::with_capacity(a.len() + b.len());99			out.extend(a);100			out.extend(b);101			Self::eager(out)102		} else {103			let mut out = Vec::with_capacity(a.len() + b.len());104			out.extend(a.iter_lazy());105			out.extend(b.iter_lazy());106			Self::lazy(Cc::new(out))107		}108	}109110	pub fn range_exclusive(a: i32, b: i32) -> Self {111		Self::Range(RangeArray::new_exclusive(a, b))112	}113	pub fn range_inclusive(a: i32, b: i32) -> Self {114		Self::Range(RangeArray::new_inclusive(a, b))115	}116117	#[must_use]118	pub fn slice(119		self,120		from: Option<usize>,121		to: Option<usize>,122		step: Option<usize>,123	) -> Option<Self> {124		let len = self.len();125		let from = from.unwrap_or(0);126		let to = to.unwrap_or(len).min(len);127		let step = step.unwrap_or(1);128129		if from >= to || step == 0 {130			return None;131		}132		// match self {133		// 	ArrValue::Slice(slice) => {134		// 		return Some(Self::Slice(Cc::new(SliceArray {135		// 			inner: slice.inner.clone(),136		// 			from: slice.from + slice.step * (from as u32),137		// 			to: slice.from + (to as u32) * slice.step,138		// 			step: slice.step * step as u32,139		// 		})))140		// 	}141		// 	_ => {}142		// }143144		Some(Self::Slice(Cc::new(SliceArray {145			inner: self,146			from: from as u32,147			to: to as u32,148			step: step as u32,149		})))150	}151152	/// Array length.153	pub fn len(&self) -> usize {154		pass!(self.len())155	}156157	/// Is array contains no elements?158	pub fn is_empty(&self) -> bool {159		pass!(self.is_empty())160	}161162	/// Get array element by index, evaluating it, if it is lazy.163	///164	/// Returns `None` on out-of-bounds condition.165	pub fn get(&self, index: usize) -> Result<Option<Val>> {166		pass!(self.get(index))167	}168169	/// Returns None if get is either non cheap, or out of bounds170	fn get_cheap(&self, index: usize) -> Option<Val> {171		pass!(self.get_cheap(index))172	}173174	/// Get array element by index, without evaluation.175	///176	/// Returns `None` on out-of-bounds condition.177	pub fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {178		pass!(self.get_lazy(index))179	}180181	#[cfg(feature = "nightly")]182	pub fn iter(&self) -> UnknownArrayIter<'_> {183		pass_iter_call!(self.iter => UnknownArrayIter)184	}185	#[cfg(not(feature = "nightly"))]186	pub fn iter(&self) -> impl ArrayLikeIter<Result<Val>> + '_ {187		(0..self.len()).map(|i| self.get(i).transpose().expect("length checked"))188	}189190	/// Iterate over elements, returning lazy values.191	#[cfg(feature = "nightly")]192	pub fn iter_lazy(&self) -> UnknownArrayIterLazy<'_> {193		pass_iter_call!(self.iter_lazy => UnknownArrayIterLazy)194	}195	#[cfg(not(feature = "nightly"))]196	pub fn iter_lazy(&self) -> impl ArrayLikeIter<Thunk<Val>> + '_ {197		(0..self.len()).map(|i| self.get_lazy(i).expect("length checked"))198	}199200	#[cfg(feature = "nightly")]201	pub fn iter_cheap(&self) -> Option<UnknownArrayIterCheap<'_>> {202		macro_rules! question {203			($v:expr) => {204				$v?205			};206		}207		Some(pass_iter_call!(self.iter_cheap in question => UnknownArrayIterCheap))208	}209210	#[cfg(not(feature = "nightly"))]211	pub fn iter_cheap(&self) -> Option<impl ArrayLikeIter<Val> + '_> {212		if self.is_cheap() {213			Some((0..self.len()).map(|i| self.get_cheap(i).expect("length and is_cheap checked")))214		} else {215			None216		}217	}218219	/// Return a reversed view on current array.220	#[must_use]221	pub fn reversed(self) -> Self {222		Self::Reverse(Cc::new(ReverseArray(self)))223	}224225	pub fn ptr_eq(a: &Self, b: &Self) -> bool {226		match (a, b) {227			(ArrValue::Bytes(a), ArrValue::Bytes(b)) => a.0 == b.0,228			(ArrValue::Lazy(a), ArrValue::Lazy(b)) => Cc::ptr_eq(&a.0, &b.0),229			(ArrValue::Expr(a), ArrValue::Expr(b)) => Cc::ptr_eq(&a.0, &b.0),230			(ArrValue::Eager(a), ArrValue::Eager(b)) => Cc::ptr_eq(&a.0, &b.0),231			(ArrValue::Extended(a), ArrValue::Extended(b)) => Cc::ptr_eq(a, b),232			(ArrValue::Range(a), ArrValue::Range(b)) => a == b,233			_ => false,234		}235	}236237	pub fn is_cheap(&self) -> bool {238		match self {239			ArrValue::Eager(_) | ArrValue::Range(..) | ArrValue::Bytes(_) => true,240			ArrValue::Extended(v) => v.a.is_cheap() && v.b.is_cheap(),241			ArrValue::Slice(r) => r.inner.is_cheap(),242			ArrValue::Reverse(i) => i.0.is_cheap(),243			ArrValue::Repeated(v) => v.is_cheap(),244			ArrValue::Expr(_) | ArrValue::Lazy(_) | ArrValue::Mapped(_) => false,245		}246	}247}248impl From<Vec<Val>> for ArrValue {249	fn from(value: Vec<Val>) -> Self {250		Self::eager(value)251	}252}253impl From<Vec<Thunk<Val>>> for ArrValue {254	fn from(value: Vec<Thunk<Val>>) -> Self {255		Self::lazy(Cc::new(value))256	}257}258impl FromIterator<Val> for ArrValue {259	fn from_iter<T: IntoIterator<Item = Val>>(iter: T) -> Self {260		Self::eager(iter.into_iter().collect())261	}262}263264#[cfg(target_pointer_width = "64")]265static_assertions::assert_eq_size!(ArrValue, [u8; 16]);