git.delta.rocks / jrsonnet / refs/commits / 23d571a0df03

difftreelog

refactor move arrays to use dyn ArrayLike

Yaroslav Bolyukin2023-08-06parent: #09dae32.patch.diff
in: master

8 files changed

modifiedcrates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/arr/mod.rs
+++ b/crates/jrsonnet-evaluator/src/arr/mod.rs
@@ -1,44 +1,20 @@
-use std::rc::Rc;
+use std::any::Any;
 
 use jrsonnet_gcmodule::{Cc, Trace};
 use jrsonnet_interner::IBytes;
 use jrsonnet_parser::LocExpr;
 
-use crate::{function::FuncVal, Context, Result, Thunk, Val};
+use crate::{function::FuncVal, gc::TraceBox, tb, Context, Result, Thunk, Val};
 
 mod spec;
-use spec::*;
+pub use spec::ArrayLike;
+pub(crate) use spec::*;
 
 /// Represents a Jsonnet array value.
 #[derive(Debug, Clone, Trace)]
 // may contrain other ArrValue
 #[trace(tracking(force))]
-pub enum ArrValue {
-	/// Layout optimized byte array.
-	Bytes(BytesArray),
-	/// Layout optimized char array.
-	Chars(CharArray),
-	/// Every element is lazy evaluated.
-	Lazy(LazyArray),
-	/// Every element is defined somewhere in source code
-	Expr(ExprArray),
-	/// Every field is already evaluated.
-	Eager(EagerArray),
-	/// Concatenation of two arrays of any kind.
-	Extended(Cc<ExtendedArray>),
-	/// Represents a integer array in form `[start, start + 1, ... end - 1, end]`.
-	/// This kind of arrays is generated by `std.range(start, end)` call, and used for loops.
-	Range(RangeArray),
-	/// Sliced array view.
-	Slice(Cc<SliceArray>),
-	/// Reversed array view.
-	/// Returned by `std.reverse(other)` call
-	Reverse(Cc<ReverseArray>),
-	/// Returned by `std.map` call
-	Mapped(MappedArray),
-	/// Returned by `std.repeat` call
-	Repeated(RepeatedArray),
-}
+pub struct ArrValue(Cc<TraceBox<dyn ArrayLike>>);
 
 pub trait ArrayLikeIter<T>: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator {}
 impl<I, T> ArrayLikeIter<T> for I where
