difftreelog
refactor move arrays to use dyn ArrayLike
in: master
8 files changed
crates/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]);
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.rsdiffbeforeafterboth1#![allow(non_snake_case)]23use std::cmp::Ordering;45use jrsonnet_evaluator::{6 error::Result,7 function::{builtin, FuncVal},8 operator::evaluate_compare_op,9 throw,10 val::{equals, ArrValue},11 Thunk, Val,12};13use jrsonnet_gcmodule::Cc;14use jrsonnet_parser::BinaryOpType;1516use crate::eval_on_empty;1718#[derive(Copy, Clone)]19enum SortKeyType {20 Number,21 String,22 Unknown,23}2425#[derive(PartialEq)]26struct NonNaNf64(f64);27impl PartialOrd for NonNaNf64 {28 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {29 Some(self.cmp(other))30 }31}32impl Eq for NonNaNf64 {}33impl Ord for NonNaNf64 {34 fn cmp(&self, other: &Self) -> std::cmp::Ordering {35 self.0.partial_cmp(&other.0).expect("non nan")36 }37}3839fn get_sort_type<T>(values: &[T], key_getter: impl Fn(&T) -> &Val) -> Result<SortKeyType> {40 let mut sort_type = SortKeyType::Unknown;41 for i in values.iter() {42 let i = key_getter(i);43 match (i, sort_type) {44 (Val::Str(_), SortKeyType::Unknown) => sort_type = SortKeyType::String,45 (Val::Num(_), SortKeyType::Unknown) => sort_type = SortKeyType::Number,46 (Val::Str(_), SortKeyType::String) | (Val::Num(_), SortKeyType::Number) => {}47 (Val::Str(_) | Val::Num(_), _) => {48 throw!("sort elements should have the same types")49 }50 _ => {}51 }52 }53 Ok(sort_type)54}5556fn sort_identity(mut values: Vec<Val>) -> Result<Vec<Val>> {57 // Fast path, identity key getter58 let sort_type = get_sort_type(&values, |k| k)?;59 match sort_type {60 SortKeyType::Number => values.sort_unstable_by_key(|v| match v {61 Val::Num(n) => NonNaNf64(*n),62 _ => unreachable!(),63 }),64 SortKeyType::String => values.sort_unstable_by_key(|v| match v {65 Val::Str(s) => s.clone(),66 _ => unreachable!(),67 }),68 SortKeyType::Unknown => {69 let mut err = None;70 // evaluate_compare_op will never return equal on types, which are different from71 // jsonnet perspective72 values.sort_unstable_by(|a, b| match evaluate_compare_op(a, b, BinaryOpType::Lt) {73 Ok(ord) => ord,74 Err(e) if err.is_none() => {75 let _ = err.insert(e);76 Ordering::Equal77 }78 Err(_) => Ordering::Equal,79 });80 if let Some(err) = err {81 return Err(err);82 }83 }84 };85 Ok(values)86}8788fn sort_keyf(values: ArrValue, keyf: FuncVal) -> Result<Vec<Thunk<Val>>> {89 // Slow path, user provided key getter90 let mut vk = Vec::with_capacity(values.len());91 for value in values.iter_lazy() {92 vk.push((93 value.clone(),94 keyf.evaluate_simple(&(value.clone(),), false)?,95 ));96 }97 let sort_type = get_sort_type(&vk, |v| &v.1)?;98 match sort_type {99 SortKeyType::Number => vk.sort_by_key(|v| match v.1 {100 Val::Num(n) => NonNaNf64(n),101 _ => unreachable!(),102 }),103 SortKeyType::String => vk.sort_by_key(|v| match &v.1 {104 Val::Str(s) => s.clone(),105 _ => unreachable!(),106 }),107 SortKeyType::Unknown => {108 let mut err = None;109 // evaluate_compare_op will never return equal on types, which are different from110 // jsonnet perspective111 vk.sort_by(112 |(_a, ak), (_b, bk)| match evaluate_compare_op(ak, bk, BinaryOpType::Lt) {113 Ok(ord) => ord,114 Err(e) if err.is_none() => {115 let _ = err.insert(e);116 Ordering::Equal117 }118 Err(_) => Ordering::Equal,119 },120 );121 if let Some(err) = err {122 return Err(err);123 }124 }125 };126 Ok(vk.into_iter().map(|v| v.0).collect())127}128129/// * `key_getter` - None, if identity sort required130pub fn sort(values: ArrValue, key_getter: FuncVal) -> Result<ArrValue> {131 if values.len() <= 1 {132 return Ok(values);133 }134 if key_getter.is_identity() {135 Ok(ArrValue::eager(sort_identity(136 values.iter().collect::<Result<Vec<Val>>>()?,137 )?))138 } else {139 Ok(ArrValue::lazy(Cc::new(sort_keyf(values, key_getter)?)))140 }141}142143#[builtin]144pub fn builtin_sort(arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {145 super::sort::sort(arr, keyF.unwrap_or_else(FuncVal::identity))146}147148fn uniq_identity(arr: Vec<Val>) -> Result<Vec<Val>> {149 let mut out = Vec::new();150 let mut last = arr[0].clone();151 out.push(last.clone());152 for next in arr.into_iter().skip(1) {153 if !equals(&last, &next)? {154 out.push(next.clone());155 }156 last = next;157 }158 Ok(out)159}160161fn uniq_keyf(arr: ArrValue, keyf: FuncVal) -> Result<Vec<Thunk<Val>>> {162 let mut out = Vec::new();163 let last_value = arr.get_lazy(0).unwrap();164 let mut last_key = keyf.evaluate_simple(&(last_value.clone(),), false)?;165 out.push(last_value);166167 for next in arr.iter_lazy().skip(1) {168 let next_key = keyf.evaluate_simple(&(next.clone(),), false)?;169 if !equals(&last_key, &next_key)? {170 out.push(next.clone());171 }172 last_key = next_key;173 }174 Ok(out)175}176177#[builtin]178#[allow(non_snake_case)]179pub fn builtin_uniq(arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {180 if arr.len() <= 1 {181 return Ok(arr);182 }183 let keyF = keyF.unwrap_or(FuncVal::identity());184 if keyF.is_identity() {185 Ok(ArrValue::eager(uniq_identity(186 arr.iter().collect::<Result<Vec<Val>>>()?,187 )?))188 } else {189 Ok(ArrValue::lazy(Cc::new(uniq_keyf(arr, keyF)?)))190 }191}192193#[builtin]194#[allow(non_snake_case)]195pub fn builtin_set(arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {196 if arr.len() <= 1 {197 return Ok(arr);198 }199 let keyF = keyF.unwrap_or(FuncVal::identity());200 if keyF.is_identity() {201 let arr = arr.iter().collect::<Result<Vec<Val>>>()?;202 let arr = sort_identity(arr)?;203 let arr = uniq_identity(arr)?;204 Ok(ArrValue::eager(arr))205 } else {206 let arr = sort_keyf(arr, keyF.clone())?;207 let arr = uniq_keyf(ArrValue::lazy(Cc::new(arr)), keyF)?;208 Ok(ArrValue::lazy(Cc::new(arr)))209 }210}211212fn eval_keyf(val: Val, key_f: &Option<FuncVal>) -> Result<Val> {213 if let Some(key_f) = key_f {214 key_f.evaluate_simple(&(val,), false)215 } else {216 Ok(val)217 }218}219220fn array_top1(arr: ArrValue, key_f: Option<FuncVal>, ordering: Ordering) -> Result<Val> {221 let mut iter = arr.iter();222 let mut min = iter.next().expect("not empty")?;223 let mut min_key = eval_keyf(min.clone(), &key_f)?;224 for item in iter {225 let cur = item?;226 let cur_key = eval_keyf(cur.clone(), &key_f)?;227 if evaluate_compare_op(&cur_key, &min_key, BinaryOpType::Lt)? == ordering {228 min = cur;229 min_key = cur_key;230 }231 }232 Ok(min)233}234235#[builtin]236pub fn builtin_min_array(237 arr: ArrValue,238 keyF: Option<FuncVal>,239 onEmpty: Option<Thunk<Val>>,240) -> Result<Val> {241 if arr.is_empty() {242 return eval_on_empty(onEmpty);243 }244 array_top1(arr, keyF, Ordering::Less)245}246#[builtin]247pub fn builtin_max_array(248 arr: ArrValue,249 keyF: Option<FuncVal>,250 onEmpty: Option<Thunk<Val>>,251) -> Result<Val> {252 if arr.is_empty() {253 return eval_on_empty(onEmpty);254 }255 array_top1(arr, keyF, Ordering::Greater)256}1#![allow(non_snake_case)]23use std::cmp::Ordering;45use jrsonnet_evaluator::{6 error::Result,7 function::{builtin, FuncVal},8 operator::evaluate_compare_op,9 throw,10 val::{equals, ArrValue},11 Thunk, Val,12};13use jrsonnet_parser::BinaryOpType;1415use crate::eval_on_empty;1617#[derive(Copy, Clone)]18enum SortKeyType {19 Number,20 String,21 Unknown,22}2324#[derive(PartialEq)]25struct NonNaNf64(f64);26impl PartialOrd for NonNaNf64 {27 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {28 Some(self.cmp(other))29 }30}31impl Eq for NonNaNf64 {}32impl Ord for NonNaNf64 {33 fn cmp(&self, other: &Self) -> std::cmp::Ordering {34 self.0.partial_cmp(&other.0).expect("non nan")35 }36}3738fn get_sort_type<T>(values: &[T], key_getter: impl Fn(&T) -> &Val) -> Result<SortKeyType> {39 let mut sort_type = SortKeyType::Unknown;40 for i in values.iter() {41 let i = key_getter(i);42 match (i, sort_type) {43 (Val::Str(_), SortKeyType::Unknown) => sort_type = SortKeyType::String,44 (Val::Num(_), SortKeyType::Unknown) => sort_type = SortKeyType::Number,45 (Val::Str(_), SortKeyType::String) | (Val::Num(_), SortKeyType::Number) => {}46 (Val::Str(_) | Val::Num(_), _) => {47 throw!("sort elements should have the same types")48 }49 _ => {}50 }51 }52 Ok(sort_type)53}5455fn sort_identity(mut values: Vec<Val>) -> Result<Vec<Val>> {56 // Fast path, identity key getter57 let sort_type = get_sort_type(&values, |k| k)?;58 match sort_type {59 SortKeyType::Number => values.sort_unstable_by_key(|v| match v {60 Val::Num(n) => NonNaNf64(*n),61 _ => unreachable!(),62 }),63 SortKeyType::String => values.sort_unstable_by_key(|v| match v {64 Val::Str(s) => s.clone(),65 _ => unreachable!(),66 }),67 SortKeyType::Unknown => {68 let mut err = None;69 // evaluate_compare_op will never return equal on types, which are different from70 // jsonnet perspective71 values.sort_unstable_by(|a, b| match evaluate_compare_op(a, b, BinaryOpType::Lt) {72 Ok(ord) => ord,73 Err(e) if err.is_none() => {74 let _ = err.insert(e);75 Ordering::Equal76 }77 Err(_) => Ordering::Equal,78 });79 if let Some(err) = err {80 return Err(err);81 }82 }83 };84 Ok(values)85}8687fn sort_keyf(values: ArrValue, keyf: FuncVal) -> Result<Vec<Thunk<Val>>> {88 // Slow path, user provided key getter89 let mut vk = Vec::with_capacity(values.len());90 for value in values.iter_lazy() {91 vk.push((92 value.clone(),93 keyf.evaluate_simple(&(value.clone(),), false)?,94 ));95 }96 let sort_type = get_sort_type(&vk, |v| &v.1)?;97 match sort_type {98 SortKeyType::Number => vk.sort_by_key(|v| match v.1 {99 Val::Num(n) => NonNaNf64(n),100 _ => unreachable!(),101 }),102 SortKeyType::String => vk.sort_by_key(|v| match &v.1 {103 Val::Str(s) => s.clone(),104 _ => unreachable!(),105 }),106 SortKeyType::Unknown => {107 let mut err = None;108 // evaluate_compare_op will never return equal on types, which are different from109 // jsonnet perspective110 vk.sort_by(111 |(_a, ak), (_b, bk)| match evaluate_compare_op(ak, bk, BinaryOpType::Lt) {112 Ok(ord) => ord,113 Err(e) if err.is_none() => {114 let _ = err.insert(e);115 Ordering::Equal116 }117 Err(_) => Ordering::Equal,118 },119 );120 if let Some(err) = err {121 return Err(err);122 }123 }124 };125 Ok(vk.into_iter().map(|v| v.0).collect())126}127128/// * `key_getter` - None, if identity sort required129pub fn sort(values: ArrValue, key_getter: FuncVal) -> Result<ArrValue> {130 if values.len() <= 1 {131 return Ok(values);132 }133 if key_getter.is_identity() {134 Ok(ArrValue::eager(sort_identity(135 values.iter().collect::<Result<Vec<Val>>>()?,136 )?))137 } else {138 Ok(ArrValue::lazy(sort_keyf(values, key_getter)?))139 }140}141142#[builtin]143pub fn builtin_sort(arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {144 super::sort::sort(arr, keyF.unwrap_or_else(FuncVal::identity))145}146147fn uniq_identity(arr: Vec<Val>) -> Result<Vec<Val>> {148 let mut out = Vec::new();149 let mut last = arr[0].clone();150 out.push(last.clone());151 for next in arr.into_iter().skip(1) {152 if !equals(&last, &next)? {153 out.push(next.clone());154 }155 last = next;156 }157 Ok(out)158}159160fn uniq_keyf(arr: ArrValue, keyf: FuncVal) -> Result<Vec<Thunk<Val>>> {161 let mut out = Vec::new();162 let last_value = arr.get_lazy(0).unwrap();163 let mut last_key = keyf.evaluate_simple(&(last_value.clone(),), false)?;164 out.push(last_value);165166 for next in arr.iter_lazy().skip(1) {167 let next_key = keyf.evaluate_simple(&(next.clone(),), false)?;168 if !equals(&last_key, &next_key)? {169 out.push(next.clone());170 }171 last_key = next_key;172 }173 Ok(out)174}175176#[builtin]177#[allow(non_snake_case)]178pub fn builtin_uniq(arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {179 if arr.len() <= 1 {180 return Ok(arr);181 }182 let keyF = keyF.unwrap_or(FuncVal::identity());183 if keyF.is_identity() {184 Ok(ArrValue::eager(uniq_identity(185 arr.iter().collect::<Result<Vec<Val>>>()?,186 )?))187 } else {188 Ok(ArrValue::lazy(uniq_keyf(arr, keyF)?))189 }190}191192#[builtin]193#[allow(non_snake_case)]194pub fn builtin_set(arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {195 if arr.len() <= 1 {196 return Ok(arr);197 }198 let keyF = keyF.unwrap_or(FuncVal::identity());199 if keyF.is_identity() {200 let arr = arr.iter().collect::<Result<Vec<Val>>>()?;201 let arr = sort_identity(arr)?;202 let arr = uniq_identity(arr)?;203 Ok(ArrValue::eager(arr))204 } else {205 let arr = sort_keyf(arr, keyF.clone())?;206 let arr = uniq_keyf(ArrValue::lazy(arr), keyF)?;207 Ok(ArrValue::lazy(arr))208 }209}210211fn eval_keyf(val: Val, key_f: &Option<FuncVal>) -> Result<Val> {212 if let Some(key_f) = key_f {213 key_f.evaluate_simple(&(val,), false)214 } else {215 Ok(val)216 }217}218219fn array_top1(arr: ArrValue, key_f: Option<FuncVal>, ordering: Ordering) -> Result<Val> {220 let mut iter = arr.iter();221 let mut min = iter.next().expect("not empty")?;222 let mut min_key = eval_keyf(min.clone(), &key_f)?;223 for item in iter {224 let cur = item?;225 let cur_key = eval_keyf(cur.clone(), &key_f)?;226 if evaluate_compare_op(&cur_key, &min_key, BinaryOpType::Lt)? == ordering {227 min = cur;228 min_key = cur_key;229 }230 }231 Ok(min)232}233234#[builtin]235pub fn builtin_min_array(236 arr: ArrValue,237 keyF: Option<FuncVal>,238 onEmpty: Option<Thunk<Val>>,239) -> Result<Val> {240 if arr.is_empty() {241 return eval_on_empty(onEmpty);242 }243 array_top1(arr, keyF, Ordering::Less)244}245#[builtin]246pub fn builtin_max_array(247 arr: ArrValue,248 keyF: Option<FuncVal>,249 onEmpty: Option<Thunk<Val>>,250) -> Result<Val> {251 if arr.is_empty() {252 return eval_on_empty(onEmpty);253 }254 array_top1(arr, keyF, Ordering::Greater)255}