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.rsdiffbeforeafterboth1use std::{collections::BTreeMap, marker::PhantomData, ops::Deref};23use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_interner::{IBytes, IStr};5pub use jrsonnet_macros::Typed;6use jrsonnet_types::{ComplexValType, ValType};78use crate::{9 arr::ArrValue,10 error::Result,11 function::{native::NativeDesc, FuncDesc, FuncVal},12 throw,13 typed::CheckType,14 val::{IndexableVal, StrValue, ThunkMapper},15 ObjValue, ObjValueBuilder, Thunk, Val,16};1718#[derive(Trace)]19struct FromUntyped<K: Trace>(PhantomData<fn() -> K>);20impl<K> ThunkMapper<Val> for FromUntyped<K>21where22 K: Typed + Trace,23{24 type Output = K;2526 fn map(self, from: Val) -> Result<Self::Output> {27 K::from_untyped(from)28 }29}30impl<K: Trace> Default for FromUntyped<K> {31 fn default() -> Self {32 Self(PhantomData)33 }34}3536pub trait TypedObj: Typed {37 fn serialize(self, out: &mut ObjValueBuilder) -> Result<()>;38 fn parse(obj: &ObjValue) -> Result<Self>;39 fn into_object(self) -> Result<ObjValue> {40 let mut builder = ObjValueBuilder::new();41 self.serialize(&mut builder)?;42 Ok(builder.build())43 }44}4546pub trait Typed: Sized {47 const TYPE: &'static ComplexValType;48 fn into_untyped(typed: Self) -> Result<Val>;49 fn into_lazy_untyped(typed: Self) -> Thunk<Val> {50 Thunk::from(Self::into_untyped(typed))51 }52 fn from_untyped(untyped: Val) -> Result<Self>;53 fn from_lazy_untyped(lazy: Thunk<Val>) -> Result<Self> {54 Self::from_untyped(lazy.evaluate()?)55 }5657 // Whatever caller should use `into_lazy_untyped` instead of `into_untyped`58 fn provides_lazy() -> bool {59 false60 }6162 // Whatever caller should use `from_lazy_untyped` instead of `from_untyped` when possible63 fn wants_lazy() -> bool {64 false65 }6667 /// Hack to make builtins be able to return non-result values, and make macros able to convert those values to result68 /// This method returns identity in impl Typed for Result, and should not be overriden69 #[doc(hidden)]70 fn into_result(typed: Self) -> Result<Val> {71 let value = Self::into_untyped(typed)?;72 Ok(value)73 }74}7576impl<T> Typed for Thunk<T>77where78 T: Typed + Trace + Clone,79{80 const TYPE: &'static ComplexValType = &ComplexValType::Lazy(T::TYPE);8182 fn into_untyped(typed: Self) -> Result<Val> {83 T::into_untyped(typed.evaluate()?)84 }8586 fn from_untyped(untyped: Val) -> Result<Self> {87 Self::from_lazy_untyped(Thunk::evaluated(untyped))88 }8990 fn provides_lazy() -> bool {91 true92 }9394 fn into_lazy_untyped(inner: Self) -> Thunk<Val> {95 #[derive(Trace)]96 struct IntoUntyped<K: Trace>(PhantomData<fn() -> K>);97 impl<K> ThunkMapper<K> for IntoUntyped<K>98 where99 K: Typed + Trace,100 {101 type Output = Val;102103 fn map(self, from: K) -> Result<Self::Output> {104 K::into_untyped(from)105 }106 }107 impl<K: Trace> Default for IntoUntyped<K> {108 fn default() -> Self {109 Self(PhantomData)110 }111 }112 inner.map(<IntoUntyped<T>>::default())113 }114115 fn wants_lazy() -> bool {116 true117 }118119 fn from_lazy_untyped(inner: Thunk<Val>) -> Result<Self> {120 Ok(inner.map(<FromUntyped<T>>::default()))121 }122}123124const MAX_SAFE_INTEGER: f64 = ((1u64 << (f64::MANTISSA_DIGITS + 1)) - 1) as f64;125126macro_rules! impl_int {127 ($($ty:ty)*) => {$(128 impl Typed for $ty {129 const TYPE: &'static ComplexValType =130 &ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64));131 fn from_untyped(value: Val) -> Result<Self> {132 <Self as Typed>::TYPE.check(&value)?;133 match value {134 Val::Num(n) => {135 #[allow(clippy::float_cmp)]136 if n.trunc() != n {137 throw!(138 "cannot convert number with fractional part to {}",139 stringify!($ty)140 )141 }142 Ok(n as Self)143 }144 _ => unreachable!(),145 }146 }147 fn into_untyped(value: Self) -> Result<Val> {148 Ok(Val::Num(value as f64))149 }150 }151 )*};152}153154impl_int!(i8 u8 i16 u16 i32 u32);155156macro_rules! impl_bounded_int {157 ($($name:ident = $ty:ty)*) => {$(158 #[derive(Clone, Copy)]159 pub struct $name<const MIN: $ty, const MAX: $ty>($ty);160 impl<const MIN: $ty, const MAX: $ty> $name<MIN, MAX> {161 pub const fn new(value: $ty) -> Option<$name<MIN, MAX>> {162 if value >= MIN && value <= MAX {163 Some(Self(value))164 } else {165 None166 }167 }168 pub const fn value(self) -> $ty {169 self.0170 }171 }172 impl<const MIN: $ty, const MAX: $ty> Deref for $name<MIN, MAX> {173 type Target = $ty;174 fn deref(&self) -> &Self::Target {175 &self.0176 }177 }178179 impl<const MIN: $ty, const MAX: $ty> Typed for $name<MIN, MAX> {180 const TYPE: &'static ComplexValType =181 &ComplexValType::BoundedNumber(182 Some(MIN as f64),183 Some(MAX as f64),184 );185186 fn from_untyped(value: Val) -> Result<Self> {187 <Self as Typed>::TYPE.check(&value)?;188 match value {189 Val::Num(n) => {190 #[allow(clippy::float_cmp)]191 if n.trunc() != n {192 throw!(193 "cannot convert number with fractional part to {}",194 stringify!($ty)195 )196 }197 Ok(Self(n as $ty))198 }199 _ => unreachable!(),200 }201 }202203 fn into_untyped(value: Self) -> Result<Val> {204 Ok(Val::Num(value.0 as f64))205 }206 }207 )*};208}209210impl_bounded_int!(211 BoundedI8 = i8212 BoundedI16 = i16213 BoundedI32 = i32214 BoundedI64 = i64215 BoundedUsize = usize216);217218impl Typed for f64 {219 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);220221 fn into_untyped(value: Self) -> Result<Val> {222 Ok(Val::Num(value))223 }224225 fn from_untyped(value: Val) -> Result<Self> {226 <Self as Typed>::TYPE.check(&value)?;227 match value {228 Val::Num(n) => Ok(n),229 _ => unreachable!(),230 }231 }232}233234pub struct PositiveF64(pub f64);235impl Typed for PositiveF64 {236 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None);237238 fn into_untyped(value: Self) -> Result<Val> {239 Ok(Val::Num(value.0))240 }241242 fn from_untyped(value: Val) -> Result<Self> {243 <Self as Typed>::TYPE.check(&value)?;244 match value {245 Val::Num(n) => Ok(Self(n)),246 _ => unreachable!(),247 }248 }249}250impl Typed for usize {251 const TYPE: &'static ComplexValType =252 &ComplexValType::BoundedNumber(Some(0.0), Some(MAX_SAFE_INTEGER));253254 fn into_untyped(value: Self) -> Result<Val> {255 if value > MAX_SAFE_INTEGER as Self {256 throw!("number is too large")257 }258 Ok(Val::Num(value as f64))259 }260261 fn from_untyped(value: Val) -> Result<Self> {262 <Self as Typed>::TYPE.check(&value)?;263 match value {264 Val::Num(n) => {265 #[allow(clippy::float_cmp)]266 if n.trunc() != n {267 throw!("cannot convert number with fractional part to usize")268 }269 Ok(n as Self)270 }271 _ => unreachable!(),272 }273 }274}275276impl Typed for IStr {277 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);278279 fn into_untyped(value: Self) -> Result<Val> {280 Ok(Val::Str(StrValue::Flat(value)))281 }282283 fn from_untyped(value: Val) -> Result<Self> {284 <Self as Typed>::TYPE.check(&value)?;285 match value {286 Val::Str(s) => Ok(s.into_flat()),287 _ => unreachable!(),288 }289 }290}291292impl Typed for String {293 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);294295 fn into_untyped(value: Self) -> Result<Val> {296 Ok(Val::Str(StrValue::Flat(value.into())))297 }298299 fn from_untyped(value: Val) -> Result<Self> {300 <Self as Typed>::TYPE.check(&value)?;301 match value {302 Val::Str(s) => Ok(s.to_string()),303 _ => unreachable!(),304 }305 }306}307308impl Typed for char {309 const TYPE: &'static ComplexValType = &ComplexValType::Char;310311 fn into_untyped(value: Self) -> Result<Val> {312 Ok(Val::Str(StrValue::Flat(value.to_string().into())))313 }314315 fn from_untyped(value: Val) -> Result<Self> {316 <Self as Typed>::TYPE.check(&value)?;317 match value {318 Val::Str(s) => Ok(s.into_flat().chars().next().unwrap()),319 _ => unreachable!(),320 }321 }322}323324impl<T> Typed for Vec<T>325where326 T: Typed,327{328 const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);329330 fn into_untyped(value: Self) -> Result<Val> {331 Ok(Val::Arr(332 value333 .into_iter()334 .map(T::into_untyped)335 .collect::<Result<ArrValue>>()?,336 ))337 }338339 fn from_untyped(value: Val) -> Result<Self> {340 let Val::Arr(a) = value else {341 <Self as Typed>::TYPE.check(&value)?;342 unreachable!("typecheck should fail")343 };344 a.iter()345 .map(|r| r.and_then(T::from_untyped))346 .collect::<Result<Vec<T>>>()347 }348}349350impl<K: Typed + Ord, V: Typed> Typed for BTreeMap<K, V> {351 const TYPE: &'static ComplexValType = &ComplexValType::AttrsOf(V::TYPE);352353 fn into_untyped(typed: Self) -> Result<Val> {354 let mut out = ObjValueBuilder::with_capacity(typed.len());355 for (k, v) in typed {356 let Some(key) = K::into_untyped(k)?.as_str() else {357 throw!("map key should serialize to string");358 };359 let value = V::into_untyped(v)?;360 out.member(key).value_unchecked(value);361 }362 Ok(Val::Obj(out.build()))363 }364365 fn from_untyped(value: Val) -> Result<Self> {366 Self::TYPE.check(&value)?;367 let obj = value.as_obj().expect("typecheck should fail");368369 let mut out = BTreeMap::new();370 if V::wants_lazy() {371 for key in obj.fields_ex(372 false,373 #[cfg(feature = "exp-preserve-order")]374 false,375 ) {376 let value = obj.get_lazy(key.clone()).expect("field exists");377 let value = V::from_lazy_untyped(value)?;378 let key = K::from_untyped(Val::Str(key.into()))?;379 let _ = out.insert(key, value);380 }381 } else {382 for (key, value) in obj.iter(383 #[cfg(feature = "exp-preserve-order")]384 false,385 ) {386 let key = K::from_untyped(Val::Str(key.into()))?;387 let value = V::from_untyped(value?)?;388 let _ = out.insert(key, value);389 }390 }391 Ok(out)392 }393}394395impl Typed for Val {396 const TYPE: &'static ComplexValType = &ComplexValType::Any;397398 fn into_untyped(typed: Self) -> Result<Val> {399 Ok(typed)400 }401 fn from_untyped(untyped: Val) -> Result<Self> {402 Ok(untyped)403 }404}405406// Hack407#[doc(hidden)]408impl<T> Typed for Result<T>409where410 T: Typed,411{412 const TYPE: &'static ComplexValType = &ComplexValType::Any;413414 fn into_untyped(_typed: Self) -> Result<Val> {415 panic!("do not use this conversion")416 }417418 fn from_untyped(_untyped: Val) -> Result<Self> {419 panic!("do not use this conversion")420 }421422 fn into_result(typed: Self) -> Result<Val> {423 typed.map(T::into_untyped)?424 }425}426427/// Specialization428impl Typed for IBytes {429 const TYPE: &'static ComplexValType =430 &ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0)));431432 fn into_untyped(value: Self) -> Result<Val> {433 Ok(Val::Arr(ArrValue::bytes(value)))434 }435436 fn from_untyped(value: Val) -> Result<Self> {437 if let Val::Arr(ArrValue::Bytes(bytes)) = value {438 return Ok(bytes.0);439 }440 <Self as Typed>::TYPE.check(&value)?;441 match value {442 Val::Arr(a) => {443 let mut out = Vec::with_capacity(a.len());444 for e in a.iter() {445 let r = e?;446 out.push(u8::from_untyped(r)?);447 }448 Ok(out.as_slice().into())449 }450 _ => unreachable!(),451 }452 }453}454455pub struct M1;456impl Typed for M1 {457 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0));458459 fn into_untyped(_: Self) -> Result<Val> {460 Ok(Val::Num(-1.0))461 }462463 fn from_untyped(value: Val) -> Result<Self> {464 <Self as Typed>::TYPE.check(&value)?;465 Ok(Self)466 }467}468469macro_rules! decl_either {470 ($($name: ident, $($id: ident)*);*) => {$(471 #[derive(Clone)]472 pub enum $name<$($id),*> {473 $($id($id)),*474 }475 impl<$($id),*> Typed for $name<$($id),*>476 where477 $($id: Typed,)*478 {479 const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]);480481 fn into_untyped(value: Self) -> Result<Val> {482 match value {$(483 $name::$id(v) => $id::into_untyped(v)484 ),*}485 }486487 fn from_untyped(value: Val) -> Result<Self> {488 $(489 if $id::TYPE.check(&value).is_ok() {490 $id::from_untyped(value).map(Self::$id)491 } else492 )* {493 <Self as Typed>::TYPE.check(&value)?;494 unreachable!()495 }496 }497 }498 )*}499}500decl_either!(501 Either1, A;502 Either2, A B;503 Either3, A B C;504 Either4, A B C D;505 Either5, A B C D E;506 Either6, A B C D E F;507 Either7, A B C D E F G508);509#[macro_export]510macro_rules! Either {511 ($a:ty) => {Either1<$a>};512 ($a:ty, $b:ty) => {Either2<$a, $b>};513 ($a:ty, $b:ty, $c:ty) => {Either3<$a, $b, $c>};514 ($a:ty, $b:ty, $c:ty, $d:ty) => {Either4<$a, $b, $c, $d>};515 ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty) => {Either5<$a, $b, $c, $d, $e>};516 ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty) => {Either6<$a, $b, $c, $d, $e, $f>};517 ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty) => {Either7<$a, $b, $c, $d, $e, $f, $g>};518}519pub use Either;520521pub type MyType = Either![u32, f64, String];522523impl Typed for ArrValue {524 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);525526 fn into_untyped(value: Self) -> Result<Val> {527 Ok(Val::Arr(value))528 }529530 fn from_untyped(value: Val) -> Result<Self> {531 <Self as Typed>::TYPE.check(&value)?;532 match value {533 Val::Arr(a) => Ok(a),534 _ => unreachable!(),535 }536 }537}538539impl Typed for FuncVal {540 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);541542 fn into_untyped(value: Self) -> Result<Val> {543 Ok(Val::Func(value))544 }545546 fn from_untyped(value: Val) -> Result<Self> {547 <Self as Typed>::TYPE.check(&value)?;548 match value {549 Val::Func(a) => Ok(a),550 _ => unreachable!(),551 }552 }553}554555impl Typed for Cc<FuncDesc> {556 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);557558 fn into_untyped(value: Self) -> Result<Val> {559 Ok(Val::Func(FuncVal::Normal(value)))560 }561562 fn from_untyped(value: Val) -> Result<Self> {563 <Self as Typed>::TYPE.check(&value)?;564 match value {565 Val::Func(FuncVal::Normal(desc)) => Ok(desc),566 Val::Func(_) => throw!("expected normal function, not builtin"),567 _ => unreachable!(),568 }569 }570}571572impl Typed for ObjValue {573 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj);574575 fn into_untyped(value: Self) -> Result<Val> {576 Ok(Val::Obj(value))577 }578579 fn from_untyped(value: Val) -> Result<Self> {580 <Self as Typed>::TYPE.check(&value)?;581 match value {582 Val::Obj(a) => Ok(a),583 _ => unreachable!(),584 }585 }586}587588impl Typed for bool {589 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);590591 fn into_untyped(value: Self) -> Result<Val> {592 Ok(Val::Bool(value))593 }594595 fn from_untyped(value: Val) -> Result<Self> {596 <Self as Typed>::TYPE.check(&value)?;597 match value {598 Val::Bool(a) => Ok(a),599 _ => unreachable!(),600 }601 }602}603impl Typed for IndexableVal {604 const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[605 &ComplexValType::Simple(ValType::Arr),606 &ComplexValType::Simple(ValType::Str),607 ]);608609 fn into_untyped(value: Self) -> Result<Val> {610 match value {611 IndexableVal::Str(s) => Ok(Val::Str(StrValue::Flat(s))),612 IndexableVal::Arr(a) => Ok(Val::Arr(a)),613 }614 }615616 fn from_untyped(value: Val) -> Result<Self> {617 <Self as Typed>::TYPE.check(&value)?;618 value.into_indexable()619 }620}621622pub struct Null;623impl Typed for Null {624 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);625626 fn into_untyped(_: Self) -> Result<Val> {627 Ok(Val::Null)628 }629630 fn from_untyped(value: Val) -> Result<Self> {631 <Self as Typed>::TYPE.check(&value)?;632 Ok(Self)633 }634}635636pub struct NativeFn<D: NativeDesc>(D::Value);637impl<D: NativeDesc> Deref for NativeFn<D> {638 type Target = D::Value;639640 fn deref(&self) -> &Self::Target {641 &self.0642 }643}644impl<D: NativeDesc> Typed for NativeFn<D> {645 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);646647 fn into_untyped(_typed: Self) -> Result<Val> {648 throw!("can only convert functions from jsonnet to native")649 }650651 fn from_untyped(untyped: Val) -> Result<Self> {652 Ok(Self(653 untyped654 .as_func()655 .expect("shape is checked")656 .into_native::<D>(),657 ))658 }659}1use std::{collections::BTreeMap, marker::PhantomData, ops::Deref};23use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_interner::{IBytes, IStr};5pub use jrsonnet_macros::Typed;6use jrsonnet_types::{ComplexValType, ValType};78use crate::{9 arr::{ArrValue, BytesArray},10 error::Result,11 function::{native::NativeDesc, FuncDesc, FuncVal},12 throw,13 typed::CheckType,14 val::{IndexableVal, StrValue, ThunkMapper},15 ObjValue, ObjValueBuilder, Thunk, Val,16};1718#[derive(Trace)]19struct FromUntyped<K: Trace>(PhantomData<fn() -> K>);20impl<K> ThunkMapper<Val> for FromUntyped<K>21where22 K: Typed + Trace,23{24 type Output = K;2526 fn map(self, from: Val) -> Result<Self::Output> {27 K::from_untyped(from)28 }29}30impl<K: Trace> Default for FromUntyped<K> {31 fn default() -> Self {32 Self(PhantomData)33 }34}3536pub trait TypedObj: Typed {37 fn serialize(self, out: &mut ObjValueBuilder) -> Result<()>;38 fn parse(obj: &ObjValue) -> Result<Self>;39 fn into_object(self) -> Result<ObjValue> {40 let mut builder = ObjValueBuilder::new();41 self.serialize(&mut builder)?;42 Ok(builder.build())43 }44}4546pub trait Typed: Sized {47 const TYPE: &'static ComplexValType;48 fn into_untyped(typed: Self) -> Result<Val>;49 fn into_lazy_untyped(typed: Self) -> Thunk<Val> {50 Thunk::from(Self::into_untyped(typed))51 }52 fn from_untyped(untyped: Val) -> Result<Self>;53 fn from_lazy_untyped(lazy: Thunk<Val>) -> Result<Self> {54 Self::from_untyped(lazy.evaluate()?)55 }5657 // Whatever caller should use `into_lazy_untyped` instead of `into_untyped`58 fn provides_lazy() -> bool {59 false60 }6162 // Whatever caller should use `from_lazy_untyped` instead of `from_untyped` when possible63 fn wants_lazy() -> bool {64 false65 }6667 /// Hack to make builtins be able to return non-result values, and make macros able to convert those values to result68 /// This method returns identity in impl Typed for Result, and should not be overriden69 #[doc(hidden)]70 fn into_result(typed: Self) -> Result<Val> {71 let value = Self::into_untyped(typed)?;72 Ok(value)73 }74}7576impl<T> Typed for Thunk<T>77where78 T: Typed + Trace + Clone,79{80 const TYPE: &'static ComplexValType = &ComplexValType::Lazy(T::TYPE);8182 fn into_untyped(typed: Self) -> Result<Val> {83 T::into_untyped(typed.evaluate()?)84 }8586 fn from_untyped(untyped: Val) -> Result<Self> {87 Self::from_lazy_untyped(Thunk::evaluated(untyped))88 }8990 fn provides_lazy() -> bool {91 true92 }9394 fn into_lazy_untyped(inner: Self) -> Thunk<Val> {95 #[derive(Trace)]96 struct IntoUntyped<K: Trace>(PhantomData<fn() -> K>);97 impl<K> ThunkMapper<K> for IntoUntyped<K>98 where99 K: Typed + Trace,100 {101 type Output = Val;102103 fn map(self, from: K) -> Result<Self::Output> {104 K::into_untyped(from)105 }106 }107 impl<K: Trace> Default for IntoUntyped<K> {108 fn default() -> Self {109 Self(PhantomData)110 }111 }112 inner.map(<IntoUntyped<T>>::default())113 }114115 fn wants_lazy() -> bool {116 true117 }118119 fn from_lazy_untyped(inner: Thunk<Val>) -> Result<Self> {120 Ok(inner.map(<FromUntyped<T>>::default()))121 }122}123124const MAX_SAFE_INTEGER: f64 = ((1u64 << (f64::MANTISSA_DIGITS + 1)) - 1) as f64;125126macro_rules! impl_int {127 ($($ty:ty)*) => {$(128 impl Typed for $ty {129 const TYPE: &'static ComplexValType =130 &ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64));131 fn from_untyped(value: Val) -> Result<Self> {132 <Self as Typed>::TYPE.check(&value)?;133 match value {134 Val::Num(n) => {135 #[allow(clippy::float_cmp)]136 if n.trunc() != n {137 throw!(138 "cannot convert number with fractional part to {}",139 stringify!($ty)140 )141 }142 Ok(n as Self)143 }144 _ => unreachable!(),145 }146 }147 fn into_untyped(value: Self) -> Result<Val> {148 Ok(Val::Num(value as f64))149 }150 }151 )*};152}153154impl_int!(i8 u8 i16 u16 i32 u32);155156macro_rules! impl_bounded_int {157 ($($name:ident = $ty:ty)*) => {$(158 #[derive(Clone, Copy)]159 pub struct $name<const MIN: $ty, const MAX: $ty>($ty);160 impl<const MIN: $ty, const MAX: $ty> $name<MIN, MAX> {161 pub const fn new(value: $ty) -> Option<$name<MIN, MAX>> {162 if value >= MIN && value <= MAX {163 Some(Self(value))164 } else {165 None166 }167 }168 pub const fn value(self) -> $ty {169 self.0170 }171 }172 impl<const MIN: $ty, const MAX: $ty> Deref for $name<MIN, MAX> {173 type Target = $ty;174 fn deref(&self) -> &Self::Target {175 &self.0176 }177 }178179 impl<const MIN: $ty, const MAX: $ty> Typed for $name<MIN, MAX> {180 const TYPE: &'static ComplexValType =181 &ComplexValType::BoundedNumber(182 Some(MIN as f64),183 Some(MAX as f64),184 );185186 fn from_untyped(value: Val) -> Result<Self> {187 <Self as Typed>::TYPE.check(&value)?;188 match value {189 Val::Num(n) => {190 #[allow(clippy::float_cmp)]191 if n.trunc() != n {192 throw!(193 "cannot convert number with fractional part to {}",194 stringify!($ty)195 )196 }197 Ok(Self(n as $ty))198 }199 _ => unreachable!(),200 }201 }202203 fn into_untyped(value: Self) -> Result<Val> {204 Ok(Val::Num(value.0 as f64))205 }206 }207 )*};208}209210impl_bounded_int!(211 BoundedI8 = i8212 BoundedI16 = i16213 BoundedI32 = i32214 BoundedI64 = i64215 BoundedUsize = usize216);217218impl Typed for f64 {219 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);220221 fn into_untyped(value: Self) -> Result<Val> {222 Ok(Val::Num(value))223 }224225 fn from_untyped(value: Val) -> Result<Self> {226 <Self as Typed>::TYPE.check(&value)?;227 match value {228 Val::Num(n) => Ok(n),229 _ => unreachable!(),230 }231 }232}233234pub struct PositiveF64(pub f64);235impl Typed for PositiveF64 {236 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None);237238 fn into_untyped(value: Self) -> Result<Val> {239 Ok(Val::Num(value.0))240 }241242 fn from_untyped(value: Val) -> Result<Self> {243 <Self as Typed>::TYPE.check(&value)?;244 match value {245 Val::Num(n) => Ok(Self(n)),246 _ => unreachable!(),247 }248 }249}250impl Typed for usize {251 const TYPE: &'static ComplexValType =252 &ComplexValType::BoundedNumber(Some(0.0), Some(MAX_SAFE_INTEGER));253254 fn into_untyped(value: Self) -> Result<Val> {255 if value > MAX_SAFE_INTEGER as Self {256 throw!("number is too large")257 }258 Ok(Val::Num(value as f64))259 }260261 fn from_untyped(value: Val) -> Result<Self> {262 <Self as Typed>::TYPE.check(&value)?;263 match value {264 Val::Num(n) => {265 #[allow(clippy::float_cmp)]266 if n.trunc() != n {267 throw!("cannot convert number with fractional part to usize")268 }269 Ok(n as Self)270 }271 _ => unreachable!(),272 }273 }274}275276impl Typed for IStr {277 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);278279 fn into_untyped(value: Self) -> Result<Val> {280 Ok(Val::Str(StrValue::Flat(value)))281 }282283 fn from_untyped(value: Val) -> Result<Self> {284 <Self as Typed>::TYPE.check(&value)?;285 match value {286 Val::Str(s) => Ok(s.into_flat()),287 _ => unreachable!(),288 }289 }290}291292impl Typed for String {293 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);294295 fn into_untyped(value: Self) -> Result<Val> {296 Ok(Val::Str(StrValue::Flat(value.into())))297 }298299 fn from_untyped(value: Val) -> Result<Self> {300 <Self as Typed>::TYPE.check(&value)?;301 match value {302 Val::Str(s) => Ok(s.to_string()),303 _ => unreachable!(),304 }305 }306}307308impl Typed for char {309 const TYPE: &'static ComplexValType = &ComplexValType::Char;310311 fn into_untyped(value: Self) -> Result<Val> {312 Ok(Val::Str(StrValue::Flat(value.to_string().into())))313 }314315 fn from_untyped(value: Val) -> Result<Self> {316 <Self as Typed>::TYPE.check(&value)?;317 match value {318 Val::Str(s) => Ok(s.into_flat().chars().next().unwrap()),319 _ => unreachable!(),320 }321 }322}323324impl<T> Typed for Vec<T>325where326 T: Typed,327{328 const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);329330 fn into_untyped(value: Self) -> Result<Val> {331 Ok(Val::Arr(332 value333 .into_iter()334 .map(T::into_untyped)335 .collect::<Result<ArrValue>>()?,336 ))337 }338339 fn from_untyped(value: Val) -> Result<Self> {340 let Val::Arr(a) = value else {341 <Self as Typed>::TYPE.check(&value)?;342 unreachable!("typecheck should fail")343 };344 a.iter()345 .map(|r| r.and_then(T::from_untyped))346 .collect::<Result<Vec<T>>>()347 }348}349350impl<K: Typed + Ord, V: Typed> Typed for BTreeMap<K, V> {351 const TYPE: &'static ComplexValType = &ComplexValType::AttrsOf(V::TYPE);352353 fn into_untyped(typed: Self) -> Result<Val> {354 let mut out = ObjValueBuilder::with_capacity(typed.len());355 for (k, v) in typed {356 let Some(key) = K::into_untyped(k)?.as_str() else {357 throw!("map key should serialize to string");358 };359 let value = V::into_untyped(v)?;360 out.member(key).value_unchecked(value);361 }362 Ok(Val::Obj(out.build()))363 }364365 fn from_untyped(value: Val) -> Result<Self> {366 Self::TYPE.check(&value)?;367 let obj = value.as_obj().expect("typecheck should fail");368369 let mut out = BTreeMap::new();370 if V::wants_lazy() {371 for key in obj.fields_ex(372 false,373 #[cfg(feature = "exp-preserve-order")]374 false,375 ) {376 let value = obj.get_lazy(key.clone()).expect("field exists");377 let value = V::from_lazy_untyped(value)?;378 let key = K::from_untyped(Val::Str(key.into()))?;379 let _ = out.insert(key, value);380 }381 } else {382 for (key, value) in obj.iter(383 #[cfg(feature = "exp-preserve-order")]384 false,385 ) {386 let key = K::from_untyped(Val::Str(key.into()))?;387 let value = V::from_untyped(value?)?;388 let _ = out.insert(key, value);389 }390 }391 Ok(out)392 }393}394395impl Typed for Val {396 const TYPE: &'static ComplexValType = &ComplexValType::Any;397398 fn into_untyped(typed: Self) -> Result<Val> {399 Ok(typed)400 }401 fn from_untyped(untyped: Val) -> Result<Self> {402 Ok(untyped)403 }404}405406// Hack407#[doc(hidden)]408impl<T> Typed for Result<T>409where410 T: Typed,411{412 const TYPE: &'static ComplexValType = &ComplexValType::Any;413414 fn into_untyped(_typed: Self) -> Result<Val> {415 panic!("do not use this conversion")416 }417418 fn from_untyped(_untyped: Val) -> Result<Self> {419 panic!("do not use this conversion")420 }421422 fn into_result(typed: Self) -> Result<Val> {423 typed.map(T::into_untyped)?424 }425}426427/// Specialization428impl Typed for IBytes {429 const TYPE: &'static ComplexValType =430 &ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0)));431432 fn into_untyped(value: Self) -> Result<Val> {433 Ok(Val::Arr(ArrValue::bytes(value)))434 }435436 fn from_untyped(value: Val) -> Result<Self> {437 match &value {438 Val::Arr(a) => {439 if let Some(bytes) = a.as_any().downcast_ref::<BytesArray>() {440 return Ok(bytes.0.as_slice().into());441 };442 <Self as Typed>::TYPE.check(&value)?;443 // Any::downcast_ref::<ByteArray>(&a);444 let mut out = Vec::with_capacity(a.len());445 for e in a.iter() {446 let r = e?;447 out.push(u8::from_untyped(r)?);448 }449 Ok(out.as_slice().into())450 }451 _ => {452 <Self as Typed>::TYPE.check(&value)?;453 unreachable!()454 }455 }456 }457}458459pub struct M1;460impl Typed for M1 {461 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0));462463 fn into_untyped(_: Self) -> Result<Val> {464 Ok(Val::Num(-1.0))465 }466467 fn from_untyped(value: Val) -> Result<Self> {468 <Self as Typed>::TYPE.check(&value)?;469 Ok(Self)470 }471}472473macro_rules! decl_either {474 ($($name: ident, $($id: ident)*);*) => {$(475 #[derive(Clone)]476 pub enum $name<$($id),*> {477 $($id($id)),*478 }479 impl<$($id),*> Typed for $name<$($id),*>480 where481 $($id: Typed,)*482 {483 const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]);484485 fn into_untyped(value: Self) -> Result<Val> {486 match value {$(487 $name::$id(v) => $id::into_untyped(v)488 ),*}489 }490491 fn from_untyped(value: Val) -> Result<Self> {492 $(493 if $id::TYPE.check(&value).is_ok() {494 $id::from_untyped(value).map(Self::$id)495 } else496 )* {497 <Self as Typed>::TYPE.check(&value)?;498 unreachable!()499 }500 }501 }502 )*}503}504decl_either!(505 Either1, A;506 Either2, A B;507 Either3, A B C;508 Either4, A B C D;509 Either5, A B C D E;510 Either6, A B C D E F;511 Either7, A B C D E F G512);513#[macro_export]514macro_rules! Either {515 ($a:ty) => {Either1<$a>};516 ($a:ty, $b:ty) => {Either2<$a, $b>};517 ($a:ty, $b:ty, $c:ty) => {Either3<$a, $b, $c>};518 ($a:ty, $b:ty, $c:ty, $d:ty) => {Either4<$a, $b, $c, $d>};519 ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty) => {Either5<$a, $b, $c, $d, $e>};520 ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty) => {Either6<$a, $b, $c, $d, $e, $f>};521 ($a:ty, $b:ty, $c:ty, $d:ty, $e:ty, $f:ty, $g:ty) => {Either7<$a, $b, $c, $d, $e, $f, $g>};522}523pub use Either;524525pub type MyType = Either![u32, f64, String];526527impl Typed for ArrValue {528 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);529530 fn into_untyped(value: Self) -> Result<Val> {531 Ok(Val::Arr(value))532 }533534 fn from_untyped(value: Val) -> Result<Self> {535 <Self as Typed>::TYPE.check(&value)?;536 match value {537 Val::Arr(a) => Ok(a),538 _ => unreachable!(),539 }540 }541}542543impl Typed for FuncVal {544 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);545546 fn into_untyped(value: Self) -> Result<Val> {547 Ok(Val::Func(value))548 }549550 fn from_untyped(value: Val) -> Result<Self> {551 <Self as Typed>::TYPE.check(&value)?;552 match value {553 Val::Func(a) => Ok(a),554 _ => unreachable!(),555 }556 }557}558559impl Typed for Cc<FuncDesc> {560 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);561562 fn into_untyped(value: Self) -> Result<Val> {563 Ok(Val::Func(FuncVal::Normal(value)))564 }565566 fn from_untyped(value: Val) -> Result<Self> {567 <Self as Typed>::TYPE.check(&value)?;568 match value {569 Val::Func(FuncVal::Normal(desc)) => Ok(desc),570 Val::Func(_) => throw!("expected normal function, not builtin"),571 _ => unreachable!(),572 }573 }574}575576impl Typed for ObjValue {577 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj);578579 fn into_untyped(value: Self) -> Result<Val> {580 Ok(Val::Obj(value))581 }582583 fn from_untyped(value: Val) -> Result<Self> {584 <Self as Typed>::TYPE.check(&value)?;585 match value {586 Val::Obj(a) => Ok(a),587 _ => unreachable!(),588 }589 }590}591592impl Typed for bool {593 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);594595 fn into_untyped(value: Self) -> Result<Val> {596 Ok(Val::Bool(value))597 }598599 fn from_untyped(value: Val) -> Result<Self> {600 <Self as Typed>::TYPE.check(&value)?;601 match value {602 Val::Bool(a) => Ok(a),603 _ => unreachable!(),604 }605 }606}607impl Typed for IndexableVal {608 const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[609 &ComplexValType::Simple(ValType::Arr),610 &ComplexValType::Simple(ValType::Str),611 ]);612613 fn into_untyped(value: Self) -> Result<Val> {614 match value {615 IndexableVal::Str(s) => Ok(Val::Str(StrValue::Flat(s))),616 IndexableVal::Arr(a) => Ok(Val::Arr(a)),617 }618 }619620 fn from_untyped(value: Val) -> Result<Self> {621 <Self as Typed>::TYPE.check(&value)?;622 value.into_indexable()623 }624}625626pub struct Null;627impl Typed for Null {628 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);629630 fn into_untyped(_: Self) -> Result<Val> {631 Ok(Val::Null)632 }633634 fn from_untyped(value: Val) -> Result<Self> {635 <Self as Typed>::TYPE.check(&value)?;636 Ok(Self)637 }638}639640pub struct NativeFn<D: NativeDesc>(D::Value);641impl<D: NativeDesc> Deref for NativeFn<D> {642 type Target = D::Value;643644 fn deref(&self) -> &Self::Target {645 &self.0646 }647}648impl<D: NativeDesc> Typed for NativeFn<D> {649 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);650651 fn into_untyped(_typed: Self) -> Result<Val> {652 throw!("can only convert functions from jsonnet to native")653 }654655 fn from_untyped(untyped: Val) -> Result<Self> {656 Ok(Self(657 untyped658 .as_func()659 .expect("shape is checked")660 .into_native::<D>(),661 ))662 }663}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))
}
}