@@ -47,36 +23,39 @@
 }
 
 impl ArrValue {
+	pub fn new(v: impl ArrayLike) -> Self {
+		Self(Cc::new(tb!(v)))
+	}
 	pub fn empty() -> Self {
-		Self::Range(RangeArray::empty())
+		Self::new(RangeArray::empty())
 	}
 
 	pub fn expr(ctx: Context, exprs: impl IntoIterator<Item = LocExpr>) -> Self {
-		Self::Expr(ExprArray::new(ctx, exprs))
+		Self::new(ExprArray::new(ctx, exprs))
 	}
 
-	pub fn lazy(thunks: Cc<Vec<Thunk<Val>>>) -> Self {
-		Self::Lazy(LazyArray(thunks))
+	pub fn lazy(thunks: Vec<Thunk<Val>>) -> Self {
+		Self::new(LazyArray(thunks))
 	}
 
 	pub fn eager(values: Vec<Val>) -> Self {
-		Self::Eager(EagerArray(Cc::new(values)))
+		Self::new(EagerArray(values))
 	}
 
 	pub fn repeated(data: ArrValue, repeats: usize) -> Option<Self> {
-		Some(Self::Repeated(RepeatedArray::new(data, repeats)?))
+		Some(Self::new(RepeatedArray::new(data, repeats)?))
 	}
 
 	pub fn bytes(bytes: IBytes) -> Self {
-		Self::Bytes(BytesArray(bytes))
+		Self::new(BytesArray(bytes))
 	}
 	pub fn chars(chars: impl Iterator<Item = char>) -> Self {
-		Self::Chars(CharArray(Rc::new(chars.collect())))
+		Self::new(CharArray(chars.collect()))
 	}
 
 	#[must_use]
 	pub fn map(self, mapper: FuncVal) -> Self {
-		Self::Mapped(MappedArray::new(self, mapper))
+		Self::new(MappedArray::new(self, mapper))
 	}
 
 	pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {
@@ -100,7 +79,7 @@
 		} else if b.is_empty() {
 			a
 		} else if a.len() + b.len() > ARR_EXTEND_THRESHOLD {
-			Self::Extended(Cc::new(ExtendedArray::new(a, b)))
+			Self::new(ExtendedArray::new(a, b))
 		} else if let (Some(a), Some(b)) = (a.iter_cheap(), b.iter_cheap()) {
 			let mut out = Vec::with_capacity(a.len() + b.len());
 			out.extend(a);
@@ -110,15 +89,15 @@
 			let mut out = Vec::with_capacity(a.len() + b.len());
 			out.extend(a.iter_lazy());
 			out.extend(b.iter_lazy());
-			Self::lazy(Cc::new(out))
+			Self::lazy(out)
 		}
 	}
 
 	pub fn range_exclusive(a: i32, b: i32) -> Self {
-		Self::Range(RangeArray::new_exclusive(a, b))
+		Self::new(RangeArray::new_exclusive(a, b))
 	}
 	pub fn range_inclusive(a: i32, b: i32) -> Self {
-		Self::Range(RangeArray::new_inclusive(a, b))
+		Self::new(RangeArray::new_inclusive(a, b))
 	}
 
 	#[must_use]
@@ -136,53 +115,42 @@
 		if from >= to || step == 0 {
 			return None;
 		}
-		// match self {
-		// 	ArrValue::Slice(slice) => {
-		// 		return Some(Self::Slice(Cc::new(SliceArray {
-		// 			inner: slice.inner.clone(),
-		// 			from: slice.from + slice.step * (from as u32),
-		// 			to: slice.from + (to as u32) * slice.step,
-		// 			step: slice.step * step as u32,
-		// 		})))
-		// 	}
-		// 	_ => {}
-		// }
 
-		Some(Self::Slice(Cc::new(SliceArray {
+		Some(Self::new(SliceArray {
 			inner: self,
 			from: from as u32,
 			to: to as u32,
 			step: step as u32,
-		})))
+		}))
 	}
 
 	/// Array length.
 	pub fn len(&self) -> usize {
-		pass!(self.len())
+		self.0.len()
 	}
 
 	/// Is array contains no elements?
 	pub fn is_empty(&self) -> bool {
-		pass!(self.is_empty())
+		self.0.is_empty()
 	}
 
 	/// Get array element by index, evaluating it, if it is lazy.
 	///
 	/// Returns `None` on out-of-bounds condition.
 	pub fn get(&self, index: usize) -> Result<Option<Val>> {
-		pass!(self.get(index))
+		self.0.get(index)
 	}
 
 	/// Returns None if get is either non cheap, or out of bounds
 	fn get_cheap(&self, index: usize) -> Option<Val> {
-		pass!(self.get_cheap(index))
+		self.0.get_cheap(index)
 	}
 
 	/// Get array element by index, without evaluation.
 	///
 	/// Returns `None` on out-of-bounds condition.
 	pub fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
-		pass!(self.get_lazy(index))
+		self.0.get_lazy(index)
 	}
 
 	pub fn iter(&self) -> impl ArrayLikeIter<Result<Val>> + '_ {
@@ -205,33 +173,20 @@
 	/// Return a reversed view on current array.
 	#[must_use]
 	pub fn reversed(self) -> Self {
-		Self::Reverse(Cc::new(ReverseArray(self)))
+		Self::new(ReverseArray(self))
 	}
 
 	pub fn ptr_eq(a: &Self, b: &Self) -> bool {
-		match (a, b) {
-			(ArrValue::Bytes(a), ArrValue::Bytes(b)) => a.0 == b.0,
-			(ArrValue::Lazy(a), ArrValue::Lazy(b)) => Cc::ptr_eq(&a.0, &b.0),
-			(ArrValue::Expr(a), ArrValue::Expr(b)) => Cc::ptr_eq(&a.0, &b.0),
-			(ArrValue::Eager(a), ArrValue::Eager(b)) => Cc::ptr_eq(&a.0, &b.0),
-			(ArrValue::Extended(a), ArrValue::Extended(b)) => Cc::ptr_eq(a, b),
-			(ArrValue::Range(a), ArrValue::Range(b)) => a == b,
-			_ => false,
-		}
+		Cc::ptr_eq(&a.0, &b.0)
 	}
 
 	/// Is this vec supports `.get_cheap()?`
 	pub fn is_cheap(&self) -> bool {
-		match self {
-			ArrValue::Eager(_) | ArrValue::Range(..) | ArrValue::Bytes(_) | ArrValue::Chars(_) => {
-				true
-			}
-			ArrValue::Extended(v) => v.a.is_cheap() && v.b.is_cheap(),
-			ArrValue::Slice(r) => r.inner.is_cheap(),
-			ArrValue::Reverse(i) => i.0.is_cheap(),
-			ArrValue::Repeated(v) => v.is_cheap(),
-			ArrValue::Expr(_) | ArrValue::Lazy(_) | ArrValue::Mapped(_) => false,
-		}
+		self.0.is_cheap()
+	}
+
+	pub fn as_any(&self) -> &dyn Any {
+		&self.0
 	}
 }
 impl From<Vec<Val>> for ArrValue {
@@ -241,7 +196,7 @@
 }
 impl From<Vec<Thunk<Val>>> for ArrValue {
 	fn from(value: Vec<Thunk<Val>>) -> Self {
-		Self::lazy(Cc::new(value))
+		Self::lazy(value)
 	}
 }
 impl FromIterator<Val> for ArrValue {
@@ -249,6 +204,27 @@
 		Self::eager(iter.into_iter().collect())
 	}
 }
