git.delta.rocks / jrsonnet / refs/commits / 7af406eaa740

difftreelog

source

crates/jrsonnet-evaluator/src/arr/mod.rs4.5 KiBsourcehistory
1use std::{2	any::Any,3	fmt::{self},4	num::NonZeroU32,5	rc::Rc,6};78use jrsonnet_gcmodule::{Cc, cc_dyn};9use jrsonnet_ir::Expr;1011use crate::{Context, Result, Thunk, Val, function::NativeFn, typed::IntoUntyped};1213mod spec;14pub use spec::{ArrayLike, *};1516cc_dyn!(17	#[doc = "Represents a Jsonnet array value."]18	#[derive(Clone)]19	ArrValue,20	ArrayLike,21	pub fn new() {...}22);23impl fmt::Debug for ArrValue {24	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {25		self.0.fmt(f)26	}27}2829pub trait ArrayLikeIter<T>: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator {}30impl<I, T> ArrayLikeIter<T> for I where31	I: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator32{33}3435impl ArrValue {36	pub fn empty() -> Self {37		Self::new(())38	}3940	pub fn expr(ctx: Context, exprs: Rc<Vec<Expr>>) -> Self {41		Self::new(ExprArray::new(ctx, exprs))42	}4344	pub fn repeated(data: Self, repeats: usize) -> Option<Self> {45		Some(Self::new(RepeatedArray::new(data, repeats)?))46	}4748	#[must_use]49	pub fn map(self, mapper: NativeFn!((Val) -> Val)) -> Self {50		Self::new(<MappedArray>::new(self, ArrayMapper::Plain(mapper)))51	}5253	#[must_use]54	pub fn map_with_index(self, mapper: NativeFn!((u32, Val) -> Val)) -> Self {55		Self::new(<MappedArray>::new(self, ArrayMapper::WithIndex(mapper)))56	}5758	pub fn filter(self, filter: NativeFn!((Thunk<Val>) -> bool)) -> Result<Self> {59		// TODO: ArrValue::Picked(inner, indexes) for large arrays60		'eager: {61			let mut out = Vec::new();62			for i in self.iter() {63				let Ok(i) = i else {64					break 'eager;65				};66				if filter.call(IntoUntyped::into_lazy_untyped(i.clone()))? {67					out.push(i);68				}69			}70			return Ok(Self::new(out));71		};7273		let mut out = Vec::new();74		for i in self.iter_lazy() {75			if filter.call(i.clone())? {76				out.push(i);77			}78		}79		Ok(Self::new(out))80	}8182	pub fn extended(a: Self, b: Self) -> Self {83		if a.is_empty() {84			b85		} else if b.is_empty() {86			a87		} else {88			Self::new(ExtendedArray::new(a, b))89		}90	}9192	pub fn range_exclusive(a: i32, b: i32) -> Self {93		Self::new(RangeArray::new_exclusive(a, b))94	}95	pub fn range_inclusive(a: i32, b: i32) -> Self {96		Self::new(RangeArray::new_inclusive(a, b))97	}9899	#[must_use]100	pub fn slice(self, index: Option<i32>, end: Option<i32>, step: Option<NonZeroU32>) -> Self {101		let get_idx = |pos: Option<i32>, len: usize, default| match pos {102			#[expect(103				clippy::cast_sign_loss,104				reason = "abs value is used, len is limited to u31"105			)]106			Some(v) if v < 0 => len.saturating_sub((-v) as usize),107			#[expect(clippy::cast_sign_loss, reason = "abs value is used")]108			Some(v) => (v as usize).min(len),109			None => default,110		};111		let index = get_idx(index, self.len(), 0);112		let end = get_idx(end, self.len(), self.len());113		let step = step.unwrap_or_else(|| NonZeroU32::new(1).expect("1 != 0"));114115		if index >= end {116			return Self::empty();117		}118119		Self::new(SliceArray {120			inner: self,121			#[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")]122			from: index as u32,123			#[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")]124			to: end as u32,125			step: step.get(),126		})127	}128129	/// Array length.130	pub fn len(&self) -> usize {131		self.0.len()132	}133134	/// Is array contains no elements?135	pub fn is_empty(&self) -> bool {136		self.0.is_empty()137	}138139	pub fn is_cheap(&self) -> bool {140		self.0.is_cheap()141	}142143	/// Get array element by index, evaluating it, if it is lazy.144	///145	/// Returns `None` on out-of-bounds condition.146	pub fn get(&self, index: usize) -> Result<Option<Val>> {147		self.0.get(index)148	}149150	/// Get array element by index, without evaluation.151	///152	/// Returns `None` on out-of-bounds condition.153	pub fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {154		self.0.get_lazy(index)155	}156157	pub fn iter(&self) -> impl ArrayLikeIter<Result<Val>> + '_ {158		(0..self.len()).map(|i| self.get(i).transpose().expect("length checked"))159	}160161	/// Iterate over elements, returning lazy values.162	pub fn iter_lazy(&self) -> impl ArrayLikeIter<Thunk<Val>> + '_ {163		(0..self.len()).map(|i| self.get_lazy(i).expect("length checked"))164	}165166	/// Return a reversed view on current array.167	#[must_use]168	pub fn reversed(self) -> Self {169		Self::new(ReverseArray(self))170	}171172	pub fn ptr_eq(a: &Self, b: &Self) -> bool {173		Cc::ptr_eq(&a.0, &b.0)174	}175176	pub fn as_any(&self) -> &dyn Any {177		&self.0178	}179}180impl<T> From<T> for ArrValue181where182	T: ArrayLike,183{184	fn from(value: T) -> Self {185		Self::new(value)186	}187}188impl<I> FromIterator<I> for ArrValue189where190	Vec<I>: ArrayLike,191{192	fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {193		Self::new(iter.into_iter().collect::<Vec<_>>())194	}195}