--- a/crates/jrsonnet-evaluator/src/arr/mod.rs +++ b/crates/jrsonnet-evaluator/src/arr/mod.rs @@ -26,16 +26,22 @@ /// This kind of arrays is generated by `std.range(start, end)` call, and used for loops. Range(RangeArray), /// Sliced array view. - Slice(Box), + Slice(Cc), /// Reversed array view. /// Returned by `std.reverse(other)` call - Reverse(Box), + Reverse(Cc), /// Returned by `std.map` call Mapped(MappedArray), /// Returned by `std.repeat` call Repeated(RepeatedArray), } +pub trait ArrayLikeIter: Iterator + DoubleEndedIterator + ExactSizeIterator {} +impl ArrayLikeIter for I where + I: Iterator + DoubleEndedIterator + ExactSizeIterator +{ +} + impl ArrValue { pub fn empty() -> Self { Self::Range(RangeArray::empty()) @@ -123,7 +129,7 @@ return None; } - Some(Self::Slice(Box::new(SliceArray { + Some(Self::Slice(Cc::new(SliceArray { inner: self, from: from as u32, to: to as u32, @@ -160,24 +166,26 @@ pass!(self.get_lazy(index)) } - /// Evaluate all array elements, returning new array. - pub fn evaluatedcc(&self) -> Result>> { - self.evaluated().map(Cc::new) - } - pub fn evaluated(&self) -> Result> { - pass!(self.evaluated()) - } - - /// Iterate over elements, evaluating them. + #[cfg(feature = "nightly")] pub fn iter(&self) -> UnknownArrayIter<'_> { pass_iter_call!(self.iter => UnknownArrayIter) } + #[cfg(not(feature = "nightly"))] + pub fn iter(&self) -> impl ArrayLikeIter> + '_ { + (0..self.len()).map(|i| self.get(i).transpose().expect("length checked")) + } /// Iterate over elements, returning lazy values. + #[cfg(feature = "nightly")] pub fn iter_lazy(&self) -> UnknownArrayIterLazy<'_> { pass_iter_call!(self.iter_lazy => UnknownArrayIterLazy) } + #[cfg(not(feature = "nightly"))] + pub fn iter_lazy(&self) -> impl ArrayLikeIter> + '_ { + (0..self.len()).map(|i| self.get_lazy(i).expect("length checked")) + } + #[cfg(feature = "nightly")] pub fn iter_cheap(&self) -> Option> { macro_rules! question { ($v:expr) => { @@ -187,10 +195,19 @@ Some(pass_iter_call!(self.iter_cheap in question => UnknownArrayIterCheap)) } + #[cfg(not(feature = "nightly"))] + pub fn iter_cheap(&self) -> Option + '_> { + if self.is_cheap() { + Some((0..self.len()).map(|i| self.get_cheap(i).expect("length and is_cheap checked"))) + } else { + None + } + } + /// Return a reversed view on current array. #[must_use] pub fn reversed(self) -> Self { - Self::Reverse(Box::new(ReverseArray(self))) + Self::Reverse(Cc::new(ReverseArray(self))) } pub fn ptr_eq(a: &Self, b: &Self) -> bool { --- a/crates/jrsonnet-evaluator/src/arr/spec.rs +++ b/crates/jrsonnet-evaluator/src/arr/spec.rs @@ -1,26 +1,28 @@ -use std::{ - cell::RefCell, - iter::{self, Rev}, - mem::replace, -}; +//! Those implementations are a bit sketchy, as this is mostly performance experiments +//! of not yet finished nightly rust features + +use std::{cell::RefCell, iter, mem::replace}; use jrsonnet_gcmodule::{Cc, Trace}; use jrsonnet_interner::IBytes; use jrsonnet_parser::LocExpr; -use super::ArrValue; +use super::{ArrValue, ArrayLikeIter}; use crate::{ error::ErrorKind::InfiniteRecursionDetected, evaluate, function::FuncVal, tb, typed::Any, val::ThunkValue, Context, Error, Result, Thunk, Val, }; -pub trait ArrayLike { +pub trait ArrayLike: Sized + Into { + #[cfg(feature = "nightly")] type Iter<'t> where Self: 't; + #[cfg(feature = "nightly")] type IterLazy<'t> where Self: 't; + #[cfg(feature = "nightly")] type IterCheap<'t> where Self: 't; @@ -32,11 +34,17 @@ fn get(&self, index: usize) -> Result>; fn get_lazy(&self, index: usize) -> Option>; fn get_cheap(&self, index: usize) -> Option; - fn evaluated(&self) -> Result>; + #[cfg(feature = "nightly")] #[allow(clippy::iter_not_returning_iterator)] fn iter(&self) -> Self::Iter<'_>; + #[cfg(feature = "nightly")] fn iter_lazy(&self) -> Self::IterLazy<'_>; + #[cfg(feature = "nightly")] fn iter_cheap(&self) -> Option>; + + fn reverse(self) -> ArrValue { + ArrValue::Reverse(Cc::new(ReverseArray(self.into()))) + } } #[derive(Debug, Clone, Trace)] @@ -46,14 +54,49 @@ pub(crate) to: u32, pub(crate) step: u32, } + +impl SliceArray { + #[cfg(not(feature = "nightly"))] + fn iter(&self) -> impl Iterator> + '_ { + self.inner + .iter() + .skip(self.from as usize) + .take((self.to - self.from) as usize) + .step_by(self.step as usize) + } + + #[cfg(not(feature = "nightly"))] + fn iter_lazy(&self) -> impl Iterator> + '_ { + self.inner + .iter_lazy() + .skip(self.from as usize) + .take((self.to - self.from) as usize) + .step_by(self.step as usize) + } + + #[cfg(not(feature = "nightly"))] + fn iter_cheap(&self) -> Option + '_> { + Some( + self.inner + .iter_cheap()? + .skip(self.from as usize) + .take((self.to - self.from) as usize) + .step_by(self.step as usize), + ) + } +} +#[cfg(feature = "nightly")] type SliceArrayIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] type SliceArrayLazyIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] type SliceArrayCheapIter<'t> = impl DoubleEndedIterator + ExactSizeIterator + 't; impl ArrayLike for SliceArray { + #[cfg(feature = "nightly")] type Iter<'t> = SliceArrayIter<'t>; - + #[cfg(feature = "nightly")] type IterLazy<'t> = SliceArrayLazyIter<'t>; - + #[cfg(feature = "nightly")] type IterCheap<'t> = SliceArrayCheapIter<'t>; fn len(&self) -> usize { @@ -75,10 +118,7 @@ self.iter_cheap()?.nth(index) } - fn evaluated(&self) -> Result> { - self.iter().collect() - } - + #[cfg(feature = "nightly")] fn iter(&self) -> SliceArrayIter<'_> { self.inner .iter() @@ -87,6 +127,7 @@ .step_by(self.step as usize) } + #[cfg(feature = "nightly")] fn iter_lazy(&self) -> SliceArrayLazyIter<'_> { self.inner .iter_lazy() @@ -95,6 +136,7 @@ .step_by(self.step as usize) } + #[cfg(feature = "nightly")] fn iter_cheap(&self) -> Option> { Some( self.inner @@ -105,17 +147,26 @@ ) } } +impl From for ArrValue { + fn from(value: SliceArray) -> Self { + Self::Slice(Cc::new(value)) + } +} #[derive(Trace, Debug, Clone)] pub struct BytesArray(pub IBytes); +#[cfg(feature = "nightly")] type BytesArrayIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] type BytesArrayLazyIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] type BytesArrayCheapIter<'t> = impl DoubleEndedIterator + ExactSizeIterator + 't; impl ArrayLike for BytesArray { + #[cfg(feature = "nightly")] type Iter<'t> = BytesArrayIter<'t>; - + #[cfg(feature = "nightly")] type IterLazy<'t> = BytesArrayLazyIter<'t>; - + #[cfg(feature = "nightly")] type IterCheap<'t> = BytesArrayCheapIter<'t>; fn len(&self) -> usize { @@ -134,24 +185,28 @@ self.0.get(index).map(|v| Val::Num(f64::from(*v))) } - fn evaluated(&self) -> Result> { - self.iter().collect() - } - + #[cfg(feature = "nightly")] fn iter(&self) -> BytesArrayIter<'_> { self.0.iter().map(|v| Ok(Val::Num(f64::from(*v)))) } + #[cfg(feature = "nightly")] fn iter_lazy(&self) -> BytesArrayLazyIter<'_> { self.0 .iter() .map(|v| Thunk::evaluated(Val::Num(f64::from(*v)))) } + #[cfg(feature = "nightly")] fn iter_cheap(&self) -> Option> { Some(self.0.iter().map(|v| Val::Num(f64::from(*v)))) } } +impl From for ArrValue { + fn from(value: BytesArray) -> Self { + ArrValue::Bytes(value) + } +} #[derive(Debug, Trace, Clone)] enum ArrayThunk { @@ -168,9 +223,6 @@ } #[derive(Debug, Trace, Clone)] pub struct ExprArray(pub Cc); -type ExprArrayIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; -type ExprArrayLazyIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; -type ExprArrayCheapIter<'t> = iter::Empty; impl ExprArray { pub fn new(ctx: Context, items: impl IntoIterator) -> Self { Self(Cc::new(ExprArrayInner { @@ -179,11 +231,18 @@ })) } } +#[cfg(feature = "nightly")] +type ExprArrayIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] +type ExprArrayLazyIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] +type ExprArrayCheapIter<'t> = iter::Empty; impl ArrayLike for ExprArray { + #[cfg(feature = "nightly")] type Iter<'t> = ExprArrayIter<'t>; - + #[cfg(feature = "nightly")] type IterLazy<'t> = ExprArrayLazyIter<'t>; - + #[cfg(feature = "nightly")] type IterCheap<'t> = ExprArrayCheapIter<'t>; fn len(&self) -> usize { @@ -250,18 +309,22 @@ None } + #[cfg(feature = "nightly")] fn iter(&self) -> ExprArrayIter<'_> { (0..self.len()).map(|i| self.get(i).transpose().expect("index checked")) } + #[cfg(feature = "nightly")] fn iter_lazy(&self) -> ExprArrayLazyIter<'_> { (0..self.len()).map(|i| self.get_lazy(i).expect("index checked")) } - fn iter_cheap(&self) -> Option> { + #[cfg(feature = "nightly")] + fn iter_cheap(&self) -> Option> { None } - - fn evaluated(&self) -> Result> { - self.iter().collect() +} +impl From for ArrValue { + fn from(value: ExprArray) -> Self { + Self::Expr(value) } } @@ -272,9 +335,14 @@ split: usize, len: usize, } -type ExtendedArrayIter<'t> = impl DoubleEndedIterator> + 't; -type ExtendedArrayLazyIter<'t> = impl DoubleEndedIterator> + 't; -type ExtendedArrayCheapIter<'t> = impl DoubleEndedIterator + 't; +#[cfg(feature = "nightly")] + +type ExtendedArrayIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] +type ExtendedArrayLazyIter<'t> = + impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] +type ExtendedArrayCheapIter<'t> = impl DoubleEndedIterator + ExactSizeIterator + 't; impl ExtendedArray { pub fn new(a: ArrValue, b: ArrValue) -> Self { let a_len = a.len(); @@ -287,11 +355,49 @@ } } } + +struct WithExactSize(I, usize); +impl Iterator for WithExactSize +where + I: Iterator, +{ + type Item = T; + + fn next(&mut self) -> Option { + self.0.next() + } + fn nth(&mut self, n: usize) -> Option { + self.0.nth(n) + } + fn size_hint(&self) -> (usize, Option) { + (self.1, Some(self.1)) + } +} +impl DoubleEndedIterator for WithExactSize +where + I: DoubleEndedIterator, +{ + fn next_back(&mut self) -> Option { + self.0.next_back() + } + fn nth_back(&mut self, n: usize) -> Option { + self.0.nth_back(n) + } +} +impl ExactSizeIterator for WithExactSize +where + I: Iterator, +{ + fn len(&self) -> usize { + self.1 + } +} impl ArrayLike for ExtendedArray { + #[cfg(feature = "nightly")] type Iter<'t> = ExtendedArrayIter<'t>; - + #[cfg(feature = "nightly")] type IterLazy<'t> = ExtendedArrayLazyIter<'t>; - + #[cfg(feature = "nightly")] type IterCheap<'t> = ExtendedArrayCheapIter<'t>; fn get(&self, index: usize) -> Result> { @@ -321,35 +427,43 @@ } } - fn evaluated(&self) -> Result> { - let mut out = self.a.evaluated()?; - out.extend(self.b.evaluated()?.into_iter()); - Ok(out) - } - + #[cfg(feature = "nightly")] fn iter(&self) -> ExtendedArrayIter<'_> { - self.a.iter().chain(self.b.iter()) + WithExactSize(self.a.iter().chain(self.b.iter()), self.len) } + #[cfg(feature = "nightly")] fn iter_lazy(&self) -> ExtendedArrayLazyIter<'_> { - self.a.iter_lazy().chain(self.b.iter_lazy()) + WithExactSize(self.a.iter_lazy().chain(self.b.iter_lazy()), self.len) } + #[cfg(feature = "nightly")] fn iter_cheap(&self) -> Option> { let a = self.a.iter_cheap()?; let b = self.b.iter_cheap()?; - Some(a.chain(b)) + Some(WithExactSize(a.chain(b), self.len)) } } +impl From for ArrValue { + fn from(value: ExtendedArray) -> Self { + Self::Extended(Cc::new(value)) + } +} #[derive(Trace, Debug, Clone)] pub struct LazyArray(pub Cc>>); +#[cfg(feature = "nightly")] type LazyArrayIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] type LazyArrayLazyIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] type LazyArrayCheapIter<'t> = iter::Empty; impl ArrayLike for LazyArray { + #[cfg(feature = "nightly")] type Iter<'t> = LazyArrayIter<'t>; + #[cfg(feature = "nightly")] type IterLazy<'t> = LazyArrayLazyIter<'t>; + #[cfg(feature = "nightly")] type IterCheap<'t> = LazyArrayCheapIter<'t>; fn len(&self) -> usize { @@ -367,34 +481,41 @@ fn get_lazy(&self, index: usize) -> Option> { self.0.get(index).cloned() } - fn evaluated(&self) -> Result> { - let mut out = Vec::with_capacity(self.len()); - for i in self.0.iter() { - out.push(i.evaluate()?); - } - Ok(out) - } + #[cfg(feature = "nightly")] fn iter(&self) -> LazyArrayIter<'_> { self.0.iter().map(Thunk::evaluate) } + #[cfg(feature = "nightly")] fn iter_lazy(&self) -> LazyArrayLazyIter<'_> { self.0.iter().cloned() } + #[cfg(feature = "nightly")] fn iter_cheap(&self) -> Option> { None } } +impl From for ArrValue { + fn from(value: LazyArray) -> Self { + Self::Lazy(value) + } +} #[derive(Trace, Debug, Clone)] pub struct EagerArray(pub Cc>); +#[cfg(feature = "nightly")] type EagerArrayIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] type EagerArrayLazyIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] type EagerArrayCheapIter<'t> = impl DoubleEndedIterator + ExactSizeIterator + 't; impl ArrayLike for EagerArray { + #[cfg(feature = "nightly")] type Iter<'t> = EagerArrayIter<'t>; + #[cfg(feature = "nightly")] type IterLazy<'t> = EagerArrayLazyIter<'t>; + #[cfg(feature = "nightly")] type IterCheap<'t> = EagerArrayCheapIter<'t>; fn len(&self) -> usize { @@ -413,105 +534,33 @@ self.0.get(index).cloned() } - fn evaluated(&self) -> Result> { - Ok((*self.0).clone()) - } - + #[cfg(feature = "nightly")] fn iter(&self) -> EagerArrayIter<'_> { self.0.iter().cloned().map(Ok) } + #[cfg(feature = "nightly")] fn iter_lazy(&self) -> EagerArrayLazyIter<'_> { self.0.iter().cloned().map(Thunk::evaluated) } + #[cfg(feature = "nightly")] fn iter_cheap(&self) -> Option> { Some(self.0.iter().cloned()) } } +impl From for ArrValue { + fn from(value: EagerArray) -> Self { + Self::Eager(value) + } +} /// Inclusive range type #[derive(Debug, Trace, Clone, PartialEq, Eq)] pub struct RangeArray { start: i32, end: i32, -} -struct RangeIter { - start: i32, - end: i32, -} -impl RangeIter { - fn finished(&self) -> bool { - self.end < self.start - } - fn finish(&mut self) { - self.start = 0; - self.end = -1; - } } -impl Iterator for RangeIter { - type Item = i32; - - fn next(&mut self) -> Option { - if self.finished() { - return None; - } - let v = self.start; - if v == self.end { - self.finish(); - } else { - self.start = v + 1; - } - Some(v) - } - fn nth(&mut self, n: usize) -> Option { - let v = (self.start as usize) + n; - if v > self.end as usize { - self.finish(); - None - } else { - self.start = v as i32; - self.next() - } - } - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } -} -impl DoubleEndedIterator for RangeIter { - fn next_back(&mut self) -> Option { - if self.finished() { - return None; - } - let v = self.end; - if v == self.start { - self.finish(); - } else { - self.end = v - 1; - } - Some(v) - } - fn nth_back(&mut self, n: usize) -> Option { - let v = (self.end as usize) - n; - if v < self.start as usize { - self.finish(); - None - } else { - self.end = v as i32; - self.next_back() - } - } -} -impl ExactSizeIterator for RangeIter { - fn len(&self) -> usize { - if self.finished() { - 0 - } else { - (self.end as isize - self.start as isize + 1) as usize - } - } -} impl RangeArray { pub fn empty() -> Self { Self::new_exclusive(0, 0) @@ -523,29 +572,37 @@ pub fn new_inclusive(start: i32, end: i32) -> Self { Self { start, end } } - fn range(&self) -> RangeIter { - RangeIter { - start: self.start, - end: self.end, - } + fn range(&self) -> impl Iterator + ExactSizeIterator + DoubleEndedIterator { + WithExactSize( + self.start..=self.end, + (self.end as usize) + .wrapping_sub(self.start as usize) + .wrapping_add(1), + ) } } +#[cfg(feature = "nightly")] type RangeArrayIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] type RangeArrayLazyIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] type RangeArrayCheapIter<'t> = impl DoubleEndedIterator + ExactSizeIterator + 't; impl ArrayLike for RangeArray { + #[cfg(feature = "nightly")] type Iter<'t> = RangeArrayIter<'t>; + #[cfg(feature = "nightly")] type IterLazy<'t> = RangeArrayLazyIter<'t>; + #[cfg(feature = "nightly")] type IterCheap<'t> = RangeArrayCheapIter<'t>; fn len(&self) -> usize { self.range().len() } fn is_empty(&self) -> bool { - self.range().finished() + self.range().len() == 0 } fn get(&self, index: usize) -> Result> { @@ -560,32 +617,39 @@ self.range().nth(index).map(|i| Val::Num(f64::from(i))) } - fn evaluated(&self) -> Result> { - Ok(self.range().map(|i| Val::Num(f64::from(i))).collect()) - } - + #[cfg(feature = "nightly")] fn iter(&self) -> RangeArrayIter<'_> { self.range().map(|i| Ok(Val::Num(f64::from(i)))) } + #[cfg(feature = "nightly")] fn iter_lazy(&self) -> RangeArrayLazyIter<'_> { self.range() .map(|i| Thunk::evaluated(Val::Num(f64::from(i)))) } + #[cfg(feature = "nightly")] fn iter_cheap(&self) -> Option> { Some(self.range().map(|i| Val::Num(f64::from(i)))) } } +impl From for ArrValue { + fn from(value: RangeArray) -> Self { + Self::Range(value) + } +} #[derive(Debug, Trace, Clone)] pub struct ReverseArray(pub ArrValue); impl ArrayLike for ReverseArray { - type Iter<'t> = Rev>; + #[cfg(feature = "nightly")] + type Iter<'t> = iter::Rev>; - type IterLazy<'t> = Rev>; + #[cfg(feature = "nightly")] + type IterLazy<'t> = iter::Rev>; - type IterCheap<'t> = Rev>; + #[cfg(feature = "nightly")] + type IterCheap<'t> = iter::Rev>; fn len(&self) -> usize { self.0.len() @@ -603,24 +667,29 @@ self.0.get_cheap(self.0.len() - index - 1) } - fn evaluated(&self) -> Result> { - let mut v = self.0.evaluated()?; - v.reverse(); - Ok(v) - } - - fn iter(&self) -> Rev> { + #[cfg(feature = "nightly")] + fn iter(&self) -> iter::Rev> { self.0.iter().rev() } - fn iter_lazy(&self) -> Rev> { + #[cfg(feature = "nightly")] + fn iter_lazy(&self) -> iter::Rev> { self.0.iter_lazy().rev() } - fn iter_cheap(&self) -> Option>> { + #[cfg(feature = "nightly")] + fn iter_cheap(&self) -> Option>> { Some(self.0.iter_cheap()?.rev()) } + fn reverse(self) -> ArrValue { + self.0 + } } +impl From for ArrValue { + fn from(value: ReverseArray) -> Self { + Self::Reverse(Cc::new(value)) + } +} #[derive(Trace, Debug)] pub struct MappedArrayInner { @@ -640,12 +709,18 @@ })) } } +#[cfg(feature = "nightly")] type MappedArrayIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] type MappedArrayLazyIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] type MappedArrayCheapIter<'t> = iter::Empty; impl ArrayLike for MappedArray { + #[cfg(feature = "nightly")] type Iter<'t> = MappedArrayIter<'t>; + #[cfg(feature = "nightly")] type IterLazy<'t> = MappedArrayLazyIter<'t>; + #[cfg(feature = "nightly")] type IterCheap<'t> = MappedArrayCheapIter<'t>; fn len(&self) -> usize { @@ -722,23 +797,26 @@ None } - fn evaluated(&self) -> Result> { - self.iter().collect() - } - + #[cfg(feature = "nightly")] fn iter(&self) -> MappedArrayIter<'_> { (0..self.len()).map(|i| self.get(i).transpose().expect("length checked")) } + #[cfg(feature = "nightly")] fn iter_lazy(&self) -> MappedArrayLazyIter<'_> { (0..self.len()).map(|i| self.get_lazy(i).expect("length checked")) } + #[cfg(feature = "nightly")] fn iter_cheap(&self) -> Option> { None } } -// impl MappedArray +impl From for ArrValue { + fn from(value: MappedArray) -> Self { + Self::Mapped(value) + } +} #[derive(Trace, Debug)] pub struct RepeatedArrayInner { @@ -762,13 +840,19 @@ } } +#[cfg(feature = "nightly")] type RepeatedArrayIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] type RepeatedArrayLazyIter<'t> = impl DoubleEndedIterator> + ExactSizeIterator + 't; +#[cfg(feature = "nightly")] type RepeatedArrayCheapIter<'t> = impl DoubleEndedIterator + ExactSizeIterator + 't; impl ArrayLike for RepeatedArray { + #[cfg(feature = "nightly")] type Iter<'t> = RepeatedArrayIter<'t>; + #[cfg(feature = "nightly")] type IterLazy<'t> = RepeatedArrayLazyIter<'t>; + #[cfg(feature = "nightly")] type IterCheap<'t> = RepeatedArrayCheapIter<'t>; fn len(&self) -> usize { @@ -796,15 +880,7 @@ self.0.data.get_cheap(index % self.0.data.len()) } - fn evaluated(&self) -> Result> { - let mut data = self.0.data.evaluated()?; - let data_range = 0..data.len(); - for _ in 1..self.0.repeats { - data.extend_from_within(data_range.clone()); - } - Ok(data) - } - + #[cfg(feature = "nightly")] fn iter(&self) -> RepeatedArrayIter<'_> { (0..self.0.total_len) .map(|i| self.get(i)) @@ -812,12 +888,14 @@ .map(Option::unwrap) } + #[cfg(feature = "nightly")] fn iter_lazy(&self) -> RepeatedArrayLazyIter<'_> { (0..self.0.total_len) .map(|i| self.get_lazy(i)) .map(Option::unwrap) } + #[cfg(feature = "nightly")] fn iter_cheap(&self) -> Option> { if !self.0.data.is_cheap() { return None; @@ -829,7 +907,13 @@ ) } } +impl From for ArrValue { + fn from(value: RepeatedArray) -> Self { + Self::Repeated(value) + } +} +#[cfg(feature = "nightly")] macro_rules! impl_iter_enum { ($n:ident => $v:ident) => { pub enum $n<'t> { @@ -865,6 +949,7 @@ } pub(super) use pass; +#[cfg(feature = "nightly")] macro_rules! pass_iter_call { ($t:ident.$c:ident $(in $wrap:ident)? => $e:ident) => { match $t { @@ -881,8 +966,10 @@ } }; } +#[cfg(feature = "nightly")] pub(super) use pass_iter_call; +#[cfg(feature = "nightly")] macro_rules! impl_iter { ($t:ident => $out:ty) => { impl Iterator for $t<'_> { @@ -927,9 +1014,15 @@ }; } +#[cfg(feature = "nightly")] impl_iter_enum!(UnknownArrayIter => Iter); -impl_iter_enum!(UnknownArrayIterLazy => IterLazy); -impl_iter_enum!(UnknownArrayIterCheap => IterCheap); +#[cfg(feature = "nightly")] impl_iter!(UnknownArrayIter => Result); +#[cfg(feature = "nightly")] +impl_iter_enum!(UnknownArrayIterLazy => IterLazy); +#[cfg(feature = "nightly")] impl_iter!(UnknownArrayIterLazy => Thunk); +#[cfg(feature = "nightly")] +impl_iter_enum!(UnknownArrayIterCheap => IterCheap); +#[cfg(feature = "nightly")] impl_iter!(UnknownArrayIterCheap => Val); --- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -414,7 +414,7 @@ #[allow(clippy::too_many_lines)] pub fn evaluate(ctx: Context, expr: &LocExpr) -> Result { use Expr::*; - if let Some(trivial) = evaluate_trivial(&expr) { + if let Some(trivial) = evaluate_trivial(expr) { return Ok(trivial); } let LocExpr(expr, loc) = expr; --- a/crates/jrsonnet-evaluator/src/evaluate/operator.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/operator.rs @@ -96,16 +96,37 @@ (Str(a), Str(b)) => a.cmp(b), (Num(a), Num(b)) => a.partial_cmp(b).expect("jsonnet numbers are non NaN"), (Arr(a), Arr(b)) => { - let ai = a.iter(); - let bi = b.iter(); + if let (Some(ai), Some(bi)) = (a.iter_cheap(), b.iter_cheap()) { + for (a, b) in ai.zip(bi) { + let ord = evaluate_compare_op(&a, &b, op)?; + if !ord.is_eq() { + return Ok(ord); + } + } + } else { + { + let ai = a.iter(); + let bi = b.iter(); - for (a, b) in ai.zip(bi) { - let ord = evaluate_compare_op(&a?, &b?, op)?; - if !ord.is_eq() { - return Ok(ord); + for (a, b) in ai.zip(bi) { + let ord = evaluate_compare_op(&a?, &b?, op)?; + if !ord.is_eq() { + return Ok(ord); + } + } } - } + // { + // let ai = a.iter_expl(); + // let bi = b.iter_expl(); + // for (a, b) in ai.zip(bi) { + // let ord = evaluate_compare_op(&a?, &b?, op)?; + // if !ord.is_eq() { + // return Ok(ord); + // } + // } + // } + } a.len().cmp(&b.len()) } (_, _) => throw!(BinaryOperatorDoesNotOperateOnValues( --- a/crates/jrsonnet-evaluator/src/lib.rs +++ b/crates/jrsonnet-evaluator/src/lib.rs @@ -1,6 +1,5 @@ //! jsonnet interpreter implementation -#![cfg_attr(feature = "nightly", feature(thread_local))] -#![feature(type_alias_impl_trait)] +#![cfg_attr(feature = "nightly", feature(thread_local, type_alias_impl_trait))] #![deny(unsafe_op_in_unsafe_fn)] #![warn( clippy::all, --- a/crates/jrsonnet-evaluator/src/stdlib/mod.rs +++ b/crates/jrsonnet-evaluator/src/stdlib/mod.rs @@ -13,9 +13,9 @@ || format!("std.format of {str}"), || { Ok(match vals { - Val::Arr(vals) => format_arr(&str, &vals.evaluatedcc()?)?, - Val::Obj(obj) => format_obj(&str, &obj)?, - o => format_arr(&str, &[o])?, + Val::Arr(vals) => format_arr(str, &vals.iter().collect::>>()?)?, + Val::Obj(obj) => format_obj(str, &obj)?, + o => format_arr(str, &[o])?, }) }, ) --- a/crates/jrsonnet-evaluator/src/typed/conversions.rs +++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs @@ -278,19 +278,19 @@ } /// Specialization, provides faster `TryFrom` for Val -pub struct VecVal(pub Cc>); +pub struct VecVal(pub Vec); impl Typed for VecVal { const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr); fn into_untyped(value: Self) -> Result { - Ok(Val::Arr(ArrValue::eager(value.0))) + Ok(Val::Arr(ArrValue::eager(Cc::new(value.0)))) } fn from_untyped(value: Val) -> Result { ::TYPE.check(&value)?; match value { - Val::Arr(a) => Ok(Self(a.evaluatedcc()?)), + Val::Arr(a) => Ok(Self(a.iter().collect::>>()?)), _ => unreachable!(), } } --- a/crates/jrsonnet-parser/src/source.rs +++ b/crates/jrsonnet-parser/src/source.rs @@ -33,8 +33,8 @@ } fn dyn_eq(&self, other: &dyn $T) -> bool { let Some(other) = other.as_any().downcast_ref::() else { - return false - }; + return false + }; let this = ::as_any(self) .downcast_ref::() .expect("restricted by impl"); --- a/crates/jrsonnet-stdlib/src/objects.rs +++ b/crates/jrsonnet-stdlib/src/objects.rs @@ -5,7 +5,6 @@ val::{StrValue, Val}, IStr, ObjValue, }; -use jrsonnet_gcmodule::Cc; #[builtin] pub fn builtin_object_fields_ex( @@ -20,12 +19,12 @@ #[cfg(feature = "exp-preserve-order")] preserve_order, ); - Ok(VecVal(Cc::new( + Ok(VecVal( out.into_iter() .map(StrValue::Flat) .map(Val::Str) .collect::>(), - ))) + )) } #[builtin] --- a/crates/jrsonnet-stdlib/src/sort.rs +++ b/crates/jrsonnet-stdlib/src/sort.rs @@ -50,13 +50,12 @@ } /// * `key_getter` - None, if identity sort required -pub fn sort(ctx: Context, values: Cc>, key_getter: FuncVal) -> Result>> { +pub fn sort(ctx: Context, mut values: Vec, key_getter: FuncVal) -> Result> { if values.len() <= 1 { return Ok(values); } if key_getter.is_identity() { // Fast path, identity key getter - let mut values = (*values).clone(); let sort_type = get_sort_type(&mut values, |k| k)?; match sort_type { SortKeyType::Number => values.sort_unstable_by_key(|v| match v { @@ -69,7 +68,7 @@ }), SortKeyType::Unknown => unreachable!(), }; - Ok(Cc::new(values)) + Ok(values) } else { // Slow path, user provided key getter let mut vk = Vec::with_capacity(values.len()); @@ -96,7 +95,7 @@ }), SortKeyType::Unknown => unreachable!(), }; - Ok(Cc::new(vk.into_iter().map(|v| v.0).collect())) + Ok(vk.into_iter().map(|v| v.0).collect()) } } @@ -106,9 +105,9 @@ if arr.len() <= 1 { return Ok(arr); } - Ok(ArrValue::eager(super::sort::sort( + Ok(ArrValue::eager(Cc::new(super::sort::sort( ctx, - arr.evaluatedcc()?, + arr.iter().collect::>>()?, keyF.unwrap_or_else(FuncVal::identity), - )?)) + )?))) } --- a/crates/jrsonnet-stdlib/src/strings.rs +++ b/crates/jrsonnet-stdlib/src/strings.rs @@ -6,7 +6,6 @@ val::{ArrValue, StrValue}, Either, IStr, Val, }; -use jrsonnet_gcmodule::Cc; #[builtin] pub const fn builtin_codepoint(str: char) -> Result { @@ -31,7 +30,7 @@ #[builtin] pub fn builtin_splitlimit(str: IStr, c: IStr, maxsplits: Either![usize, M1]) -> Result { use Either2::*; - Ok(VecVal(Cc::new(match maxsplits { + Ok(VecVal(match maxsplits { A(n) => str .splitn(n + 1, &c as &str) .map(|s| Val::Str(StrValue::Flat(s.into()))) @@ -40,7 +39,7 @@ .split(&c as &str) .map(|s| Val::Str(StrValue::Flat(s.into()))) .collect(), - }))) + })) } #[builtin] --- a/flake.lock +++ b/flake.lock @@ -15,28 +15,13 @@ "type": "github" } }, - "flake-utils_2": { - "locked": { - "lastModified": 1659877975, - "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1668090223, - "narHash": "sha256-Bynlfyf/LsQJ+CJ//1TGmA7eiCzqk95bz+bxyP39xYY=", + "lastModified": 1670089411, + "narHash": "sha256-iiW+L7iN8At8s98qb2h1P8Z0BVTZLqY8KHpfZuM7ULQ=", "owner": "nixos", "repo": "nixpkgs", - "rev": "1f6b98281191b50ba987cabd5bf3068870c26789", + "rev": "ffa4eb958a435e9833bda0fdfc834e87232aa879", "type": "github" }, "original": { @@ -45,22 +30,6 @@ "type": "github" } }, - "nixpkgs_2": { - "locked": { - "lastModified": 1665296151, - "narHash": "sha256-uOB0oxqxN9K7XGF1hcnY+PQnlQJ+3bP2vCn/+Ru/bbc=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "14ccaaedd95a488dd7ae142757884d8e125b3363", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, "root": { "inputs": { "flake-utils": "flake-utils", @@ -70,15 +39,19 @@ }, "rust-overlay": { "inputs": { - "flake-utils": "flake-utils_2", - "nixpkgs": "nixpkgs_2" + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs" + ] }, "locked": { - "lastModified": 1668048396, - "narHash": "sha256-SUWQlSa/H5XKPeuF9XmWzmwIJrgK42Lak6/1jBAwyd0=", + "lastModified": 1670034122, + "narHash": "sha256-EqmuOKucPWtMvCZtHraHr3Q3bgVszq1x2PoZtQkUuEk=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "859fefb532bb957f51a9b5e8e3ba2e48394c9353", + "rev": "a0d5773275ecd4f141d792d3a0376277c0fc0b65", "type": "github" }, "original": { --- a/flake.nix +++ b/flake.nix @@ -3,7 +3,11 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs"; flake-utils.url = "github:numtide/flake-utils"; - rust-overlay.url = "github:oxalica/rust-overlay"; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.flake-utils.follows = "flake-utils"; + }; }; outputs = { nixpkgs, flake-utils, rust-overlay, ... }: flake-utils.lib.eachDefaultSystem (system: @@ -12,7 +16,7 @@ inherit system; overlays = [ rust-overlay.overlays.default ]; }; - rust = ((pkgs.rustChannelOf { date = "2022-11-10"; channel = "nightly"; }).default.override { + rust = ((pkgs.rustChannelOf { date = "2022-11-19"; channel = "nightly"; }).default.override { extensions = [ "rust-src" "miri" ]; }); in @@ -29,6 +33,13 @@ cargo = rust; }; }; + jrsonnet-nightly = pkgs.callPackage ./nix/jrsonnet.nix { + rustPlatform = pkgs.makeRustPlatform { + rustc = rust; + cargo = rust; + }; + withNightlyFeatures = true; + }; jrsonnet-release = pkgs.callPackage ./nix/jrsonnet-release.nix { rustPlatform = pkgs.makeRustPlatform { rustc = rust; @@ -37,29 +48,48 @@ }; benchmarks = pkgs.callPackage ./nix/benchmarks.nix { - inherit go-jsonnet sjsonnet jsonnet jrsonnet jrsonnet-release; + inherit go-jsonnet sjsonnet jsonnet; + jrsonnetVariants = [ + { drv = jrsonnet; name = "current"; } + { drv = jrsonnet-nightly; name = "current-nightly"; } + ]; }; benchmarks-quick = pkgs.callPackage ./nix/benchmarks.nix { - inherit go-jsonnet sjsonnet jsonnet jrsonnet jrsonnet-release; + inherit go-jsonnet sjsonnet jsonnet; quick = true; + jrsonnetVariants = [ + { drv = jrsonnet; name = "current"; } + { drv = jrsonnet-nightly; name = "current-nightly"; } + ]; }; benchmarks-against-release = pkgs.callPackage ./nix/benchmarks.nix { - inherit go-jsonnet sjsonnet jsonnet jrsonnet jrsonnet-release; - againstRelease = true; + inherit go-jsonnet sjsonnet jsonnet; + jrsonnetVariants = [ + { drv = jrsonnet; name = "current"; } + { drv = jrsonnet-nightly; name = "current-nightly"; } + { drv = jrsonnet-release; name = "before-str-extend"; } + ]; }; benchmarks-quick-against-release = pkgs.callPackage ./nix/benchmarks.nix { - inherit go-jsonnet sjsonnet jsonnet jrsonnet jrsonnet-release; + inherit go-jsonnet sjsonnet jsonnet; quick = true; - againstRelease = true; + jrsonnetVariants = [ + { drv = jrsonnet; name = "current"; } + { drv = jrsonnet-nightly; name = "current-nightly"; } + { drv = jrsonnet-release; name = "before-str-extend"; } + ]; }; }; devShell = pkgs.mkShell { nativeBuildInputs = with pkgs;[ rust cargo-edit + cargo-asm lld hyperfine valgrind + kcachegrind + graphviz ]; }; } --- a/nix/benchmarks.nix +++ b/nix/benchmarks.nix @@ -4,15 +4,16 @@ , cacert , stdenv , fetchFromGitHub -, jrsonnet -, jrsonnet-release , go-jsonnet , sjsonnet , jsonnet , hyperfine , quick ? false -, againstRelease ? false +, jrsonnetVariants }: + +with lib; + let jsonnetBench = fetchFromGitHub { rev = "v0.19.1"; @@ -65,13 +66,12 @@ unpackPhase = "true"; buildInputs = [ - jrsonnet go-jsonnet sjsonnet jsonnet hyperfine - ] ++ (if againstRelease then [ jrsonnet-release ] else [ ]); + ]; installPhase = let @@ -81,47 +81,48 @@ echo >> $out echo "### ${name}" >> $out echo >> $out - ${if skipGo != "" then '' + ${optionalString (skipGo != "") '' echo "> Note: No results for Go, ${skipGo}" >> $out echo >> $out - '' else ""} - ${if skipScala != "" then '' + ''} + ${optionalString (skipScala != "") '' echo "> Note: No results for Scala, ${skipScala}" >> $out echo >> $out - '' else ""} - ${if skipCpp != "" then '' + ''} + ${optionalString (skipCpp != "") '' echo "> Note: No results for C++, ${skipCpp}" >> $out echo >> $out - '' else ""} - ${if !quick then '' + ''} + ${optionalString (!quick && !omitSource) '' echo "
" >> $out echo "Source" >> $out echo >> $out echo "\`\`\`jsonnet" >> $out - ${if pathIsGenerator then "echo \"// Generator source\" >> $out" else ""} - ${if omitSource then "echo \"// Omitted: too large\" >> $out" else "cat ${path} >> $out"} + ${optionalString pathIsGenerator "echo \"// Generator source\" >> $out"} + cat ${path} >> $out echo >> $out echo "\`\`\`" >> $out echo "
" >> $out echo >> $out - '' else ""} + ''} path=${path} - ${if pathIsGenerator then '' - jrsonnet $path > generated.jsonnet + ${optionalString pathIsGenerator '' + go-jsonnet $path > generated.jsonnet path=generated.jsonnet - '' else ""} - hyperfine -N -w4 --output=pipe --style=basic --export-markdown result.md \ - "jrsonnet $path ${if vendor != "" then "-J${vendor}" else ""}" -n "Rust" \ - ${if againstRelease then "\"jrsonnet-release $path ${if vendor != "" then "-J${vendor}" else ""}\" -n \"Rust (released)\"" else "" } \ - ${if skipGo == "" then "\"go-jsonnet $path ${if vendor != "" then "-J ${vendor}" else ""}\" -n \"Go\"" else "" } \ - ${if skipScala == "" then "\"sjsonnet $path ${if vendor != "" then "-J ${vendor}" else ""}\" -n \"Scala\"" else "" } \ - ${if skipCpp == "" then "\"jsonnet $path ${if vendor != "" then "-J ${vendor}" else ""}\" -n \"C++\"" else "" } + ''} + hyperfine -N -w4 -m20 --output=pipe --style=basic --export-markdown result.md \ + ${concatStringsSep " " (forEach jrsonnetVariants (variant: + "\"${variant.drv}/bin/jrsonnet $path ${optionalString (vendor != "") "-J${vendor}"}\" -n \"Rust (${variant.name})\"" + ))} \ + ${optionalString (skipGo == "") "\"go-jsonnet $path ${optionalString (vendor != "") "-J ${vendor}"}\" -n \"Go\""} \ + ${optionalString (skipScala == "") "\"sjsonnet $path ${optionalString (vendor != "") "-J ${vendor}"}\" -n \"Scala\""} \ + ${optionalString (skipCpp == "") "\"jsonnet $path ${optionalString (vendor != "") "-J ${vendor}"}\" -n \"C++\""} cat result.md >> $out ''; in '' touch $out - ${if !quick then '' + ${optionalString (!quick) '' cat ${./benchmarks.md} >> $out echo >> $out @@ -156,43 +157,43 @@ echo >> $out echo >> $out - '' else ""} + ''} echo "## Real world" >> $out - ${mkBench {name = "Graalvm CI"; path = "${graalvmBench}/ci.jsonnet"; skipCpp = "takes longer than a hour";}} - ${mkBench {name = "Kube-prometheus manifests"; vendor = "${kubePrometheusBench}/vendor"; path = "${kubePrometheusBench}/example.jsonnet"; skipCpp = skipSlow;}} + ${mkBench {name = "Graalvm CI"; path = "${graalvmBench}/ci.jsonnet"; skipCpp = "takes longer than a hour"; skipGo = skipSlow; skipScala = skipSlow;}} + ${mkBench {name = "Kube-prometheus manifests"; vendor = "${kubePrometheusBench}/vendor"; path = "${kubePrometheusBench}/example.jsonnet"; skipCpp = skipSlow; skipGo = skipSlow; skipScala = skipSlow;}} echo >> $out echo "## Benchmarks from C++ jsonnet (/perf_tests)" >> $out - ${mkBench {name = "Large string join"; path = "${jsonnetBench}/perf_tests/large_string_join.jsonnet";}} - ${mkBench {name = "Large string template"; omitSource = true; path = "${jsonnetBench}/perf_tests/large_string_template.jsonnet"; skipGo = "fails with os stack size exhausion"; skipCpp = skipSlow;}} - ${mkBench {name = "Realistic 1"; path = "${jsonnetBench}/perf_tests/realistic1.jsonnet"; skipGo = skipSlow; skipCpp = skipSlow;}} - ${mkBench {name = "Realistic 2"; path = "${jsonnetBench}/perf_tests/realistic2.jsonnet"; skipGo = skipSlow; skipCpp = skipSlow;}} + ${mkBench {name = "Large string join"; path = "${jsonnetBench}/perf_tests/large_string_join.jsonnet"; skipScala = skipSlow;}} + ${mkBench {name = "Large string template"; omitSource = true; path = "${jsonnetBench}/perf_tests/large_string_template.jsonnet"; skipGo = "fails with os stack size exhausion"; skipCpp = skipSlow; skipScala = skipSlow;}} + ${mkBench {name = "Realistic 1"; path = "${jsonnetBench}/perf_tests/realistic1.jsonnet"; skipGo = skipSlow; skipCpp = skipSlow; skipScala = skipSlow;}} + ${mkBench {name = "Realistic 2"; path = "${jsonnetBench}/perf_tests/realistic2.jsonnet"; skipGo = skipSlow; skipCpp = skipSlow; skipScala = skipSlow;}} echo >> $out echo "## Benchmarks from C++ jsonnet (/benchmarks)" >> $out - ${mkBench {name = "Tail call"; path = "${jsonnetBench}/benchmarks/bench.01.jsonnet";}} - ${mkBench {name = "Inheritance recursion"; path = "${jsonnetBench}/benchmarks/bench.02.jsonnet"; skipCpp = skipSlow;}} - ${mkBench {name = "Simple recursive call"; path = "${jsonnetBench}/benchmarks/bench.03.jsonnet";}} - ${mkBench {name = "Foldl string concat"; path = "${jsonnetBench}/benchmarks/bench.04.jsonnet";}} + ${mkBench {name = "Tail call"; path = "${jsonnetBench}/benchmarks/bench.01.jsonnet"; skipScala = skipSlow;}} + ${mkBench {name = "Inheritance recursion"; path = "${jsonnetBench}/benchmarks/bench.02.jsonnet"; skipCpp = skipSlow; skipGo = skipSlow;}} + ${mkBench {name = "Simple recursive call"; path = "${jsonnetBench}/benchmarks/bench.03.jsonnet"; skipScala = skipSlow; skipGo = skipSlow;}} + ${mkBench {name = "Foldl string concat"; path = "${jsonnetBench}/benchmarks/bench.04.jsonnet"; skipCpp = skipSlow; skipScala = skipSlow;}} ${mkBench {name = "Array sorts"; path = "${jsonnetBench}/benchmarks/bench.06.jsonnet"; skipScala = "std.reverse is not implemented"; skipCpp = skipSlow;}} - ${mkBench {name = "Lazy array"; path = "${jsonnetBench}/benchmarks/bench.07.jsonnet";}} - ${mkBench {name = "Inheritance function recursion"; path = "${jsonnetBench}/benchmarks/bench.08.jsonnet";}} - ${mkBench {name = "String strips"; path = "${jsonnetBench}/benchmarks/bench.09.jsonnet"; skipCpp = skipSlow;}} - ${mkBench {name = "Big object"; path = "${jsonnetBench}/benchmarks/gen_big_object.jsonnet"; pathIsGenerator = true;}} + ${mkBench {name = "Lazy array"; path = "${jsonnetBench}/benchmarks/bench.07.jsonnet"; skipGo = skipSlow; skipScala = skipSlow;}} + ${mkBench {name = "Inheritance function recursion"; path = "${jsonnetBench}/benchmarks/bench.08.jsonnet"; skipCpp = skipSlow; skipScala = skipSlow;}} + ${mkBench {name = "String strips"; path = "${jsonnetBench}/benchmarks/bench.09.jsonnet"; skipCpp = skipSlow; skipScala = skipSlow;}} + ${mkBench {name = "Big object"; path = "${jsonnetBench}/benchmarks/gen_big_object.jsonnet"; pathIsGenerator = true; skipScala = skipSlow;}} echo >> $out echo "## Benchmarks from Go jsonnet (builtins)" >> $out - ${mkBench {name = "std.base64"; path = "${goJsonnetBench}/base64.jsonnet"; skipCpp = skipSlow;}} - ${mkBench {name = "std.base64Decode"; path = "${goJsonnetBench}/base64Decode.jsonnet"; skipCpp = skipSlow;}} - ${mkBench {name = "std.base64DecodeBytes"; path = "${goJsonnetBench}/base64DecodeBytes.jsonnet"; skipCpp = skipSlow;}} - ${mkBench {name = "std.base64 (byte array)"; path = "${goJsonnetBench}/base64_byte_array.jsonnet"; skipCpp = skipSlow;}} - ${mkBench {name = "std.foldl"; path = "${goJsonnetBench}/foldl.jsonnet";}} - ${mkBench {name = "std.manifestJsonEx"; path = "${goJsonnetBench}/manifestJsonEx.jsonnet";}} - ${mkBench {name = "std.manifestTomlEx"; path = "${goJsonnetBench}/manifestTomlEx.jsonnet"; skipScala = "std.manifestTomlEx is not implemented";}} - ${mkBench {name = "std.parseInt"; path = "${goJsonnetBench}/parseInt.jsonnet";}} - ${mkBench {name = "std.reverse"; path = "${goJsonnetBench}/reverse.jsonnet"; skipScala = "std.reverse is not implemented";}} - ${mkBench {name = "std.substr"; path = "${goJsonnetBench}/substr.jsonnet";}} + ${mkBench {name = "std.base64"; path = "${goJsonnetBench}/base64.jsonnet"; skipCpp = skipSlow; skipScala = skipSlow;}} + ${mkBench {name = "std.base64Decode"; path = "${goJsonnetBench}/base64Decode.jsonnet"; skipCpp = skipSlow; skipScala = skipSlow;}} + ${mkBench {name = "std.base64DecodeBytes"; path = "${goJsonnetBench}/base64DecodeBytes.jsonnet"; skipCpp = skipSlow; skipGo = skipSlow; skipScala = skipSlow;}} + ${mkBench {name = "std.base64 (byte array)"; path = "${goJsonnetBench}/base64_byte_array.jsonnet"; skipCpp = skipSlow; skipGo = skipSlow; skipScala = skipSlow;}} + ${mkBench {name = "std.foldl"; path = "${goJsonnetBench}/foldl.jsonnet"; skipScala = skipSlow;}} + ${mkBench {name = "std.manifestJsonEx"; path = "${goJsonnetBench}/manifestJsonEx.jsonnet"; skipScala = skipSlow; skipCpp = skipSlow;}} + ${mkBench {name = "std.manifestTomlEx"; path = "${goJsonnetBench}/manifestTomlEx.jsonnet"; skipScala = "std.manifestTomlEx is not implemented"; skipCpp=skipSlow;}} + ${mkBench {name = "std.parseInt"; path = "${goJsonnetBench}/parseInt.jsonnet"; skipScala = skipSlow; skipCpp = skipSlow;}} + ${mkBench {name = "std.reverse"; path = "${goJsonnetBench}/reverse.jsonnet"; skipScala = "std.reverse is not implemented"; skipCpp = skipSlow; skipGo = skipSlow;}} + ${mkBench {name = "std.substr"; path = "${goJsonnetBench}/substr.jsonnet"; skipScala = skipSlow;}} ${mkBench {name = "Comparsion for array"; path = "${goJsonnetBench}/comparison.jsonnet"; skipScala = "array comparsion is not implemented"; skipCpp = skipSlow;}} - ${mkBench {name = "Comparsion for primitives"; path = "${goJsonnetBench}/comparison2.jsonnet"; skipCpp = "can't run: uses up to 192GB of RAM";}} + ${mkBench {name = "Comparsion for primitives"; path = "${goJsonnetBench}/comparison2.jsonnet"; skipCpp = "can't run: uses up to 192GB of RAM"; skipGo = skipSlow; skipScala = skipSlow;}} ''; } --- a/nix/jrsonnet-release.nix +++ b/nix/jrsonnet-release.nix @@ -3,15 +3,15 @@ rustPlatform.buildRustPackage rec { pname = "jrsonnet"; - version = "d32fe45b8ed28fb39b5359a704922922368af1c0"; + version = "before-str-extend"; src = fetchFromGitHub { owner = "CertainLach"; repo = pname; - rev = version; + rev = "d32fe45b8ed28fb39b5359a704922922368af1c0"; hash = "sha256-R9Xt36bYS5upVDzt8hEifwmfocXpJbIKwvxkoJNEGVc="; }; - cargoHash = "sha256-V+KGWeNlUnelofaGzufNPLGDyxazoFrjZ/n391VYYws="; + cargoHash = "sha256-j2sUIzvK66jn8ajmMsXXHstw79jCLog93XCQj1qjAN8="; cargoTestFlags = [ "--package=jrsonnet --features=mimalloc,legacy-this-file" ]; cargoBuildFlags = [ "--package=jrsonnet --features=mimalloc,legacy-this-file" ]; @@ -19,7 +19,6 @@ buildInputs = [ makeWrapper ]; postInstall = '' - mv $out/bin/jrsonnet $out/bin/jrsonnet-release - wrapProgram $out/bin/jrsonnet-release --add-flags "--max-stack=200000 --os-stack=200000" + wrapProgram $out/bin/jrsonnet --add-flags "--max-stack=200000 --os-stack=200000" ''; } --- a/nix/jrsonnet.nix +++ b/nix/jrsonnet.nix @@ -1,4 +1,12 @@ -{ lib, fetchFromGitHub, rustPlatform, runCommand, makeWrapper }: +{ lib +, fetchFromGitHub +, rustPlatform +, runCommand +, makeWrapper +, withNightlyFeatures ? false +}: + +with lib; let filteredSrc = builtins.path { @@ -18,10 +26,12 @@ rustPlatform.buildRustPackage rec { inherit src; pname = "jrsonnet"; - version = "git"; + version = "current${optionalString withNightlyFeatures "-nightly"}"; - cargoTestFlags = [ "--features=mimalloc,legacy-this-file,nightly" ]; - cargoBuildFlags = [ "--features=mimalloc,legacy-this-file,nightly" ]; + cargoTestFlags = [ + "--features=mimalloc,legacy-this-file${optionalString withNightlyFeatures ",nightly"}" + ]; + cargoBuildFlags = cargoTestFlags; buildInputs = [ makeWrapper ];