git.delta.rocks / jrsonnet / refs/commits / 4944c9eb9e42

difftreelog

refactor drop CharArray

rzmtutyqYaroslav Bolyukin2026-04-04parent: #6f6b79f.patch.diff
in: master

5 files changed

modifiedcrates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/arr/mod.rs
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	pub fn chars(chars: impl Iterator<Item = char>) -> Self {49		Self::new(CharArray(chars.collect()))50	}5152	#[must_use]53	pub fn map(self, mapper: NativeFn!((Val) -> Val)) -> Self {54		Self::new(<MappedArray>::new(self, ArrayMapper::Plain(mapper)))55	}5657	#[must_use]58	pub fn map_with_index(self, mapper: NativeFn!((u32, Val) -> Val)) -> Self {59		Self::new(<MappedArray>::new(self, ArrayMapper::WithIndex(mapper)))60	}6162	pub fn filter(self, filter: NativeFn!((Thunk<Val>) -> bool)) -> Result<Self> {63		// TODO: ArrValue::Picked(inner, indexes) for large arrays64		'eager: {65			let mut out = Vec::new();66			for i in self.iter() {67				let Ok(i) = i else {68					break 'eager;69				};70				if filter.call(IntoUntyped::into_lazy_untyped(i.clone()))? {71					out.push(i);72				}73			}74			return Ok(Self::new(out));75		};7677		let mut out = Vec::new();78		for i in self.iter_lazy() {79			if filter.call(i.clone())? {80				out.push(i);81			}82		}83		Ok(Self::new(out))84	}8586	pub fn extended(a: Self, b: Self) -> Self {87		if a.is_empty() {88			b89		} else if b.is_empty() {90			a91		} else {92			Self::new(ExtendedArray::new(a, b))93		}94	}9596	pub fn range_exclusive(a: i32, b: i32) -> Self {97		Self::new(RangeArray::new_exclusive(a, b))98	}99	pub fn range_inclusive(a: i32, b: i32) -> Self {100		Self::new(RangeArray::new_inclusive(a, b))101	}102103	#[must_use]104	pub fn slice(self, index: Option<i32>, end: Option<i32>, step: Option<NonZeroU32>) -> Self {105		let get_idx = |pos: Option<i32>, len: usize, default| match pos {106			#[expect(107				clippy::cast_sign_loss,108				reason = "abs value is used, len is limited to u31"109			)]110			Some(v) if v < 0 => len.saturating_sub((-v) as usize),111			#[expect(clippy::cast_sign_loss, reason = "abs value is used")]112			Some(v) => (v as usize).min(len),113			None => default,114		};115		let index = get_idx(index, self.len(), 0);116		let end = get_idx(end, self.len(), self.len());117		let step = step.unwrap_or_else(|| NonZeroU32::new(1).expect("1 != 0"));118119		if index >= end {120			return Self::empty();121		}122123		Self::new(SliceArray {124			inner: self,125			#[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")]126			from: index as u32,127			#[expect(clippy::cast_possible_truncation, reason = "len is limited to u31")]128			to: end as u32,129			step: step.get(),130		})131	}132133	/// Array length.134	pub fn len(&self) -> usize {135		self.0.len()136	}137138	/// Is array contains no elements?139	pub fn is_empty(&self) -> bool {140		self.0.is_empty()141	}142143	pub fn is_cheap(&self) -> bool {144		self.0.is_cheap()145	}146147	/// Get array element by index, evaluating it, if it is lazy.148	///149	/// Returns `None` on out-of-bounds condition.150	pub fn get(&self, index: usize) -> Result<Option<Val>> {151		self.0.get(index)152	}153154	/// Get array element by index, without evaluation.155	///156	/// Returns `None` on out-of-bounds condition.157	pub fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {158		self.0.get_lazy(index)159	}160161	pub fn iter(&self) -> impl ArrayLikeIter<Result<Val>> + '_ {162		(0..self.len()).map(|i| self.get(i).transpose().expect("length checked"))163	}164165	/// Iterate over elements, returning lazy values.166	pub fn iter_lazy(&self) -> impl ArrayLikeIter<Thunk<Val>> + '_ {167		(0..self.len()).map(|i| self.get_lazy(i).expect("length checked"))168	}169170	/// Return a reversed view on current array.171	#[must_use]172	pub fn reversed(self) -> Self {173		Self::new(ReverseArray(self))174	}175176	pub fn ptr_eq(a: &Self, b: &Self) -> bool {177		Cc::ptr_eq(&a.0, &b.0)178	}179180	pub fn as_any(&self) -> &dyn Any {181		&self.0182	}183}184impl<T> From<T> for ArrValue185where186	T: ArrayLike,187{188	fn from(value: T) -> Self {189		Self::new(value)190	}191}192impl<I> FromIterator<I> for ArrValue193where194	Vec<I>: ArrayLike,195{196	fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {197		Self::new(iter.into_iter().collect::<Vec<_>>())198	}199}
modifiedcrates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/arr/spec.rs
+++ b/crates/jrsonnet-evaluator/src/arr/spec.rs
@@ -97,17 +97,6 @@
 	}
 }
 
-#[derive(Trace, Debug)]
-pub struct CharArray(pub Vec<char>);
-impl ArrayCheap for CharArray {
-	fn len(&self) -> usize {
-		self.0.as_slice().len()
-	}
-	fn get(&self, index: usize) -> Option<Val> {
-		self.0.as_slice().get(index).map(|v| Val::string(*v))
-	}
-}
-
 impl ArrayCheap for IBytes {
 	fn len(&self) -> usize {
 		self.as_slice().len()
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/typed/conversions.rs
+++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs
@@ -463,6 +463,11 @@
 impl Typed for char {
 	const TYPE: &'static ComplexValType = &ComplexValType::Char;
 }
+impl IntoUntyped for &char {
+	fn into_untyped(value: Self) -> Result<Val> {
+		Ok(Val::string(*value))
+	}
+}
 impl IntoUntyped for char {
 	fn into_untyped(value: Self) -> Result<Val> {
 		Ok(Val::string(value))
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -266,7 +266,7 @@
 
 	pub fn to_array(self) -> ArrValue {
 		match self {
-			Self::Str(s) => ArrValue::chars(s.chars()),
+			Self::Str(s) => s.chars().collect(),
 			Self::Arr(arr) => arr,
 		}
 	}
modifiedcrates/jrsonnet-stdlib/src/strings.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/strings.rs
+++ b/crates/jrsonnet-stdlib/src/strings.rs
@@ -223,7 +223,7 @@
 
 #[builtin]
 pub fn builtin_string_chars(str: IStr) -> ArrValue {
-	ArrValue::chars(str.chars())
+	str.chars().collect()
 }
 
 #[builtin]