+impl ArrayLike for ArrValue {
+	fn len(&self) -> usize {
+		self.0.len()
+	}
 
+	fn get(&self, index: usize) -> Result<Option<Val>> {
+		self.0.get(index)
+	}
+
+	fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
+		self.0.get_lazy(index)
+	}
+
+	fn get_cheap(&self, index: usize) -> Option<Val> {
+		self.0.get_cheap(index)
+	}
+
+	fn is_cheap(&self) -> bool {
+		self.0.is_cheap()
+	}
+}
+
 #[cfg(target_pointer_width = "64")]
-static_assertions::assert_eq_size!(ArrValue, [u8; 16]);
+static_assertions::assert_eq_size!(ArrValue, [u8; 8]);
modifiedcrates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth
1use std::{cell::RefCell, iter, mem::replace, rc::Rc};1use std::{any::Any, cell::RefCell, fmt::Debug, iter, mem::replace};
22
3use jrsonnet_gcmodule::{Cc, Trace};3use jrsonnet_gcmodule::{Cc, Trace};
4use jrsonnet_interner::{IBytes, IStr};4use jrsonnet_interner::{IBytes, IStr};
13 Context, Error, Result, Thunk, Val,13 Context, Error, Result, Thunk, Val,
14};14};
1515
16pub trait ArrayLike: Sized + Into<ArrValue> {16pub trait ArrayLike: Any + Trace + Debug {
17 fn len(&self) -> usize;17 fn len(&self) -> usize;
18 fn is_empty(&self) -> bool {18 fn is_empty(&self) -> bool {
19 self.len() == 019 self.len() == 0
22 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>>;22 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>>;
23 fn get_cheap(&self, index: usize) -> Option<Val>;23 fn get_cheap(&self, index: usize) -> Option<Val>;
2424
25 fn reverse(self) -> ArrValue {25 fn is_cheap(&self) -> bool;
26 ArrValue::Reverse(Cc::new(ReverseArray(self.into())))
27 }
28}26}
2927
30#[derive(Debug, Clone, Trace)]28#[derive(Debug, Trace)]
31pub struct SliceArray {29pub struct SliceArray {
32 pub(crate) inner: ArrValue,30 pub(crate) inner: ArrValue,
33 pub(crate) from: u32,31 pub(crate) from: u32,
62 )60 )
63 }61 }
64}62}
65impl ArrayLike for SliceArray {63impl ArrayLike for SliceArray {
66 fn len(&self) -> usize {64 fn len(&self) -> usize {
67 iter::repeat(())65 iter::repeat(())
68 .take((self.to - self.from) as usize)66 .take((self.to - self.from) as usize)
81 fn get_cheap(&self, index: usize) -> Option<Val> {79 fn get_cheap(&self, index: usize) -> Option<Val> {
82 self.iter_cheap()?.nth(index)80 self.iter_cheap()?.nth(index)
83 }81 }
84}
85impl From<SliceArray> for ArrValue {
86 fn from(value: SliceArray) -> Self {82 fn is_cheap(&self) -> bool {
87 Self::Slice(Cc::new(value))83 self.inner.is_cheap()
88 }84 }
89}85}
9086
91#[derive(Trace, Debug, Clone)]87#[derive(Trace, Debug)]
92pub struct CharArray(pub Rc<Vec<char>>);88pub struct CharArray(pub Vec<char>);
93impl ArrayLike for CharArray {89impl ArrayLike for CharArray {
94 fn len(&self) -> usize {90 fn len(&self) -> usize {
95 self.0.len()91 self.0.len()
96 }92 }
108 .get(index)104 .get(index)
109 .map(|v| Val::Str(StrValue::Flat(IStr::from(*v))))105 .map(|v| Val::Str(StrValue::Flat(IStr::from(*v))))
110 }106 }
111}
112impl From<CharArray> for ArrValue {
113 fn from(value: CharArray) -> Self {107 fn is_cheap(&self) -> bool {
114 ArrValue::Chars(value)108 true
115 }109 }
116}110}
117111
118#[derive(Trace, Debug, Clone)]112#[derive(Trace, Debug)]
119pub struct BytesArray(pub IBytes);113pub struct BytesArray(pub IBytes);
120impl ArrayLike for BytesArray {114impl ArrayLike for BytesArray {
121 fn len(&self) -> usize {115 fn len(&self) -> usize {
122 self.0.len()116 self.0.len()
123 }117 }
133 fn get_cheap(&self, index: usize) -> Option<Val> {127 fn get_cheap(&self, index: usize) -> Option<Val> {
134 self.0.get(index).map(|v| Val::Num(f64::from(*v)))128 self.0.get(index).map(|v| Val::Num(f64::from(*v)))
135 }129 }
136}
137impl From<BytesArray> for ArrValue {
138 fn from(value: BytesArray) -> Self {130 fn is_cheap(&self) -> bool {
139 ArrValue::Bytes(value)131 true
140 }132 }
141}133}
142134
143#[derive(Debug, Trace, Clone)]135#[derive(Debug, Trace, Clone)]
144enum ArrayThunk<T: 'static + Trace> {136enum ArrayThunk<T: 'static + Trace> {
148 Pending,140 Pending,
149}141}
150142
151#[derive(Debug, Trace)]143#[derive(Debug, Trace, Clone)]
152pub struct ExprArrayInner {144pub struct ExprArray {
153 ctx: Context,145 ctx: Context,
154 cached: RefCell<Vec<ArrayThunk<LocExpr>>>,146 cached: Cc<RefCell<Vec<ArrayThunk<LocExpr>>>>,
155}147}
156#[derive(Debug, Trace, Clone)]
157pub struct ExprArray(pub Cc<ExprArrayInner>);
158impl ExprArray {148impl ExprArray {
159 pub fn new(ctx: Context, items: impl IntoIterator<Item = LocExpr>) -> Self {149 pub fn new(ctx: Context, items: impl IntoIterator<Item = LocExpr>) -> Self {
160 Self(Cc::new(ExprArrayInner {150 Self {
161 ctx,151 ctx,
162 cached: RefCell::new(items.into_iter().map(ArrayThunk::Waiting).collect()),152 cached: Cc::new(RefCell::new(
153 items.into_iter().map(ArrayThunk::Waiting).collect(),
163 }))154 )),
155 }
164 }156 }
165}157}
166impl ArrayLike for ExprArray {158impl ArrayLike for ExprArray {
167 fn len(&self) -> usize {159 fn len(&self) -> usize {
168 self.0.cached.borrow().len()160 self.cached.borrow().len()
169 }161 }
170 fn get(&self, index: usize) -> Result<Option<Val>> {162 fn get(&self, index: usize) -> Result<Option<Val>> {
171 if index >= self.len() {163 if index >= self.len() {
172 return Ok(None);164 return Ok(None);
173 }165 }
174 match &self.0.cached.borrow()[index] {166 match &self.cached.borrow()[index] {
175 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),167 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),
176 ArrayThunk::Errored(e) => return Err(e.clone()),168 ArrayThunk::Errored(e) => return Err(e.clone()),
177 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),169 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),
178 ArrayThunk::Waiting(..) => {}170 ArrayThunk::Waiting(..) => {}
179 };171 };
180172
181 let ArrayThunk::Waiting(expr) =173 let ArrayThunk::Waiting(expr) =
182 replace(&mut self.0.cached.borrow_mut()[index], ArrayThunk::Pending)174 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)
183 else {175 else {
184 unreachable!()176 unreachable!()
185 };177 };
186178
187 let new_value = match evaluate(self.0.ctx.clone(), &expr) {179 let new_value = match evaluate(self.ctx.clone(), &expr) {
188 Ok(v) => v,180 Ok(v) => v,
189 Err(e) => {181 Err(e) => {
190 self.0.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());182 self.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());
191 return Err(e);183 return Err(e);
192 }184 }
193 };185 };
194 self.0.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());186 self.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());
195 Ok(Some(new_value))187 Ok(Some(new_value))
196 }188 }
197 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {189 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
215 if index >= self.len() {207 if index >= self.len() {
216 return None;208 return None;
217 }209 }
218 match &self.0.cached.borrow()[index] {210 match &self.cached.borrow()[index] {
219 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),211 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),
220 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),212 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),
221 ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}213 ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}
229 fn get_cheap(&self, _index: usize) -> Option<Val> {221 fn get_cheap(&self, _index: usize) -> Option<Val> {
230 None222 None
231 }223 }
224 fn is_cheap(&self) -> bool {
225 false
226 }
232}227}
233impl From<ExprArray> for ArrValue {
234 fn from(value: ExprArray) -> Self {
235 Self::Expr(value)
236 }
237}
238228
239#[derive(Trace, Debug, Clone)]229#[derive(Trace, Debug)]
240pub struct ExtendedArray {230pub struct ExtendedArray {
241 pub a: ArrValue,231 pub a: ArrValue,
242 pub b: ArrValue,232 pub b: ArrValue,
292 self.1282 self.1
293 }283 }
294}284}
295impl ArrayLike for ExtendedArray {285impl ArrayLike for ExtendedArray {
296 fn get(&self, index: usize) -> Result<Option<Val>> {286 fn get(&self, index: usize) -> Result<Option<Val>> {
297 if self.split > index {287 if self.split > index {
298 self.a.get(index)288 self.a.get(index)
319 self.b.get_cheap(index - self.split)309 self.b.get_cheap(index - self.split)
320 }310 }
321 }311 }
322}
323impl From<ExtendedArray> for ArrValue {
324 fn from(value: ExtendedArray) -> Self {312 fn is_cheap(&self) -> bool {
325 Self::Extended(Cc::new(value))313 self.a.is_cheap() && self.b.is_cheap()
326 }314 }
327}315}
328316
329#[derive(Trace, Debug, Clone)]317#[derive(Trace, Debug)]
330pub struct LazyArray(pub Cc<Vec<Thunk<Val>>>);318pub struct LazyArray(pub Vec<Thunk<Val>>);
331impl ArrayLike for LazyArray {319impl ArrayLike for LazyArray {
332 fn len(&self) -> usize {320 fn len(&self) -> usize {
333 self.0.len()321 self.0.len()
334 }322 }
344 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {332 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
345 self.0.get(index).cloned()333 self.0.get(index).cloned()
346 }334 }
347}
348impl From<LazyArray> for ArrValue {
349 fn from(value: LazyArray) -> Self {335 fn is_cheap(&self) -> bool {
350 Self::Lazy(value)336 false
351 }337 }
352}338}
353339
354#[derive(Trace, Debug, Clone)]340#[derive(Trace, Debug)]
355pub struct EagerArray(pub Cc<Vec<Val>>);341pub struct EagerArray(pub Vec<Val>);
356impl ArrayLike for EagerArray {342impl ArrayLike for EagerArray {
357 fn len(&self) -> usize {343 fn len(&self) -> usize {
358 self.0.len()344 self.0.len()
359 }345 }
369 fn get_cheap(&self, index: usize) -> Option<Val> {355 fn get_cheap(&self, index: usize) -> Option<Val> {
370 self.0.get(index).cloned()356 self.0.get(index).cloned()
371 }357 }
372}
373impl From<EagerArray> for ArrValue {
374 fn from(value: EagerArray) -> Self {358 fn is_cheap(&self) -> bool {
375 Self::Eager(value)359 true
376 }360 }
377}361}
378362
379/// Inclusive range type363/// Inclusive range type
380#[derive(Debug, Trace, Clone, PartialEq, Eq)]364#[derive(Debug, Trace, PartialEq, Eq)]
381pub struct RangeArray {365pub struct RangeArray {
382 start: i32,366 start: i32,
383 end: i32,367 end: i32,
403 }387 }
404}388}
405389
406impl ArrayLike for RangeArray {390impl ArrayLike for RangeArray {
407 fn len(&self) -> usize {391 fn len(&self) -> usize {
408 self.range().len()392 self.range().len()
409 }393 }
422 fn get_cheap(&self, index: usize) -> Option<Val> {406 fn get_cheap(&self, index: usize) -> Option<Val> {
423 self.range().nth(index).map(|i| Val::Num(f64::from(i)))407 self.range().nth(index).map(|i| Val::Num(f64::from(i)))
424 }408 }
425}
426impl From<RangeArray> for ArrValue {
427 fn from(value: RangeArray) -> Self {409 fn is_cheap(&self) -> bool {
428 Self::Range(value)410 true
429 }411 }
430}412}
431413
432#[derive(Debug, Trace, Clone)]414#[derive(Debug, Trace)]
433pub struct ReverseArray(pub ArrValue);415pub struct ReverseArray(pub ArrValue);
434impl ArrayLike for ReverseArray {416impl ArrayLike for ReverseArray {
435 fn len(&self) -> usize {417 fn len(&self) -> usize {
447 fn get_cheap(&self, index: usize) -> Option<Val> {429 fn get_cheap(&self, index: usize) -> Option<Val> {
448 self.0.get_cheap(self.0.len() - index - 1)430 self.0.get_cheap(self.0.len() - index - 1)
449 }431 }
450 fn reverse(self) -> ArrValue {432 fn is_cheap(&self) -> bool {
451 self.0433 self.0.is_cheap()
452 }434 }
453}435}
454impl From<ReverseArray> for ArrValue {
455 fn from(value: ReverseArray) -> Self {
456 Self::Reverse(Cc::new(value))
457 }
458}
459436
460#[derive(Trace, Debug)]437#[derive(Trace, Debug, Clone)]
461pub struct MappedArrayInner {438pub struct MappedArray {
462 inner: ArrValue,439 inner: ArrValue,
463 cached: RefCell<Vec<ArrayThunk<()>>>,440 cached: Cc<RefCell<Vec<ArrayThunk<()>>>>,
464 mapper: FuncVal,441 mapper: FuncVal,
465}442}
466#[derive(Trace, Debug, Clone)]
467pub struct MappedArray(Cc<MappedArrayInner>);
468impl MappedArray {443impl MappedArray {
469 pub fn new(inner: ArrValue, mapper: FuncVal) -> Self {444 pub fn new(inner: ArrValue, mapper: FuncVal) -> Self {
470 let len = inner.len();445 let len = inner.len();
471 Self(Cc::new(MappedArrayInner {446 Self {
472 inner,447 inner,
473 cached: RefCell::new(vec![ArrayThunk::Waiting(()); len]),448 cached: Cc::new(RefCell::new(vec![ArrayThunk::Waiting(()); len])),
474 mapper,449 mapper,
475 }))450 }
476 }451 }
477}452}
478impl ArrayLike for MappedArray {453impl ArrayLike for MappedArray {
479 fn len(&self) -> usize {454 fn len(&self) -> usize {
480 self.0.cached.borrow().len()455 self.cached.borrow().len()
481 }456 }
482457
483 fn get(&self, index: usize) -> Result<Option<Val>> {458 fn get(&self, index: usize) -> Result<Option<Val>> {
484 if index >= self.len() {459 if index >= self.len() {
485 return Ok(None);460 return Ok(None);
486 }461 }
487 match &self.0.cached.borrow()[index] {462 match &self.cached.borrow()[index] {
488 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),463 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),
489 ArrayThunk::Errored(e) => return Err(e.clone()),464 ArrayThunk::Errored(e) => return Err(e.clone()),
490 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),465 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),
491 ArrayThunk::Waiting(..) => {}466 ArrayThunk::Waiting(..) => {}
492 };467 };
493468
494 let ArrayThunk::Waiting(_) =469 let ArrayThunk::Waiting(_) =
495 replace(&mut self.0.cached.borrow_mut()[index], ArrayThunk::Pending)470 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)
496 else {471 else {
497 unreachable!()472 unreachable!()
498 };473 };
499474
500 let val = self475 let val = self
501 .0
502 .inner476 .inner
503 .get(index)477 .get(index)
504 .transpose()478 .transpose()
505 .expect("index checked")479 .expect("index checked")
506 .and_then(|r| self.0.mapper.evaluate_simple(&(r,), false));480 .and_then(|r| self.mapper.evaluate_simple(&(r,), false));
507481
508 let new_value = match val {482 let new_value = match val {
509 Ok(v) => v,483 Ok(v) => v,
510 Err(e) => {484 Err(e) => {
511 self.0.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());485 self.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());
512 return Err(e);486 return Err(e);
513 }487 }
514 };488 };
515 self.0.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());489 self.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());
516 Ok(Some(new_value))490 Ok(Some(new_value))
517 }491 }
518 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {492 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
536 if index >= self.len() {510 if index >= self.len() {
537 return None;511 return None;
538 }512 }
539 match &self.0.cached.borrow()[index] {513 match &self.cached.borrow()[index] {
540 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),514 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),
541 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),515 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),
542 ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}516 ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}
551 fn get_cheap(&self, _index: usize) -> Option<Val> {525 fn get_cheap(&self, _index: usize) -> Option<Val> {
552 None526 None
553 }527 }
528 fn is_cheap(&self) -> bool {
529 false
530 }
554}531}
555impl From<MappedArray> for ArrValue {
556 fn from(value: MappedArray) -> Self {
557 Self::Mapped(value)
558 }
559}
560532
561#[derive(Trace, Debug)]533#[derive(Trace, Debug)]
562pub struct RepeatedArrayInner {534pub struct RepeatedArray {
563 data: ArrValue,535 data: ArrValue,
564 repeats: usize,536 repeats: usize,
565 total_len: usize,537 total_len: usize,
566}538}
567#[derive(Trace, Debug, Clone)]
568pub struct RepeatedArray(Cc<RepeatedArrayInner>);
569impl RepeatedArray {539impl RepeatedArray {
570 pub fn new(data: ArrValue, repeats: usize) -> Option<Self> {540 pub fn new(data: ArrValue, repeats: usize) -> Option<Self> {
571 let total_len = data.len().checked_mul(repeats)?;541 let total_len = data.len().checked_mul(repeats)?;
572 Some(Self(Cc::new(RepeatedArrayInner {542 Some(Self {
573 data,543 data,
574 repeats,544 repeats,
575 total_len,545 total_len,
576 })))546 })
577 }547 }
578 pub fn is_cheap(&self) -> bool {
579 self.0.data.is_cheap()
580 }
581}548}
582549
583impl ArrayLike for RepeatedArray {550impl ArrayLike for RepeatedArray {
584 fn len(&self) -> usize {551 fn len(&self) -> usize {
585 self.0.total_len552 self.total_len
586 }553 }
587554
588 fn get(&self, index: usize) -> Result<Option<Val>> {555 fn get(&self, index: usize) -> Result<Option<Val>> {
589 if index > self.0.total_len {556 if index > self.total_len {
590 return Ok(None);557 return Ok(None);
591 }558 }
592 self.0.data.get(index % self.0.data.len())559 self.data.get(index % self.data.len())
593 }560 }
594561
595 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {562 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
596 if index > self.0.total_len {563 if index > self.total_len {
597 return None;564 return None;
598 }565 }
599 self.0.data.get_lazy(index % self.0.data.len())566 self.data.get_lazy(index % self.data.len())
600 }567 }
601568
602 fn get_cheap(&self, index: usize) -> Option<Val> {569 fn get_cheap(&self, index: usize) -> Option<Val> {
603 if index > self.0.total_len {570 if index > self.total_len {
604 return None;571 return None;
605 }572 }
606 self.0.data.get_cheap(index % self.0.data.len())573 self.data.get_cheap(index % self.data.len())
607 }574 }
575 fn is_cheap(&self) -> bool {
576 self.data.is_cheap()
577 }
608}578}
609impl From<RepeatedArray> for ArrValue {
610 fn from(value: RepeatedArray) -> Self {
611 Self::Repeated(value)
612 }
613}
614
615macro_rules! pass {
616 ($t:ident.$m:ident($($ident:ident),*)) => {
617 match $t {
618 Self::Bytes(e) => e.$m($($ident)*),
619 Self::Chars(e) => e.$m($($ident)*),
620 Self::Expr(e) => e.$m($($ident)*),
621 Self::Lazy(e) => e.$m($($ident)*),
622 Self::Eager(e) => e.$m($($ident)*),
623 Self::Range(e) => e.$m($($ident)*),
624 Self::Slice(e) => e.$m($($ident)*),
625 Self::Extended(e) => e.$m($($ident)*),
626 Self::Reverse(e) => e.$m($($ident)*),
627 Self::Mapped(e) => e.$m($($ident)*),
628 Self::Repeated(e) => e.$m($($ident)*),
629 }
630 };
631}
632pub(super) use pass;
633579
modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -573,10 +573,10 @@
 						evaluate(self.ctx, &self.item)
 					}
 				}
