difftreelog
refactor move arrays to use dyn ArrayLike
in: master
8 files changed
crates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth1use std::rc::Rc;23use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_interner::IBytes;5use jrsonnet_parser::LocExpr;67use crate::{function::FuncVal, Context, Result, Thunk, Val};89mod spec;10use spec::*;1112/// Represents a Jsonnet array value.13#[derive(Debug, Clone, Trace)]14// may contrain other ArrValue15#[trace(tracking(force))]16pub enum ArrValue {17 /// Layout optimized byte array.18 Bytes(BytesArray),19 /// Layout optimized char array.20 Chars(CharArray),21 /// Every element is lazy evaluated.22 Lazy(LazyArray),23 /// Every element is defined somewhere in source code24 Expr(ExprArray),25 /// Every field is already evaluated.26 Eager(EagerArray),27 /// Concatenation of two arrays of any kind.28 Extended(Cc<ExtendedArray>),29 /// Represents a integer array in form `[start, start + 1, ... end - 1, end]`.30 /// This kind of arrays is generated by `std.range(start, end)` call, and used for loops.31 Range(RangeArray),32 /// Sliced array view.33 Slice(Cc<SliceArray>),34 /// Reversed array view.35 /// Returned by `std.reverse(other)` call36 Reverse(Cc<ReverseArray>),37 /// Returned by `std.map` call38 Mapped(MappedArray),39 /// Returned by `std.repeat` call40 Repeated(RepeatedArray),41}4243pub trait ArrayLikeIter<T>: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator {}44impl<I, T> ArrayLikeIter<T> for I where45 I: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator46{47}4849impl ArrValue {50 pub fn empty() -> Self {51 Self::Range(RangeArray::empty())52 }5354 pub fn expr(ctx: Context, exprs: impl IntoIterator<Item = LocExpr>) -> Self {55 Self::Expr(ExprArray::new(ctx, exprs))56 }5758 pub fn lazy(thunks: Cc<Vec<Thunk<Val>>>) -> Self {59 Self::Lazy(LazyArray(thunks))60 }6162 pub fn eager(values: Vec<Val>) -> Self {63 Self::Eager(EagerArray(Cc::new(values)))64 }6566 pub fn repeated(data: ArrValue, repeats: usize) -> Option<Self> {67 Some(Self::Repeated(RepeatedArray::new(data, repeats)?))68 }6970 pub fn bytes(bytes: IBytes) -> Self {71 Self::Bytes(BytesArray(bytes))72 }73 pub fn chars(chars: impl Iterator<Item = char>) -> Self {74 Self::Chars(CharArray(Rc::new(chars.collect())))75 }7677 #[must_use]78 pub fn map(self, mapper: FuncVal) -> Self {79 Self::Mapped(MappedArray::new(self, mapper))80 }8182 pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {83 // TODO: ArrValue::Picked(inner, indexes) for large arrays84 let mut out = Vec::new();85 for i in self.iter() {86 let i = i?;87 if filter(&i)? {88 out.push(i);89 };90 }91 Ok(Self::eager(out))92 }9394 pub fn extended(a: ArrValue, b: ArrValue) -> Self {95 // TODO: benchmark for an optimal value, currently just a arbitrary choice96 const ARR_EXTEND_THRESHOLD: usize = 100;9798 if a.is_empty() {99 b100 } else if b.is_empty() {101 a102 } else if a.len() + b.len() > ARR_EXTEND_THRESHOLD {103 Self::Extended(Cc::new(ExtendedArray::new(a, b)))104 } else if let (Some(a), Some(b)) = (a.iter_cheap(), b.iter_cheap()) {105 let mut out = Vec::with_capacity(a.len() + b.len());106 out.extend(a);107 out.extend(b);108 Self::eager(out)109 } else {110 let mut out = Vec::with_capacity(a.len() + b.len());111 out.extend(a.iter_lazy());112 out.extend(b.iter_lazy());113 Self::lazy(Cc::new(out))114 }115 }116117 pub fn range_exclusive(a: i32, b: i32) -> Self {118 Self::Range(RangeArray::new_exclusive(a, b))119 }120 pub fn range_inclusive(a: i32, b: i32) -> Self {121 Self::Range(RangeArray::new_inclusive(a, b))122 }123124 #[must_use]125 pub fn slice(126 self,127 from: Option<usize>,128 to: Option<usize>,129 step: Option<usize>,130 ) -> Option<Self> {131 let len = self.len();132 let from = from.unwrap_or(0);133 let to = to.unwrap_or(len).min(len);134 let step = step.unwrap_or(1);135136 if from >= to || step == 0 {137 return None;138 }139 // match self {140 // ArrValue::Slice(slice) => {141 // return Some(Self::Slice(Cc::new(SliceArray {142 // inner: slice.inner.clone(),143 // from: slice.from + slice.step * (from as u32),144 // to: slice.from + (to as u32) * slice.step,145 // step: slice.step * step as u32,146 // })))147 // }148 // _ => {}149 // }150151 Some(Self::Slice(Cc::new(SliceArray {152 inner: self,153 from: from as u32,154 to: to as u32,155 step: step as u32,156 })))157 }158159 /// Array length.160 pub fn len(&self) -> usize {161 pass!(self.len())162 }163164 /// Is array contains no elements?165 pub fn is_empty(&self) -> bool {166 pass!(self.is_empty())167 }168169 /// Get array element by index, evaluating it, if it is lazy.170 ///171 /// Returns `None` on out-of-bounds condition.172 pub fn get(&self, index: usize) -> Result<Option<Val>> {173 pass!(self.get(index))174 }175176 /// Returns None if get is either non cheap, or out of bounds177 fn get_cheap(&self, index: usize) -> Option<Val> {178 pass!(self.get_cheap(index))179 }180181 /// Get array element by index, without evaluation.182 ///183 /// Returns `None` on out-of-bounds condition.184 pub fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {185 pass!(self.get_lazy(index))186 }187188 pub fn iter(&self) -> impl ArrayLikeIter<Result<Val>> + '_ {189 (0..self.len()).map(|i| self.get(i).transpose().expect("length checked"))190 }191192 /// Iterate over elements, returning lazy values.193 pub fn iter_lazy(&self) -> impl ArrayLikeIter<Thunk<Val>> + '_ {194 (0..self.len()).map(|i| self.get_lazy(i).expect("length checked"))195 }196197 pub fn iter_cheap(&self) -> Option<impl ArrayLikeIter<Val> + '_> {198 if self.is_cheap() {199 Some((0..self.len()).map(|i| self.get_cheap(i).expect("length and is_cheap checked")))200 } else {201 None202 }203 }204205 /// Return a reversed view on current array.206 #[must_use]207 pub fn reversed(self) -> Self {208 Self::Reverse(Cc::new(ReverseArray(self)))209 }210211 pub fn ptr_eq(a: &Self, b: &Self) -> bool {212 match (a, b) {213 (ArrValue::Bytes(a), ArrValue::Bytes(b)) => a.0 == b.0,214 (ArrValue::Lazy(a), ArrValue::Lazy(b)) => Cc::ptr_eq(&a.0, &b.0),215 (ArrValue::Expr(a), ArrValue::Expr(b)) => Cc::ptr_eq(&a.0, &b.0),216 (ArrValue::Eager(a), ArrValue::Eager(b)) => Cc::ptr_eq(&a.0, &b.0),217 (ArrValue::Extended(a), ArrValue::Extended(b)) => Cc::ptr_eq(a, b),218 (ArrValue::Range(a), ArrValue::Range(b)) => a == b,219 _ => false,220 }221 }222223 /// Is this vec supports `.get_cheap()?`224 pub fn is_cheap(&self) -> bool {225 match self {226 ArrValue::Eager(_) | ArrValue::Range(..) | ArrValue::Bytes(_) | ArrValue::Chars(_) => {227 true228 }229 ArrValue::Extended(v) => v.a.is_cheap() && v.b.is_cheap(),230 ArrValue::Slice(r) => r.inner.is_cheap(),231 ArrValue::Reverse(i) => i.0.is_cheap(),232 ArrValue::Repeated(v) => v.is_cheap(),233 ArrValue::Expr(_) | ArrValue::Lazy(_) | ArrValue::Mapped(_) => false,234 }235 }236}237impl From<Vec<Val>> for ArrValue {238 fn from(value: Vec<Val>) -> Self {239 Self::eager(value)240 }241}242impl From<Vec<Thunk<Val>>> for ArrValue {243 fn from(value: Vec<Thunk<Val>>) -> Self {244 Self::lazy(Cc::new(value))245 }246}247impl FromIterator<Val> for ArrValue {248 fn from_iter<T: IntoIterator<Item = Val>>(iter: T) -> Self {249 Self::eager(iter.into_iter().collect())250 }251}252253#[cfg(target_pointer_width = "64")]254static_assertions::assert_eq_size!(ArrValue, [u8; 16]);1use std::any::Any;23use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_interner::IBytes;5use jrsonnet_parser::LocExpr;67use crate::{function::FuncVal, gc::TraceBox, tb, Context, Result, Thunk, Val};89mod spec;10pub use spec::ArrayLike;11pub(crate) use spec::*;1213/// Represents a Jsonnet array value.14#[derive(Debug, Clone, Trace)]15// may contrain other ArrValue16#[trace(tracking(force))]17pub struct ArrValue(Cc<TraceBox<dyn ArrayLike>>);1819pub trait ArrayLikeIter<T>: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator {}20impl<I, T> ArrayLikeIter<T> for I where21 I: Iterator<Item = T> + DoubleEndedIterator + ExactSizeIterator22{23}2425impl ArrValue {26 pub fn new(v: impl ArrayLike) -> Self {27 Self(Cc::new(tb!(v)))28 }29 pub fn empty() -> Self {30 Self::new(RangeArray::empty())31 }3233 pub fn expr(ctx: Context, exprs: impl IntoIterator<Item = LocExpr>) -> Self {34 Self::new(ExprArray::new(ctx, exprs))35 }3637 pub fn lazy(thunks: Vec<Thunk<Val>>) -> Self {38 Self::new(LazyArray(thunks))39 }4041 pub fn eager(values: Vec<Val>) -> Self {42 Self::new(EagerArray(values))43 }4445 pub fn repeated(data: ArrValue, repeats: usize) -> Option<Self> {46 Some(Self::new(RepeatedArray::new(data, repeats)?))47 }4849 pub fn bytes(bytes: IBytes) -> Self {50 Self::new(BytesArray(bytes))51 }52 pub fn chars(chars: impl Iterator<Item = char>) -> Self {53 Self::new(CharArray(chars.collect()))54 }5556 #[must_use]57 pub fn map(self, mapper: FuncVal) -> Self {58 Self::new(MappedArray::new(self, mapper))59 }6061 pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {62 // TODO: ArrValue::Picked(inner, indexes) for large arrays63 let mut out = Vec::new();64 for i in self.iter() {65 let i = i?;66 if filter(&i)? {67 out.push(i);68 };69 }70 Ok(Self::eager(out))71 }7273 pub fn extended(a: ArrValue, b: ArrValue) -> Self {74 // TODO: benchmark for an optimal value, currently just a arbitrary choice75 const ARR_EXTEND_THRESHOLD: usize = 100;7677 if a.is_empty() {78 b79 } else if b.is_empty() {80 a81 } else if a.len() + b.len() > ARR_EXTEND_THRESHOLD {82 Self::new(ExtendedArray::new(a, b))83 } else if let (Some(a), Some(b)) = (a.iter_cheap(), b.iter_cheap()) {84 let mut out = Vec::with_capacity(a.len() + b.len());85 out.extend(a);86 out.extend(b);87 Self::eager(out)88 } else {89 let mut out = Vec::with_capacity(a.len() + b.len());90 out.extend(a.iter_lazy());91 out.extend(b.iter_lazy());92 Self::lazy(out)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(105 self,106 from: Option<usize>,107 to: Option<usize>,108 step: Option<usize>,109 ) -> Option<Self> {110 let len = self.len();111 let from = from.unwrap_or(0);112 let to = to.unwrap_or(len).min(len);113 let step = step.unwrap_or(1);114115 if from >= to || step == 0 {116 return None;117 }118119 Some(Self::new(SliceArray {120 inner: self,121 from: from as u32,122 to: to as u32,123 step: step as u32,124 }))125 }126127 /// Array length.128 pub fn len(&self) -> usize {129 self.0.len()130 }131132 /// Is array contains no elements?133 pub fn is_empty(&self) -> bool {134 self.0.is_empty()135 }136137 /// Get array element by index, evaluating it, if it is lazy.138 ///139 /// Returns `None` on out-of-bounds condition.140 pub fn get(&self, index: usize) -> Result<Option<Val>> {141 self.0.get(index)142 }143144 /// Returns None if get is either non cheap, or out of bounds145 fn get_cheap(&self, index: usize) -> Option<Val> {146 self.0.get_cheap(index)147 }148149 /// Get array element by index, without evaluation.150 ///151 /// Returns `None` on out-of-bounds condition.152 pub fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {153 self.0.get_lazy(index)154 }155156 pub fn iter(&self) -> impl ArrayLikeIter<Result<Val>> + '_ {157 (0..self.len()).map(|i| self.get(i).transpose().expect("length checked"))158 }159160 /// Iterate over elements, returning lazy values.161 pub fn iter_lazy(&self) -> impl ArrayLikeIter<Thunk<Val>> + '_ {162 (0..self.len()).map(|i| self.get_lazy(i).expect("length checked"))163 }164165 pub fn iter_cheap(&self) -> Option<impl ArrayLikeIter<Val> + '_> {166 if self.is_cheap() {167 Some((0..self.len()).map(|i| self.get_cheap(i).expect("length and is_cheap checked")))168 } else {169 None170 }171 }172173 /// Return a reversed view on current array.174 #[must_use]175 pub fn reversed(self) -> Self {176 Self::new(ReverseArray(self))177 }178179 pub fn ptr_eq(a: &Self, b: &Self) -> bool {180 Cc::ptr_eq(&a.0, &b.0)181 }182183 /// Is this vec supports `.get_cheap()?`184 pub fn is_cheap(&self) -> bool {185 self.0.is_cheap()186 }187188 pub fn as_any(&self) -> &dyn Any {189 &self.0190 }191}192impl From<Vec<Val>> for ArrValue {193 fn from(value: Vec<Val>) -> Self {194 Self::eager(value)195 }196}197impl From<Vec<Thunk<Val>>> for ArrValue {198 fn from(value: Vec<Thunk<Val>>) -> Self {199 Self::lazy(value)200 }201}202impl FromIterator<Val> for ArrValue {203 fn from_iter<T: IntoIterator<Item = Val>>(iter: T) -> Self {204 Self::eager(iter.into_iter().collect())205 }206}207impl ArrayLike for ArrValue {208 fn len(&self) -> usize {209 self.0.len()210 }211212 fn get(&self, index: usize) -> Result<Option<Val>> {213 self.0.get(index)214 }215216 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {217 self.0.get_lazy(index)218 }219220 fn get_cheap(&self, index: usize) -> Option<Val> {221 self.0.get_cheap(index)222 }223224 fn is_cheap(&self) -> bool {225 self.0.is_cheap()226 }227}228229#[cfg(target_pointer_width = "64")]230static_assertions::assert_eq_size!(ArrValue, [u8; 8]);crates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/arr/spec.rs
+++ b/crates/jrsonnet-evaluator/src/arr/spec.rs
@@ -1,4 +1,4 @@
-use std::{cell::RefCell, iter, mem::replace, rc::Rc};
+use std::{any::Any, cell::RefCell, fmt::Debug, iter, mem::replace};
use jrsonnet_gcmodule::{Cc, Trace};
use jrsonnet_interner::{IBytes, IStr};
@@ -13,7 +13,7 @@
Context, Error, Result, Thunk, Val,
};
-pub trait ArrayLike: Sized + Into<ArrValue> {
+pub trait ArrayLike: Any + Trace + Debug {
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
@@ -22,12 +22,10 @@
fn get_lazy(&self, index: usize) -> Option<Thunk<Val>>;
fn get_cheap(&self, index: usize) -> Option<Val>;
- fn reverse(self) -> ArrValue {
- ArrValue::Reverse(Cc::new(ReverseArray(self.into())))
- }
+ fn is_cheap(&self) -> bool;
}
-#[derive(Debug, Clone, Trace)]
+#[derive(Debug, Trace)]
pub struct SliceArray {
pub(crate) inner: ArrValue,
pub(crate) from: u32,
@@ -81,15 +79,13 @@
fn get_cheap(&self, index: usize) -> Option<Val> {
self.iter_cheap()?.nth(index)
}
-}
-impl From<SliceArray> for ArrValue {
- fn from(value: SliceArray) -> Self {
- Self::Slice(Cc::new(value))
+ fn is_cheap(&self) -> bool {
+ self.inner.is_cheap()
}
}
-#[derive(Trace, Debug, Clone)]
-pub struct CharArray(pub Rc<Vec<char>>);
+#[derive(Trace, Debug)]
+pub struct CharArray(pub Vec<char>);
impl ArrayLike for CharArray {
fn len(&self) -> usize {
self.0.len()
@@ -108,14 +104,12 @@
.get(index)
.map(|v| Val::Str(StrValue::Flat(IStr::from(*v))))
}
-}
-impl From<CharArray> for ArrValue {
- fn from(value: CharArray) -> Self {
- ArrValue::Chars(value)
+ fn is_cheap(&self) -> bool {
+ true
}
}
-#[derive(Trace, Debug, Clone)]
+#[derive(Trace, Debug)]
pub struct BytesArray(pub IBytes);
impl ArrayLike for BytesArray {
fn len(&self) -> usize {
@@ -133,10 +127,8 @@
fn get_cheap(&self, index: usize) -> Option<Val> {
self.0.get(index).map(|v| Val::Num(f64::from(*v)))
}
-}
-impl From<BytesArray> for ArrValue {
- fn from(value: BytesArray) -> Self {
- ArrValue::Bytes(value)
+ fn is_cheap(&self) -> bool {
+ true
}
}
@@ -148,30 +140,30 @@
Pending,
}
-#[derive(Debug, Trace)]
-pub struct ExprArrayInner {
+#[derive(Debug, Trace, Clone)]
+pub struct ExprArray {
ctx: Context,
- cached: RefCell<Vec<ArrayThunk<LocExpr>>>,
+ cached: Cc<RefCell<Vec<ArrayThunk<LocExpr>>>>,
}
-#[derive(Debug, Trace, Clone)]
-pub struct ExprArray(pub Cc<ExprArrayInner>);
impl ExprArray {
pub fn new(ctx: Context, items: impl IntoIterator<Item = LocExpr>) -> Self {
- Self(Cc::new(ExprArrayInner {
+ Self {
ctx,
- cached: RefCell::new(items.into_iter().map(ArrayThunk::Waiting).collect()),
- }))
+ cached: Cc::new(RefCell::new(
+ items.into_iter().map(ArrayThunk::Waiting).collect(),
+ )),
+ }
}
}
impl ArrayLike for ExprArray {
fn len(&self) -> usize {
- self.0.cached.borrow().len()
+ self.cached.borrow().len()
}
fn get(&self, index: usize) -> Result<Option<Val>> {
if index >= self.len() {
return Ok(None);
}
- match &self.0.cached.borrow()[index] {
+ match &self.cached.borrow()[index] {
ArrayThunk::Computed(c) => return Ok(Some(c.clone())),
ArrayThunk::Errored(e) => return Err(e.clone()),
ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),
@@ -179,19 +171,19 @@
};
let ArrayThunk::Waiting(expr) =
- replace(&mut self.0.cached.borrow_mut()[index], ArrayThunk::Pending)
+ replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)
else {
unreachable!()
};
- let new_value = match evaluate(self.0.ctx.clone(), &expr) {
+ let new_value = match evaluate(self.ctx.clone(), &expr) {
Ok(v) => v,
Err(e) => {
- self.0.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());
+ self.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());
return Err(e);
}
};
- self.0.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());
+ self.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());
Ok(Some(new_value))
}
fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
@@ -215,7 +207,7 @@
if index >= self.len() {
return None;
}
- match &self.0.cached.borrow()[index] {
+ match &self.cached.borrow()[index] {
ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),
ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),
ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}
@@ -229,14 +221,12 @@
fn get_cheap(&self, _index: usize) -> Option<Val> {
None
}
-}
-impl From<ExprArray> for ArrValue {
- fn from(value: ExprArray) -> Self {
- Self::Expr(value)
+ fn is_cheap(&self) -> bool {
+ false
}
}
-#[derive(Trace, Debug, Clone)]
+#[derive(Trace, Debug)]
pub struct ExtendedArray {
pub a: ArrValue,
pub b: ArrValue,
@@ -319,15 +309,13 @@
self.b.get_cheap(index - self.split)
}
}
-}
-impl From<ExtendedArray> for ArrValue {
- fn from(value: ExtendedArray) -> Self {
- Self::Extended(Cc::new(value))
+ fn is_cheap(&self) -> bool {
+ self.a.is_cheap() && self.b.is_cheap()
}
}
-#[derive(Trace, Debug, Clone)]
-pub struct LazyArray(pub Cc<Vec<Thunk<Val>>>);
+#[derive(Trace, Debug)]
+pub struct LazyArray(pub Vec<Thunk<Val>>);
impl ArrayLike for LazyArray {
fn len(&self) -> usize {
self.0.len()
@@ -344,15 +332,13 @@
fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
self.0.get(index).cloned()
}
-}
-impl From<LazyArray> for ArrValue {
- fn from(value: LazyArray) -> Self {
- Self::Lazy(value)
+ fn is_cheap(&self) -> bool {
+ false
}
}
-#[derive(Trace, Debug, Clone)]
-pub struct EagerArray(pub Cc<Vec<Val>>);
+#[derive(Trace, Debug)]
+pub struct EagerArray(pub Vec<Val>);
impl ArrayLike for EagerArray {
fn len(&self) -> usize {
self.0.len()
@@ -369,15 +355,13 @@
fn get_cheap(&self, index: usize) -> Option<Val> {
self.0.get(index).cloned()
}
-}
-impl From<EagerArray> for ArrValue {
- fn from(value: EagerArray) -> Self {
- Self::Eager(value)
+ fn is_cheap(&self) -> bool {
+ true
}
}
/// Inclusive range type
-#[derive(Debug, Trace, Clone, PartialEq, Eq)]
+#[derive(Debug, Trace, PartialEq, Eq)]
pub struct RangeArray {
start: i32,
end: i32,
@@ -422,14 +406,12 @@
fn get_cheap(&self, index: usize) -> Option<Val> {
self.range().nth(index).map(|i| Val::Num(f64::from(i)))
}
-}
-impl From<RangeArray> for ArrValue {
- fn from(value: RangeArray) -> Self {
- Self::Range(value)
+ fn is_cheap(&self) -> bool {
+ true
}
}
-#[derive(Debug, Trace, Clone)]
+#[derive(Debug, Trace)]
pub struct ReverseArray(pub ArrValue);
impl ArrayLike for ReverseArray {
fn len(&self) -> usize {
@@ -447,44 +429,37 @@
fn get_cheap(&self, index: usize) -> Option<Val> {
self.0.get_cheap(self.0.len() - index - 1)
}
- fn reverse(self) -> ArrValue {
- self.0
- }
-}
-impl From<ReverseArray> for ArrValue {
- fn from(value: ReverseArray) -> Self {
- Self::Reverse(Cc::new(value))
+ fn is_cheap(&self) -> bool {
+ self.0.is_cheap()
}
}
-#[derive(Trace, Debug)]
-pub struct MappedArrayInner {
+#[derive(Trace, Debug, Clone)]
+pub struct MappedArray {
inner: ArrValue,
- cached: RefCell<Vec<ArrayThunk<()>>>,
+ cached: Cc<RefCell<Vec<ArrayThunk<()>>>>,
mapper: FuncVal,
}
-#[derive(Trace, Debug, Clone)]
-pub struct MappedArray(Cc<MappedArrayInner>);
impl MappedArray {
pub fn new(inner: ArrValue, mapper: FuncVal) -> Self {
let len = inner.len();
- Self(Cc::new(MappedArrayInner {
+ Self {
inner,
- cached: RefCell::new(vec![ArrayThunk::Waiting(()); len]),
+ cached: Cc::new(RefCell::new(vec![ArrayThunk::Waiting(()); len])),
mapper,
- }))
+ }
}
}
impl ArrayLike for MappedArray {
fn len(&self) -> usize {
- self.0.cached.borrow().len()
+ self.cached.borrow().len()
}
fn get(&self, index: usize) -> Result<Option<Val>> {
if index >= self.len() {
return Ok(None);
}
- match &self.0.cached.borrow()[index] {
+ match &self.cached.borrow()[index] {
ArrayThunk::Computed(c) => return Ok(Some(c.clone())),
ArrayThunk::Errored(e) => return Err(e.clone()),
ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),
@@ -492,27 +467,26 @@
};
let ArrayThunk::Waiting(_) =
- replace(&mut self.0.cached.borrow_mut()[index], ArrayThunk::Pending)
+ replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)
else {
unreachable!()
};
let val = self
- .0
.inner
.get(index)
.transpose()
.expect("index checked")
- .and_then(|r| self.0.mapper.evaluate_simple(&(r,), false));
+ .and_then(|r| self.mapper.evaluate_simple(&(r,), false));
let new_value = match val {
Ok(v) => v,
Err(e) => {
- self.0.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());
+ self.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());
return Err(e);
}
};
- self.0.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());
+ self.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());
Ok(Some(new_value))
}
fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
@@ -536,7 +510,7 @@
if index >= self.len() {
return None;
}
- match &self.0.cached.borrow()[index] {
+ match &self.cached.borrow()[index] {
ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),
ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),
ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}
@@ -551,82 +525,54 @@
fn get_cheap(&self, _index: usize) -> Option<Val> {
None
}
-}
-impl From<MappedArray> for ArrValue {
- fn from(value: MappedArray) -> Self {
- Self::Mapped(value)
+ fn is_cheap(&self) -> bool {
+ false
}
}
#[derive(Trace, Debug)]
-pub struct RepeatedArrayInner {
+pub struct RepeatedArray {
data: ArrValue,
repeats: usize,
total_len: usize,
}
-#[derive(Trace, Debug, Clone)]
-pub struct RepeatedArray(Cc<RepeatedArrayInner>);
impl RepeatedArray {
pub fn new(data: ArrValue, repeats: usize) -> Option<Self> {
let total_len = data.len().checked_mul(repeats)?;
- Some(Self(Cc::new(RepeatedArrayInner {
+ Some(Self {
data,
repeats,
total_len,
- })))
- }
- pub fn is_cheap(&self) -> bool {
- self.0.data.is_cheap()
+ })
}
}
impl ArrayLike for RepeatedArray {
fn len(&self) -> usize {
- self.0.total_len
+ self.total_len
}
fn get(&self, index: usize) -> Result<Option<Val>> {
- if index > self.0.total_len {
+ if index > self.total_len {
return Ok(None);
}
- self.0.data.get(index % self.0.data.len())
+ self.data.get(index % self.data.len())
}
fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {
- if index > self.0.total_len {
+ if index > self.total_len {
return None;
}
- self.0.data.get_lazy(index % self.0.data.len())
+ self.data.get_lazy(index % self.data.len())
}
fn get_cheap(&self, index: usize) -> Option<Val> {
- if index > self.0.total_len {
+ if index > self.total_len {
return None;
}
- self.0.data.get_cheap(index % self.0.data.len())
+ self.data.get_cheap(index % self.data.len())
}
-}
-impl From<RepeatedArray> for ArrValue {
- fn from(value: RepeatedArray) -> Self {
- Self::Repeated(value)
+ fn is_cheap(&self) -> bool {
+ self.data.is_cheap()
}
}
-
-macro_rules! pass {
- ($t:ident.$m:ident($($ident:ident),*)) => {
- match $t {
- Self::Bytes(e) => e.$m($($ident)*),
- Self::Chars(e) => e.$m($($ident)*),
- Self::Expr(e) => e.$m($($ident)*),
- Self::Lazy(e) => e.$m($($ident)*),
- Self::Eager(e) => e.$m($($ident)*),
- Self::Range(e) => e.$m($($ident)*),
- Self::Slice(e) => e.$m($($ident)*),
- Self::Extended(e) => e.$m($($ident)*),
- Self::Reverse(e) => e.$m($($ident)*),
- Self::Mapped(e) => e.$m($($ident)*),
- Self::Repeated(e) => e.$m($($ident)*),
- }
- };
-}
-pub(super) use pass;
crates/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()))
}
crates/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"))]
crates/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!()
+ }
}
}
}
crates/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,
crates/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))
}
crates/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))
}
}