-				Val::Arr(ArrValue::lazy(Cc::new(vec![Thunk::new(ArrayElement {
+				Val::Arr(ArrValue::lazy(vec![Thunk::new(ArrayElement {
 					ctx,
 					item: items[0].clone(),
-				})])))
+				})]))
 			} else {
 				Val::Arr(ArrValue::expr(ctx, items.iter().cloned()))
 			}
modifiedcrates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/obj.rs
+++ b/crates/jrsonnet-evaluator/src/obj.rs
@@ -17,7 +17,7 @@
 	operator::evaluate_add_op,
 	tb, throw,
 	val::ThunkValue,
-	MaybeUnbound, Result, ResultExt, State, Thunk, Unbound, Val,
+	MaybeUnbound, Result, State, Thunk, Unbound, Val,
 };
 
 #[cfg(not(feature = "exp-preserve-order"))]
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/typed/conversions.rs
+++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs
@@ -6,7 +6,7 @@
 use jrsonnet_types::{ComplexValType, ValType};
 
 use crate::{
-	arr::ArrValue,
+	arr::{ArrValue, BytesArray},
 	error::Result,
 	function::{native::NativeDesc, FuncDesc, FuncVal},
 	throw,
@@ -434,12 +434,13 @@
 	}
 
 	fn from_untyped(value: Val) -> Result<Self> {
-		if let Val::Arr(ArrValue::Bytes(bytes)) = value {
-			return Ok(bytes.0);
-		}
-		<Self as Typed>::TYPE.check(&value)?;
-		match value {
+		match &value {
 			Val::Arr(a) => {
+				if let Some(bytes) = a.as_any().downcast_ref::<BytesArray>() {
+					return Ok(bytes.0.as_slice().into());
+				};
+				<Self as Typed>::TYPE.check(&value)?;
+				// Any::downcast_ref::<ByteArray>(&a);
 				let mut out = Vec::with_capacity(a.len());
 				for e in a.iter() {
 					let r = e?;
@@ -447,7 +448,10 @@
 				}
 				Ok(out.as_slice().into())
 			}
-			_ => unreachable!(),
+			_ => {
+				<Self as Typed>::TYPE.check(&value)?;
+				unreachable!()
+			}
 		}
 	}
 }
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -9,7 +9,7 @@
 use jrsonnet_interner::IStr;
 use jrsonnet_types::ValType;
 
-pub use crate::arr::ArrValue;
+pub use crate::arr::{ArrValue, ArrayLike};
 use crate::{
 	error::{Error, ErrorKind::*},
 	function::FuncVal,
modifiedcrates/jrsonnet-stdlib/src/sets.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/sets.rs
+++ b/crates/jrsonnet-stdlib/src/sets.rs
@@ -7,7 +7,6 @@
 	val::ArrValue,
 	Thunk, Val,
 };
-use jrsonnet_gcmodule::Cc;
 use jrsonnet_parser::BinaryOpType;
 
 #[builtin]
@@ -70,5 +69,5 @@
 			}
 		};
 	}
-	Ok(ArrValue::lazy(Cc::new(out)))
+	Ok(ArrValue::lazy(out))
 }
modifiedcrates/jrsonnet-stdlib/src/sort.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/sort.rs
+++ b/crates/jrsonnet-stdlib/src/sort.rs
@@ -10,7 +10,6 @@
 	val::{equals, ArrValue},
 	Thunk, Val,
 };
-use jrsonnet_gcmodule::Cc;
 use jrsonnet_parser::BinaryOpType;
 
 use crate::eval_on_empty;
@@ -136,7 +135,7 @@
 			values.iter().collect::<Result<Vec<Val>>>()?,
 		)?))
 	} else {
-		Ok(ArrValue::lazy(Cc::new(sort_keyf(values, key_getter)?)))
+		Ok(ArrValue::lazy(sort_keyf(values, key_getter)?))
 	}
 }
 
@@ -186,7 +185,7 @@
 			arr.iter().collect::<Result<Vec<Val>>>()?,
 		)?))
 	} else {
-		Ok(ArrValue::lazy(Cc::new(uniq_keyf(arr, keyF)?)))
+		Ok(ArrValue::lazy(uniq_keyf(arr, keyF)?))
 	}
 }
 
@@ -204,8 +203,8 @@
 		Ok(ArrValue::eager(arr))
 	} else {
 		let arr = sort_keyf(arr, keyF.clone())?;
-		let arr = uniq_keyf(ArrValue::lazy(Cc::new(arr)), keyF)?;
-		Ok(ArrValue::lazy(Cc::new(arr)))
+		let arr = uniq_keyf(ArrValue::lazy(arr), keyF)?;
+		Ok(ArrValue::lazy(arr))
 	}
 }