difftreelog
refactor reduce callsite boilerplate
in: master
38 files changed
bindings/jsonnet/src/import.rsdiffbeforeafterboth--- a/bindings/jsonnet/src/import.rs
+++ b/bindings/jsonnet/src/import.rs
@@ -116,12 +116,11 @@
cb: JsonnetImportCallback,
ctx: *mut c_void,
) {
- vm.state
- .set_import_resolver(Box::new(CallbackImportResolver {
- cb,
- ctx,
- out: RefCell::new(HashMap::new()),
- }))
+ vm.state.set_import_resolver(CallbackImportResolver {
+ cb,
+ ctx,
+ out: RefCell::new(HashMap::new()),
+ })
}
/// # Safety
bindings/jsonnet/src/native.rsdiffbeforeafterboth--- a/bindings/jsonnet/src/native.rs
+++ b/bindings/jsonnet/src/native.rs
@@ -7,11 +7,9 @@
use jrsonnet_evaluator::{
error::{Error, ErrorKind},
function::builtin::{NativeCallback, NativeCallbackHandler},
- tb,
typed::Typed,
IStr, Val,
};
-use jrsonnet_gcmodule::Cc;
use crate::VM;
@@ -102,9 +100,6 @@
.add_native(
name,
#[allow(deprecated)]
- Cc::new(tb!(NativeCallback::new(
- params,
- tb!(JsonnetNativeCallbackHandler { ctx, cb }),
- ))),
+ NativeCallback::new(params, JsonnetNativeCallbackHandler { ctx, cb }),
)
}
bindings/jsonnet/src/val_extract.rsdiffbeforeafterboth--- a/bindings/jsonnet/src/val_extract.rs
+++ b/bindings/jsonnet/src/val_extract.rs
@@ -13,7 +13,10 @@
#[no_mangle]
pub extern "C" fn jsonnet_json_extract_string(_vm: &VM, v: &Val) -> *mut c_char {
match v {
- Val::Str(s) => CString::new(s as &str).unwrap().into_raw(),
+ Val::Str(s) => {
+ let s = s.clone().into_flat();
+ CString::new(s.as_str()).unwrap().into_raw()
+ }
_ => std::ptr::null_mut(),
}
}
bindings/jsonnet/src/val_make.rsdiffbeforeafterboth--- a/bindings/jsonnet/src/val_make.rs
+++ b/bindings/jsonnet/src/val_make.rs
@@ -5,8 +5,10 @@
os::raw::{c_char, c_double, c_int},
};
-use jrsonnet_evaluator::{val::ArrValue, ObjValue, Val};
-use jrsonnet_gcmodule::Cc;
+use jrsonnet_evaluator::{
+ val::{ArrValue, StrValue},
+ ObjValue, Val,
+};
use crate::VM;
@@ -19,7 +21,7 @@
pub unsafe extern "C" fn jsonnet_json_make_string(_vm: &VM, val: *const c_char) -> *mut Val {
let val = CStr::from_ptr(val);
let val = val.to_str().expect("string is not utf-8");
- Box::into_raw(Box::new(Val::Str(val.into())))
+ Box::into_raw(Box::new(Val::Str(StrValue::Flat(val.into()))))
}
/// Convert the given double to a `JsonnetJsonValue`.
@@ -46,7 +48,7 @@
/// Assign elements with [`jsonnet_json_array_append`].
#[no_mangle]
pub extern "C" fn jsonnet_json_make_array(_vm: &VM) -> *mut Val {
- Box::into_raw(Box::new(Val::Arr(ArrValue::eager(Cc::new(Vec::new())))))
+ Box::into_raw(Box::new(Val::Arr(ArrValue::eager(Vec::new()))))
}
/// Make a `JsonnetJsonValue` representing an object.
crates/jrsonnet-cli/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-cli/src/lib.rs
+++ b/crates/jrsonnet-cli/src/lib.rs
@@ -54,7 +54,7 @@
library_paths.extend(env::split_paths(path.as_os_str()));
}
- s.set_import_resolver(Box::new(FileImportResolver::new(library_paths)));
+ s.set_import_resolver(FileImportResolver::new(library_paths));
set_stack_depth_limit(self.max_stack);
Ok(())
crates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/arr/mod.rs
+++ b/crates/jrsonnet-evaluator/src/arr/mod.rs
@@ -55,8 +55,8 @@
Self::Lazy(LazyArray(thunks))
}
- pub fn eager(values: Cc<Vec<Val>>) -> Self {
- Self::Eager(EagerArray(values))
+ pub fn eager(values: Vec<Val>) -> Self {
+ Self::Eager(EagerArray(Cc::new(values)))
}
pub fn repeated(data: ArrValue, repeats: usize) -> Option<Self> {
@@ -81,7 +81,7 @@
out.push(i);
};
}
- Ok(Self::eager(Cc::new(out)))
+ Ok(Self::eager(out))
}
pub fn extended(a: ArrValue, b: ArrValue) -> Self {
@@ -98,7 +98,7 @@
let mut out = Vec::with_capacity(a.len() + b.len());
out.extend(a);
out.extend(b);
- Self::eager(Cc::new(out))
+ Self::eager(out)
} else {
let mut out = Vec::with_capacity(a.len() + b.len());
out.extend(a.iter_lazy());
@@ -235,7 +235,7 @@
}
impl From<Vec<Val>> for ArrValue {
fn from(value: Vec<Val>) -> Self {
- Self::eager(Cc::new(value))
+ Self::eager(value)
}
}
impl From<Vec<Thunk<Val>>> for ArrValue {
@@ -243,6 +243,11 @@
Self::lazy(Cc::new(value))
}
}
+impl FromIterator<Val> for ArrValue {
+ fn from_iter<T: IntoIterator<Item = Val>>(iter: T) -> Self {
+ Self::eager(iter.into_iter().collect())
+ }
+}
#[cfg(target_pointer_width = "64")]
static_assertions::assert_eq_size!(ArrValue, [u8; 16]);
crates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth1//! Those implementations are a bit sketchy, as this is mostly performance experiments2//! of not yet finished nightly rust features34use std::{cell::RefCell, iter, mem::replace};56use jrsonnet_gcmodule::{Cc, Trace};7use jrsonnet_interner::IBytes;8use jrsonnet_parser::LocExpr;910use super::{ArrValue, ArrayLikeIter};11use crate::{12 error::ErrorKind::InfiniteRecursionDetected, evaluate, function::FuncVal, tb, typed::Any,13 val::ThunkValue, Context, Error, Result, Thunk, Val,14};1516pub trait ArrayLike: Sized + Into<ArrValue> {17 #[cfg(feature = "nightly")]18 type Iter<'t>19 where20 Self: 't;21 #[cfg(feature = "nightly")]22 type IterLazy<'t>23 where24 Self: 't;25 #[cfg(feature = "nightly")]26 type IterCheap<'t>27 where28 Self: 't;2930 fn len(&self) -> usize;31 fn is_empty(&self) -> bool {32 self.len() == 033 }34 fn get(&self, index: usize) -> Result<Option<Val>>;35 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>>;36 fn get_cheap(&self, index: usize) -> Option<Val>;37 #[cfg(feature = "nightly")]38 #[allow(clippy::iter_not_returning_iterator)]39 fn iter(&self) -> Self::Iter<'_>;40 #[cfg(feature = "nightly")]41 fn iter_lazy(&self) -> Self::IterLazy<'_>;42 #[cfg(feature = "nightly")]43 fn iter_cheap(&self) -> Option<Self::IterCheap<'_>>;4445 fn reverse(self) -> ArrValue {46 ArrValue::Reverse(Cc::new(ReverseArray(self.into())))47 }48}4950#[derive(Debug, Clone, Trace)]51pub struct SliceArray {52 pub(crate) inner: ArrValue,53 pub(crate) from: u32,54 pub(crate) to: u32,55 pub(crate) step: u32,56}5758impl SliceArray {59 #[cfg(not(feature = "nightly"))]60 fn iter(&self) -> impl Iterator<Item = Result<Val>> + '_ {61 self.inner62 .iter()63 .skip(self.from as usize)64 .take((self.to - self.from) as usize)65 .step_by(self.step as usize)66 }6768 #[cfg(not(feature = "nightly"))]69 fn iter_lazy(&self) -> impl Iterator<Item = Thunk<Val>> + '_ {70 self.inner71 .iter_lazy()72 .skip(self.from as usize)73 .take((self.to - self.from) as usize)74 .step_by(self.step as usize)75 }7677 #[cfg(not(feature = "nightly"))]78 fn iter_cheap(&self) -> Option<impl ArrayLikeIter<Val> + '_> {79 Some(80 self.inner81 .iter_cheap()?82 .skip(self.from as usize)83 .take((self.to - self.from) as usize)84 .step_by(self.step as usize),85 )86 }87}88#[cfg(feature = "nightly")]89type SliceArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;90#[cfg(feature = "nightly")]91type SliceArrayLazyIter<'t> = impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;92#[cfg(feature = "nightly")]93type SliceArrayCheapIter<'t> = impl DoubleEndedIterator<Item = Val> + ExactSizeIterator + 't;94impl ArrayLike for SliceArray {95 #[cfg(feature = "nightly")]96 type Iter<'t> = SliceArrayIter<'t>;97 #[cfg(feature = "nightly")]98 type IterLazy<'t> = SliceArrayLazyIter<'t>;99 #[cfg(feature = "nightly")]100 type IterCheap<'t> = SliceArrayCheapIter<'t>;101102 fn len(&self) -> usize {103 iter::repeat(())104 .take((self.to - self.from) as usize)105 .step_by(self.step as usize)106 .count()107 }108109 fn get(&self, index: usize) -> Result<Option<Val>> {110 self.iter().nth(index).transpose()111 }112113 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {114 self.iter_lazy().nth(index)115 }116117 fn get_cheap(&self, index: usize) -> Option<Val> {118 self.iter_cheap()?.nth(index)119 }120121 #[cfg(feature = "nightly")]122 fn iter(&self) -> SliceArrayIter<'_> {123 self.inner124 .iter()125 .skip(self.from as usize)126 .take((self.to - self.from) as usize)127 .step_by(self.step as usize)128 }129130 #[cfg(feature = "nightly")]131 fn iter_lazy(&self) -> SliceArrayLazyIter<'_> {132 self.inner133 .iter_lazy()134 .skip(self.from as usize)135 .take((self.to - self.from) as usize)136 .step_by(self.step as usize)137 }138139 #[cfg(feature = "nightly")]140 fn iter_cheap(&self) -> Option<SliceArrayCheapIter<'_>> {141 Some(142 self.inner143 .iter_cheap()?144 .skip(self.from as usize)145 .take((self.to - self.from) as usize)146 .step_by(self.step as usize),147 )148 }149}150impl From<SliceArray> for ArrValue {151 fn from(value: SliceArray) -> Self {152 Self::Slice(Cc::new(value))153 }154}155156#[derive(Trace, Debug, Clone)]157pub struct BytesArray(pub IBytes);158#[cfg(feature = "nightly")]159type BytesArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;160#[cfg(feature = "nightly")]161type BytesArrayLazyIter<'t> = impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;162#[cfg(feature = "nightly")]163type BytesArrayCheapIter<'t> = impl DoubleEndedIterator<Item = Val> + ExactSizeIterator + 't;164impl ArrayLike for BytesArray {165 #[cfg(feature = "nightly")]166 type Iter<'t> = BytesArrayIter<'t>;167 #[cfg(feature = "nightly")]168 type IterLazy<'t> = BytesArrayLazyIter<'t>;169 #[cfg(feature = "nightly")]170 type IterCheap<'t> = BytesArrayCheapIter<'t>;171172 fn len(&self) -> usize {173 self.0.len()174 }175176 fn get(&self, index: usize) -> Result<Option<Val>> {177 Ok(self.get_cheap(index))178 }179180 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {181 self.get_cheap(index).map(Thunk::evaluated)182 }183184 fn get_cheap(&self, index: usize) -> Option<Val> {185 self.0.get(index).map(|v| Val::Num(f64::from(*v)))186 }187188 #[cfg(feature = "nightly")]189 fn iter(&self) -> BytesArrayIter<'_> {190 self.0.iter().map(|v| Ok(Val::Num(f64::from(*v))))191 }192193 #[cfg(feature = "nightly")]194 fn iter_lazy(&self) -> BytesArrayLazyIter<'_> {195 self.0196 .iter()197 .map(|v| Thunk::evaluated(Val::Num(f64::from(*v))))198 }199200 #[cfg(feature = "nightly")]201 fn iter_cheap(&self) -> Option<BytesArrayCheapIter<'_>> {202 Some(self.0.iter().map(|v| Val::Num(f64::from(*v))))203 }204}205impl From<BytesArray> for ArrValue {206 fn from(value: BytesArray) -> Self {207 ArrValue::Bytes(value)208 }209}210211#[derive(Debug, Trace, Clone)]212enum ArrayThunk<T: 'static + Trace> {213 Computed(Val),214 Errored(Error),215 Waiting(T),216 Pending,217}218219#[derive(Debug, Trace)]220pub struct ExprArrayInner {221 ctx: Context,222 cached: RefCell<Vec<ArrayThunk<LocExpr>>>,223}224#[derive(Debug, Trace, Clone)]225pub struct ExprArray(pub Cc<ExprArrayInner>);226impl ExprArray {227 pub fn new(ctx: Context, items: impl IntoIterator<Item = LocExpr>) -> Self {228 Self(Cc::new(ExprArrayInner {229 ctx,230 cached: RefCell::new(items.into_iter().map(ArrayThunk::Waiting).collect()),231 }))232 }233}234#[cfg(feature = "nightly")]235type ExprArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;236#[cfg(feature = "nightly")]237type ExprArrayLazyIter<'t> = impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;238#[cfg(feature = "nightly")]239type ExprArrayCheapIter<'t> = iter::Empty<Val>;240impl ArrayLike for ExprArray {241 #[cfg(feature = "nightly")]242 type Iter<'t> = ExprArrayIter<'t>;243 #[cfg(feature = "nightly")]244 type IterLazy<'t> = ExprArrayLazyIter<'t>;245 #[cfg(feature = "nightly")]246 type IterCheap<'t> = ExprArrayCheapIter<'t>;247248 fn len(&self) -> usize {249 self.0.cached.borrow().len()250 }251 fn get(&self, index: usize) -> Result<Option<Val>> {252 if index >= self.len() {253 return Ok(None);254 }255 match &self.0.cached.borrow()[index] {256 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),257 ArrayThunk::Errored(e) => return Err(e.clone()),258 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),259 ArrayThunk::Waiting(..) => {}260 };261262 let ArrayThunk::Waiting(expr) = replace(&mut self.0.cached.borrow_mut()[index], ArrayThunk::Pending) else {263 unreachable!()264 };265266 let new_value = match evaluate(self.0.ctx.clone(), &expr) {267 Ok(v) => v,268 Err(e) => {269 self.0.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());270 return Err(e);271 }272 };273 self.0.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());274 Ok(Some(new_value))275 }276 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {277 #[derive(Trace)]278 struct ArrayElement {279 arr_thunk: ExprArray,280 index: usize,281 }282283 impl ThunkValue for ArrayElement {284 type Output = Val;285286 fn get(self: Box<Self>) -> Result<Self::Output> {287 self.arr_thunk288 .get(self.index)289 .transpose()290 .expect("index checked")291 }292 }293294 if index >= self.len() {295 return None;296 }297 match &self.0.cached.borrow()[index] {298 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),299 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),300 ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}301 };302303 Some(Thunk::new(tb!(ArrayElement {304 arr_thunk: self.clone(),305 index,306 })))307 }308 fn get_cheap(&self, _index: usize) -> Option<Val> {309 None310 }311312 #[cfg(feature = "nightly")]313 fn iter(&self) -> ExprArrayIter<'_> {314 (0..self.len()).map(|i| self.get(i).transpose().expect("index checked"))315 }316 #[cfg(feature = "nightly")]317 fn iter_lazy(&self) -> ExprArrayLazyIter<'_> {318 (0..self.len()).map(|i| self.get_lazy(i).expect("index checked"))319 }320 #[cfg(feature = "nightly")]321 fn iter_cheap(&self) -> Option<Self::IterCheap<'_>> {322 None323 }324}325impl From<ExprArray> for ArrValue {326 fn from(value: ExprArray) -> Self {327 Self::Expr(value)328 }329}330331#[derive(Trace, Debug, Clone)]332pub struct ExtendedArray {333 pub a: ArrValue,334 pub b: ArrValue,335 split: usize,336 len: usize,337}338#[cfg(feature = "nightly")]339340type ExtendedArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;341#[cfg(feature = "nightly")]342type ExtendedArrayLazyIter<'t> =343 impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;344#[cfg(feature = "nightly")]345type ExtendedArrayCheapIter<'t> = impl DoubleEndedIterator<Item = Val> + ExactSizeIterator + 't;346impl ExtendedArray {347 pub fn new(a: ArrValue, b: ArrValue) -> Self {348 let a_len = a.len();349 let b_len = b.len();350 Self {351 a,352 b,353 split: a_len,354 len: a_len.checked_add(b_len).expect("too large array value"),355 }356 }357}358359struct WithExactSize<I>(I, usize);360impl<I, T> Iterator for WithExactSize<I>361where362 I: Iterator<Item = T>,363{364 type Item = T;365366 fn next(&mut self) -> Option<Self::Item> {367 self.0.next()368 }369 fn nth(&mut self, n: usize) -> Option<Self::Item> {370 self.0.nth(n)371 }372 fn size_hint(&self) -> (usize, Option<usize>) {373 (self.1, Some(self.1))374 }375}376impl<I> DoubleEndedIterator for WithExactSize<I>377where378 I: DoubleEndedIterator,379{380 fn next_back(&mut self) -> Option<Self::Item> {381 self.0.next_back()382 }383 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {384 self.0.nth_back(n)385 }386}387impl<I> ExactSizeIterator for WithExactSize<I>388where389 I: Iterator,390{391 fn len(&self) -> usize {392 self.1393 }394}395impl ArrayLike for ExtendedArray {396 #[cfg(feature = "nightly")]397 type Iter<'t> = ExtendedArrayIter<'t>;398 #[cfg(feature = "nightly")]399 type IterLazy<'t> = ExtendedArrayLazyIter<'t>;400 #[cfg(feature = "nightly")]401 type IterCheap<'t> = ExtendedArrayCheapIter<'t>;402403 fn get(&self, index: usize) -> Result<Option<Val>> {404 if self.split > index {405 self.a.get(index)406 } else {407 self.b.get(index - self.split)408 }409 }410 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {411 if self.split > index {412 self.a.get_lazy(index)413 } else {414 self.b.get_lazy(index - self.split)415 }416 }417418 fn len(&self) -> usize {419 self.len420 }421422 fn get_cheap(&self, index: usize) -> Option<Val> {423 if self.split > index {424 self.a.get_cheap(index)425 } else {426 self.b.get_cheap(index - self.split)427 }428 }429430 #[cfg(feature = "nightly")]431 fn iter(&self) -> ExtendedArrayIter<'_> {432 WithExactSize(self.a.iter().chain(self.b.iter()), self.len)433 }434 #[cfg(feature = "nightly")]435 fn iter_lazy(&self) -> ExtendedArrayLazyIter<'_> {436 WithExactSize(self.a.iter_lazy().chain(self.b.iter_lazy()), self.len)437 }438 #[cfg(feature = "nightly")]439 fn iter_cheap(&self) -> Option<ExtendedArrayCheapIter<'_>> {440 let a = self.a.iter_cheap()?;441 let b = self.b.iter_cheap()?;442 Some(WithExactSize(a.chain(b), self.len))443 }444}445impl From<ExtendedArray> for ArrValue {446 fn from(value: ExtendedArray) -> Self {447 Self::Extended(Cc::new(value))448 }449}450451#[derive(Trace, Debug, Clone)]452pub struct LazyArray(pub Cc<Vec<Thunk<Val>>>);453#[cfg(feature = "nightly")]454type LazyArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;455#[cfg(feature = "nightly")]456type LazyArrayLazyIter<'t> = impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;457#[cfg(feature = "nightly")]458type LazyArrayCheapIter<'t> = iter::Empty<Val>;459impl ArrayLike for LazyArray {460 #[cfg(feature = "nightly")]461 type Iter<'t> = LazyArrayIter<'t>;462463 #[cfg(feature = "nightly")]464 type IterLazy<'t> = LazyArrayLazyIter<'t>;465466 #[cfg(feature = "nightly")]467 type IterCheap<'t> = LazyArrayCheapIter<'t>;468469 fn len(&self) -> usize {470 self.0.len()471 }472 fn get(&self, index: usize) -> Result<Option<Val>> {473 let Some(v) = self.0.get(index) else {474 return Ok(None);475 };476 v.evaluate().map(Some)477 }478 fn get_cheap(&self, _index: usize) -> Option<Val> {479 None480 }481 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {482 self.0.get(index).cloned()483 }484 #[cfg(feature = "nightly")]485 fn iter(&self) -> LazyArrayIter<'_> {486 self.0.iter().map(Thunk::evaluate)487 }488 #[cfg(feature = "nightly")]489 fn iter_lazy(&self) -> LazyArrayLazyIter<'_> {490 self.0.iter().cloned()491 }492 #[cfg(feature = "nightly")]493 fn iter_cheap(&self) -> Option<LazyArrayCheapIter<'_>> {494 None495 }496}497impl From<LazyArray> for ArrValue {498 fn from(value: LazyArray) -> Self {499 Self::Lazy(value)500 }501}502503#[derive(Trace, Debug, Clone)]504pub struct EagerArray(pub Cc<Vec<Val>>);505#[cfg(feature = "nightly")]506type EagerArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;507#[cfg(feature = "nightly")]508type EagerArrayLazyIter<'t> = impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;509#[cfg(feature = "nightly")]510type EagerArrayCheapIter<'t> = impl DoubleEndedIterator<Item = Val> + ExactSizeIterator + 't;511impl ArrayLike for EagerArray {512 #[cfg(feature = "nightly")]513 type Iter<'t> = EagerArrayIter<'t>;514515 #[cfg(feature = "nightly")]516 type IterLazy<'t> = EagerArrayLazyIter<'t>;517518 #[cfg(feature = "nightly")]519 type IterCheap<'t> = EagerArrayCheapIter<'t>;520521 fn len(&self) -> usize {522 self.0.len()523 }524525 fn get(&self, index: usize) -> Result<Option<Val>> {526 Ok(self.0.get(index).cloned())527 }528529 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {530 self.0.get(index).cloned().map(Thunk::evaluated)531 }532533 fn get_cheap(&self, index: usize) -> Option<Val> {534 self.0.get(index).cloned()535 }536537 #[cfg(feature = "nightly")]538 fn iter(&self) -> EagerArrayIter<'_> {539 self.0.iter().cloned().map(Ok)540 }541542 #[cfg(feature = "nightly")]543 fn iter_lazy(&self) -> EagerArrayLazyIter<'_> {544 self.0.iter().cloned().map(Thunk::evaluated)545 }546547 #[cfg(feature = "nightly")]548 fn iter_cheap(&self) -> Option<EagerArrayCheapIter<'_>> {549 Some(self.0.iter().cloned())550 }551}552impl From<EagerArray> for ArrValue {553 fn from(value: EagerArray) -> Self {554 Self::Eager(value)555 }556}557558/// Inclusive range type559#[derive(Debug, Trace, Clone, PartialEq, Eq)]560pub struct RangeArray {561 start: i32,562 end: i32,563}564impl RangeArray {565 pub fn empty() -> Self {566 Self::new_exclusive(0, 0)567 }568 pub fn new_exclusive(start: i32, end: i32) -> Self {569 end.checked_sub(1)570 .map_or_else(Self::empty, |end| Self { start, end })571 }572 pub fn new_inclusive(start: i32, end: i32) -> Self {573 Self { start, end }574 }575 fn range(&self) -> impl Iterator<Item = i32> + ExactSizeIterator + DoubleEndedIterator {576 WithExactSize(577 self.start..=self.end,578 (self.end as usize)579 .wrapping_sub(self.start as usize)580 .wrapping_add(1),581 )582 }583}584585#[cfg(feature = "nightly")]586type RangeArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;587#[cfg(feature = "nightly")]588type RangeArrayLazyIter<'t> = impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;589#[cfg(feature = "nightly")]590type RangeArrayCheapIter<'t> = impl DoubleEndedIterator<Item = Val> + ExactSizeIterator + 't;591impl ArrayLike for RangeArray {592 #[cfg(feature = "nightly")]593 type Iter<'t> = RangeArrayIter<'t>;594595 #[cfg(feature = "nightly")]596 type IterLazy<'t> = RangeArrayLazyIter<'t>;597598 #[cfg(feature = "nightly")]599 type IterCheap<'t> = RangeArrayCheapIter<'t>;600601 fn len(&self) -> usize {602 self.range().len()603 }604 fn is_empty(&self) -> bool {605 self.range().len() == 0606 }607608 fn get(&self, index: usize) -> Result<Option<Val>> {609 Ok(self.get_cheap(index))610 }611612 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {613 self.get_cheap(index).map(Thunk::evaluated)614 }615616 fn get_cheap(&self, index: usize) -> Option<Val> {617 self.range().nth(index).map(|i| Val::Num(f64::from(i)))618 }619620 #[cfg(feature = "nightly")]621 fn iter(&self) -> RangeArrayIter<'_> {622 self.range().map(|i| Ok(Val::Num(f64::from(i))))623 }624625 #[cfg(feature = "nightly")]626 fn iter_lazy(&self) -> RangeArrayLazyIter<'_> {627 self.range()628 .map(|i| Thunk::evaluated(Val::Num(f64::from(i))))629 }630631 #[cfg(feature = "nightly")]632 fn iter_cheap(&self) -> Option<RangeArrayCheapIter<'_>> {633 Some(self.range().map(|i| Val::Num(f64::from(i))))634 }635}636impl From<RangeArray> for ArrValue {637 fn from(value: RangeArray) -> Self {638 Self::Range(value)639 }640}641642#[derive(Debug, Trace, Clone)]643pub struct ReverseArray(pub ArrValue);644impl ArrayLike for ReverseArray {645 #[cfg(feature = "nightly")]646 type Iter<'t> = iter::Rev<UnknownArrayIter<'t>>;647648 #[cfg(feature = "nightly")]649 type IterLazy<'t> = iter::Rev<UnknownArrayIterLazy<'t>>;650651 #[cfg(feature = "nightly")]652 type IterCheap<'t> = iter::Rev<UnknownArrayIterCheap<'t>>;653654 fn len(&self) -> usize {655 self.0.len()656 }657658 fn get(&self, index: usize) -> Result<Option<Val>> {659 self.0.get(self.0.len() - index - 1)660 }661662 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {663 self.0.get_lazy(self.0.len() - index - 1)664 }665666 fn get_cheap(&self, index: usize) -> Option<Val> {667 self.0.get_cheap(self.0.len() - index - 1)668 }669670 #[cfg(feature = "nightly")]671 fn iter(&self) -> iter::Rev<UnknownArrayIter<'_>> {672 self.0.iter().rev()673 }674675 #[cfg(feature = "nightly")]676 fn iter_lazy(&self) -> iter::Rev<UnknownArrayIterLazy<'_>> {677 self.0.iter_lazy().rev()678 }679680 #[cfg(feature = "nightly")]681 fn iter_cheap(&self) -> Option<iter::Rev<UnknownArrayIterCheap<'_>>> {682 Some(self.0.iter_cheap()?.rev())683 }684 fn reverse(self) -> ArrValue {685 self.0686 }687}688impl From<ReverseArray> for ArrValue {689 fn from(value: ReverseArray) -> Self {690 Self::Reverse(Cc::new(value))691 }692}693694#[derive(Trace, Debug)]695pub struct MappedArrayInner {696 inner: ArrValue,697 cached: RefCell<Vec<ArrayThunk<()>>>,698 mapper: FuncVal,699}700#[derive(Trace, Debug, Clone)]701pub struct MappedArray(Cc<MappedArrayInner>);702impl MappedArray {703 pub fn new(inner: ArrValue, mapper: FuncVal) -> Self {704 let len = inner.len();705 Self(Cc::new(MappedArrayInner {706 inner,707 cached: RefCell::new(vec![ArrayThunk::Waiting(()); len]),708 mapper,709 }))710 }711}712#[cfg(feature = "nightly")]713type MappedArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;714#[cfg(feature = "nightly")]715type MappedArrayLazyIter<'t> = impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;716#[cfg(feature = "nightly")]717type MappedArrayCheapIter<'t> = iter::Empty<Val>;718impl ArrayLike for MappedArray {719 #[cfg(feature = "nightly")]720 type Iter<'t> = MappedArrayIter<'t>;721 #[cfg(feature = "nightly")]722 type IterLazy<'t> = MappedArrayLazyIter<'t>;723 #[cfg(feature = "nightly")]724 type IterCheap<'t> = MappedArrayCheapIter<'t>;725726 fn len(&self) -> usize {727 self.0.cached.borrow().len()728 }729730 fn get(&self, index: usize) -> Result<Option<Val>> {731 if index >= self.len() {732 return Ok(None);733 }734 match &self.0.cached.borrow()[index] {735 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),736 ArrayThunk::Errored(e) => return Err(e.clone()),737 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),738 ArrayThunk::Waiting(..) => {}739 };740741 let ArrayThunk::Waiting(_) = replace(&mut self.0.cached.borrow_mut()[index], ArrayThunk::Pending) else {742 unreachable!()743 };744745 let val = self746 .0747 .inner748 .get(index)749 .transpose()750 .expect("index checked")751 .and_then(|r| self.0.mapper.evaluate_simple(&(Any(r),)));752753 let new_value = match val {754 Ok(v) => v,755 Err(e) => {756 self.0.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());757 return Err(e);758 }759 };760 self.0.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());761 Ok(Some(new_value))762 }763 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {764 #[derive(Trace)]765 struct ArrayElement {766 arr_thunk: MappedArray,767 index: usize,768 }769770 impl ThunkValue for ArrayElement {771 type Output = Val;772773 fn get(self: Box<Self>) -> Result<Self::Output> {774 self.arr_thunk775 .get(self.index)776 .transpose()777 .expect("index checked")778 }779 }780781 if index >= self.len() {782 return None;783 }784 match &self.0.cached.borrow()[index] {785 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),786 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),787 ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}788 };789790 Some(Thunk::new(tb!(ArrayElement {791 arr_thunk: self.clone(),792 index,793 })))794 }795796 fn get_cheap(&self, _index: usize) -> Option<Val> {797 None798 }799800 #[cfg(feature = "nightly")]801 fn iter(&self) -> MappedArrayIter<'_> {802 (0..self.len()).map(|i| self.get(i).transpose().expect("length checked"))803 }804805 #[cfg(feature = "nightly")]806 fn iter_lazy(&self) -> MappedArrayLazyIter<'_> {807 (0..self.len()).map(|i| self.get_lazy(i).expect("length checked"))808 }809810 #[cfg(feature = "nightly")]811 fn iter_cheap(&self) -> Option<Self::IterCheap<'_>> {812 None813 }814}815impl From<MappedArray> for ArrValue {816 fn from(value: MappedArray) -> Self {817 Self::Mapped(value)818 }819}820821#[derive(Trace, Debug)]822pub struct RepeatedArrayInner {823 data: ArrValue,824 repeats: usize,825 total_len: usize,826}827#[derive(Trace, Debug, Clone)]828pub struct RepeatedArray(Cc<RepeatedArrayInner>);829impl RepeatedArray {830 pub fn new(data: ArrValue, repeats: usize) -> Option<Self> {831 let total_len = data.len().checked_mul(repeats)?;832 Some(Self(Cc::new(RepeatedArrayInner {833 data,834 repeats,835 total_len,836 })))837 }838 pub fn is_cheap(&self) -> bool {839 self.0.data.is_cheap()840 }841}842843#[cfg(feature = "nightly")]844type RepeatedArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;845#[cfg(feature = "nightly")]846type RepeatedArrayLazyIter<'t> =847 impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;848#[cfg(feature = "nightly")]849type RepeatedArrayCheapIter<'t> = impl DoubleEndedIterator<Item = Val> + ExactSizeIterator + 't;850impl ArrayLike for RepeatedArray {851 #[cfg(feature = "nightly")]852 type Iter<'t> = RepeatedArrayIter<'t>;853 #[cfg(feature = "nightly")]854 type IterLazy<'t> = RepeatedArrayLazyIter<'t>;855 #[cfg(feature = "nightly")]856 type IterCheap<'t> = RepeatedArrayCheapIter<'t>;857858 fn len(&self) -> usize {859 self.0.total_len860 }861862 fn get(&self, index: usize) -> Result<Option<Val>> {863 if index > self.0.total_len {864 return Ok(None);865 }866 self.0.data.get(index % self.0.data.len())867 }868869 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {870 if index > self.0.total_len {871 return None;872 }873 self.0.data.get_lazy(index % self.0.data.len())874 }875876 fn get_cheap(&self, index: usize) -> Option<Val> {877 if index > self.0.total_len {878 return None;879 }880 self.0.data.get_cheap(index % self.0.data.len())881 }882883 #[cfg(feature = "nightly")]884 fn iter(&self) -> RepeatedArrayIter<'_> {885 (0..self.0.total_len)886 .map(|i| self.get(i))887 .map(Result::transpose)888 .map(Option::unwrap)889 }890891 #[cfg(feature = "nightly")]892 fn iter_lazy(&self) -> RepeatedArrayLazyIter<'_> {893 (0..self.0.total_len)894 .map(|i| self.get_lazy(i))895 .map(Option::unwrap)896 }897898 #[cfg(feature = "nightly")]899 fn iter_cheap(&self) -> Option<RepeatedArrayCheapIter<'_>> {900 if !self.0.data.is_cheap() {901 return None;902 }903 Some(904 (0..self.0.total_len)905 .map(|i| self.get_cheap(i))906 .map(Option::unwrap),907 )908 }909}910impl From<RepeatedArray> for ArrValue {911 fn from(value: RepeatedArray) -> Self {912 Self::Repeated(value)913 }914}915916#[cfg(feature = "nightly")]917macro_rules! impl_iter_enum {918 ($n:ident => $v:ident) => {919 pub enum $n<'t> {920 Bytes(<BytesArray as ArrayLike>::$v<'t>),921 Expr(<ExprArray as ArrayLike>::$v<'t>),922 Lazy(<LazyArray as ArrayLike>::$v<'t>),923 Eager(<EagerArray as ArrayLike>::$v<'t>),924 Range(<RangeArray as ArrayLike>::$v<'t>),925 Slice(Box<<SliceArray as ArrayLike>::$v<'t>>),926 Extended(Box<<ExtendedArray as ArrayLike>::$v<'t>>),927 Reverse(Box<<ReverseArray as ArrayLike>::$v<'t>>),928 Mapped(Box<<MappedArray as ArrayLike>::$v<'t>>),929 Repeated(Box<<RepeatedArray as ArrayLike>::$v<'t>>),930 }931 };932}933934macro_rules! pass {935 ($t:ident.$m:ident($($ident:ident),*)) => {936 match $t {937 Self::Bytes(e) => e.$m($($ident)*),938 Self::Expr(e) => e.$m($($ident)*),939 Self::Lazy(e) => e.$m($($ident)*),940 Self::Eager(e) => e.$m($($ident)*),941 Self::Range(e) => e.$m($($ident)*),942 Self::Slice(e) => e.$m($($ident)*),943 Self::Extended(e) => e.$m($($ident)*),944 Self::Reverse(e) => e.$m($($ident)*),945 Self::Mapped(e) => e.$m($($ident)*),946 Self::Repeated(e) => e.$m($($ident)*),947 }948 };949}950pub(super) use pass;951952#[cfg(feature = "nightly")]953macro_rules! pass_iter_call {954 ($t:ident.$c:ident $(in $wrap:ident)? => $e:ident) => {955 match $t {956 ArrValue::Bytes(e) => $e::Bytes($($wrap!)?(e.$c())),957 ArrValue::Lazy(e) => $e::Lazy($($wrap!)?(e.$c())),958 ArrValue::Expr(e) => $e::Expr($($wrap!)?(e.$c())),959 ArrValue::Eager(e) => $e::Eager($($wrap!)?(e.$c())),960 ArrValue::Range(e) => $e::Range($($wrap!)?(e.$c())),961 ArrValue::Slice(e) => $e::Slice(Box::new($($wrap!)?(e.$c()))),962 ArrValue::Extended(e) => $e::Extended(Box::new($($wrap!)?(e.$c()))),963 ArrValue::Reverse(e) => $e::Reverse(Box::new($($wrap!)?(e.$c()))),964 ArrValue::Mapped(e) => $e::Mapped(Box::new($($wrap!)?(e.$c()))),965 ArrValue::Repeated(e) => $e::Repeated(Box::new($($wrap!)?(e.$c()))),966 }967 };968}969#[cfg(feature = "nightly")]970pub(super) use pass_iter_call;971972#[cfg(feature = "nightly")]973macro_rules! impl_iter {974 ($t:ident => $out:ty) => {975 impl Iterator for $t<'_> {976 type Item = $out;977978 fn next(&mut self) -> Option<Self::Item> {979 pass!(self.next())980 }981 fn nth(&mut self, count: usize) -> Option<Self::Item> {982 pass!(self.nth(count))983 }984 fn size_hint(&self) -> (usize, Option<usize>) {985 pass!(self.size_hint())986 }987 }988 impl DoubleEndedIterator for $t<'_> {989 fn next_back(&mut self) -> Option<Self::Item> {990 pass!(self.next_back())991 }992 fn nth_back(&mut self, count: usize) -> Option<Self::Item> {993 pass!(self.nth_back(count))994 }995 }996 impl ExactSizeIterator for $t<'_> {997 fn len(&self) -> usize {998 match self {999 Self::Bytes(e) => e.len(),1000 Self::Expr(e) => e.len(),1001 Self::Lazy(e) => e.len(),1002 Self::Eager(e) => e.len(),1003 Self::Range(e) => e.len(),1004 Self::Slice(e) => e.len(),1005 Self::Extended(e) => {1006 e.size_hint().1.expect("overflow is checked in constructor")1007 }1008 Self::Reverse(e) => e.len(),1009 Self::Mapped(e) => e.len(),1010 Self::Repeated(e) => e.len(),1011 }1012 }1013 }1014 };1015}10161017#[cfg(feature = "nightly")]1018impl_iter_enum!(UnknownArrayIter => Iter);1019#[cfg(feature = "nightly")]1020impl_iter!(UnknownArrayIter => Result<Val>);1021#[cfg(feature = "nightly")]1022impl_iter_enum!(UnknownArrayIterLazy => IterLazy);1023#[cfg(feature = "nightly")]1024impl_iter!(UnknownArrayIterLazy => Thunk<Val>);1025#[cfg(feature = "nightly")]1026impl_iter_enum!(UnknownArrayIterCheap => IterCheap);1027#[cfg(feature = "nightly")]1028impl_iter!(UnknownArrayIterCheap => Val);1//! Those implementations are a bit sketchy, as this is mostly performance experiments2//! of not yet finished nightly rust features34use std::{cell::RefCell, iter, mem::replace};56use jrsonnet_gcmodule::{Cc, Trace};7use jrsonnet_interner::IBytes;8use jrsonnet_parser::LocExpr;910use super::ArrValue;11use crate::{12 error::ErrorKind::InfiniteRecursionDetected, evaluate, function::FuncVal, val::ThunkValue,13 Context, Error, Result, Thunk, Val,14};1516pub trait ArrayLike: Sized + Into<ArrValue> {17 #[cfg(feature = "nightly")]18 type Iter<'t>19 where20 Self: 't;21 #[cfg(feature = "nightly")]22 type IterLazy<'t>23 where24 Self: 't;25 #[cfg(feature = "nightly")]26 type IterCheap<'t>27 where28 Self: 't;2930 fn len(&self) -> usize;31 fn is_empty(&self) -> bool {32 self.len() == 033 }34 fn get(&self, index: usize) -> Result<Option<Val>>;35 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>>;36 fn get_cheap(&self, index: usize) -> Option<Val>;37 #[cfg(feature = "nightly")]38 #[allow(clippy::iter_not_returning_iterator)]39 fn iter(&self) -> Self::Iter<'_>;40 #[cfg(feature = "nightly")]41 fn iter_lazy(&self) -> Self::IterLazy<'_>;42 #[cfg(feature = "nightly")]43 fn iter_cheap(&self) -> Option<Self::IterCheap<'_>>;4445 fn reverse(self) -> ArrValue {46 ArrValue::Reverse(Cc::new(ReverseArray(self.into())))47 }48}4950#[derive(Debug, Clone, Trace)]51pub struct SliceArray {52 pub(crate) inner: ArrValue,53 pub(crate) from: u32,54 pub(crate) to: u32,55 pub(crate) step: u32,56}5758impl SliceArray {59 #[cfg(not(feature = "nightly"))]60 fn iter(&self) -> impl Iterator<Item = Result<Val>> + '_ {61 self.inner62 .iter()63 .skip(self.from as usize)64 .take((self.to - self.from) as usize)65 .step_by(self.step as usize)66 }6768 #[cfg(not(feature = "nightly"))]69 fn iter_lazy(&self) -> impl Iterator<Item = Thunk<Val>> + '_ {70 self.inner71 .iter_lazy()72 .skip(self.from as usize)73 .take((self.to - self.from) as usize)74 .step_by(self.step as usize)75 }7677 #[cfg(not(feature = "nightly"))]78 fn iter_cheap(&self) -> Option<impl crate::arr::ArrayLikeIter<Val> + '_> {79 Some(80 self.inner81 .iter_cheap()?82 .skip(self.from as usize)83 .take((self.to - self.from) as usize)84 .step_by(self.step as usize),85 )86 }87}88#[cfg(feature = "nightly")]89type SliceArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;90#[cfg(feature = "nightly")]91type SliceArrayLazyIter<'t> = impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;92#[cfg(feature = "nightly")]93type SliceArrayCheapIter<'t> = impl DoubleEndedIterator<Item = Val> + ExactSizeIterator + 't;94impl ArrayLike for SliceArray {95 #[cfg(feature = "nightly")]96 type Iter<'t> = SliceArrayIter<'t>;97 #[cfg(feature = "nightly")]98 type IterLazy<'t> = SliceArrayLazyIter<'t>;99 #[cfg(feature = "nightly")]100 type IterCheap<'t> = SliceArrayCheapIter<'t>;101102 fn len(&self) -> usize {103 iter::repeat(())104 .take((self.to - self.from) as usize)105 .step_by(self.step as usize)106 .count()107 }108109 fn get(&self, index: usize) -> Result<Option<Val>> {110 self.iter().nth(index).transpose()111 }112113 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {114 self.iter_lazy().nth(index)115 }116117 fn get_cheap(&self, index: usize) -> Option<Val> {118 self.iter_cheap()?.nth(index)119 }120121 #[cfg(feature = "nightly")]122 fn iter(&self) -> SliceArrayIter<'_> {123 self.inner124 .iter()125 .skip(self.from as usize)126 .take((self.to - self.from) as usize)127 .step_by(self.step as usize)128 }129130 #[cfg(feature = "nightly")]131 fn iter_lazy(&self) -> SliceArrayLazyIter<'_> {132 self.inner133 .iter_lazy()134 .skip(self.from as usize)135 .take((self.to - self.from) as usize)136 .step_by(self.step as usize)137 }138139 #[cfg(feature = "nightly")]140 fn iter_cheap(&self) -> Option<SliceArrayCheapIter<'_>> {141 Some(142 self.inner143 .iter_cheap()?144 .skip(self.from as usize)145 .take((self.to - self.from) as usize)146 .step_by(self.step as usize),147 )148 }149}150impl From<SliceArray> for ArrValue {151 fn from(value: SliceArray) -> Self {152 Self::Slice(Cc::new(value))153 }154}155156#[derive(Trace, Debug, Clone)]157pub struct BytesArray(pub IBytes);158#[cfg(feature = "nightly")]159type BytesArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;160#[cfg(feature = "nightly")]161type BytesArrayLazyIter<'t> = impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;162#[cfg(feature = "nightly")]163type BytesArrayCheapIter<'t> = impl DoubleEndedIterator<Item = Val> + ExactSizeIterator + 't;164impl ArrayLike for BytesArray {165 #[cfg(feature = "nightly")]166 type Iter<'t> = BytesArrayIter<'t>;167 #[cfg(feature = "nightly")]168 type IterLazy<'t> = BytesArrayLazyIter<'t>;169 #[cfg(feature = "nightly")]170 type IterCheap<'t> = BytesArrayCheapIter<'t>;171172 fn len(&self) -> usize {173 self.0.len()174 }175176 fn get(&self, index: usize) -> Result<Option<Val>> {177 Ok(self.get_cheap(index))178 }179180 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {181 self.get_cheap(index).map(Thunk::evaluated)182 }183184 fn get_cheap(&self, index: usize) -> Option<Val> {185 self.0.get(index).map(|v| Val::Num(f64::from(*v)))186 }187188 #[cfg(feature = "nightly")]189 fn iter(&self) -> BytesArrayIter<'_> {190 self.0.iter().map(|v| Ok(Val::Num(f64::from(*v))))191 }192193 #[cfg(feature = "nightly")]194 fn iter_lazy(&self) -> BytesArrayLazyIter<'_> {195 self.0196 .iter()197 .map(|v| Thunk::evaluated(Val::Num(f64::from(*v))))198 }199200 #[cfg(feature = "nightly")]201 fn iter_cheap(&self) -> Option<BytesArrayCheapIter<'_>> {202 Some(self.0.iter().map(|v| Val::Num(f64::from(*v))))203 }204}205impl From<BytesArray> for ArrValue {206 fn from(value: BytesArray) -> Self {207 ArrValue::Bytes(value)208 }209}210211#[derive(Debug, Trace, Clone)]212enum ArrayThunk<T: 'static + Trace> {213 Computed(Val),214 Errored(Error),215 Waiting(T),216 Pending,217}218219#[derive(Debug, Trace)]220pub struct ExprArrayInner {221 ctx: Context,222 cached: RefCell<Vec<ArrayThunk<LocExpr>>>,223}224#[derive(Debug, Trace, Clone)]225pub struct ExprArray(pub Cc<ExprArrayInner>);226impl ExprArray {227 pub fn new(ctx: Context, items: impl IntoIterator<Item = LocExpr>) -> Self {228 Self(Cc::new(ExprArrayInner {229 ctx,230 cached: RefCell::new(items.into_iter().map(ArrayThunk::Waiting).collect()),231 }))232 }233}234#[cfg(feature = "nightly")]235type ExprArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;236#[cfg(feature = "nightly")]237type ExprArrayLazyIter<'t> = impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;238#[cfg(feature = "nightly")]239type ExprArrayCheapIter<'t> = iter::Empty<Val>;240impl ArrayLike for ExprArray {241 #[cfg(feature = "nightly")]242 type Iter<'t> = ExprArrayIter<'t>;243 #[cfg(feature = "nightly")]244 type IterLazy<'t> = ExprArrayLazyIter<'t>;245 #[cfg(feature = "nightly")]246 type IterCheap<'t> = ExprArrayCheapIter<'t>;247248 fn len(&self) -> usize {249 self.0.cached.borrow().len()250 }251 fn get(&self, index: usize) -> Result<Option<Val>> {252 if index >= self.len() {253 return Ok(None);254 }255 match &self.0.cached.borrow()[index] {256 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),257 ArrayThunk::Errored(e) => return Err(e.clone()),258 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),259 ArrayThunk::Waiting(..) => {}260 };261262 let ArrayThunk::Waiting(expr) = replace(&mut self.0.cached.borrow_mut()[index], ArrayThunk::Pending) else {263 unreachable!()264 };265266 let new_value = match evaluate(self.0.ctx.clone(), &expr) {267 Ok(v) => v,268 Err(e) => {269 self.0.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());270 return Err(e);271 }272 };273 self.0.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());274 Ok(Some(new_value))275 }276 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {277 #[derive(Trace)]278 struct ArrayElement {279 arr_thunk: ExprArray,280 index: usize,281 }282283 impl ThunkValue for ArrayElement {284 type Output = Val;285286 fn get(self: Box<Self>) -> Result<Self::Output> {287 self.arr_thunk288 .get(self.index)289 .transpose()290 .expect("index checked")291 }292 }293294 if index >= self.len() {295 return None;296 }297 match &self.0.cached.borrow()[index] {298 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),299 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),300 ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}301 };302303 Some(Thunk::new(ArrayElement {304 arr_thunk: self.clone(),305 index,306 }))307 }308 fn get_cheap(&self, _index: usize) -> Option<Val> {309 None310 }311312 #[cfg(feature = "nightly")]313 fn iter(&self) -> ExprArrayIter<'_> {314 (0..self.len()).map(|i| self.get(i).transpose().expect("index checked"))315 }316 #[cfg(feature = "nightly")]317 fn iter_lazy(&self) -> ExprArrayLazyIter<'_> {318 (0..self.len()).map(|i| self.get_lazy(i).expect("index checked"))319 }320 #[cfg(feature = "nightly")]321 fn iter_cheap(&self) -> Option<Self::IterCheap<'_>> {322 None323 }324}325impl From<ExprArray> for ArrValue {326 fn from(value: ExprArray) -> Self {327 Self::Expr(value)328 }329}330331#[derive(Trace, Debug, Clone)]332pub struct ExtendedArray {333 pub a: ArrValue,334 pub b: ArrValue,335 split: usize,336 len: usize,337}338#[cfg(feature = "nightly")]339340type ExtendedArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;341#[cfg(feature = "nightly")]342type ExtendedArrayLazyIter<'t> =343 impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;344#[cfg(feature = "nightly")]345type ExtendedArrayCheapIter<'t> = impl DoubleEndedIterator<Item = Val> + ExactSizeIterator + 't;346impl ExtendedArray {347 pub fn new(a: ArrValue, b: ArrValue) -> Self {348 let a_len = a.len();349 let b_len = b.len();350 Self {351 a,352 b,353 split: a_len,354 len: a_len.checked_add(b_len).expect("too large array value"),355 }356 }357}358359struct WithExactSize<I>(I, usize);360impl<I, T> Iterator for WithExactSize<I>361where362 I: Iterator<Item = T>,363{364 type Item = T;365366 fn next(&mut self) -> Option<Self::Item> {367 self.0.next()368 }369 fn nth(&mut self, n: usize) -> Option<Self::Item> {370 self.0.nth(n)371 }372 fn size_hint(&self) -> (usize, Option<usize>) {373 (self.1, Some(self.1))374 }375}376impl<I> DoubleEndedIterator for WithExactSize<I>377where378 I: DoubleEndedIterator,379{380 fn next_back(&mut self) -> Option<Self::Item> {381 self.0.next_back()382 }383 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {384 self.0.nth_back(n)385 }386}387impl<I> ExactSizeIterator for WithExactSize<I>388where389 I: Iterator,390{391 fn len(&self) -> usize {392 self.1393 }394}395impl ArrayLike for ExtendedArray {396 #[cfg(feature = "nightly")]397 type Iter<'t> = ExtendedArrayIter<'t>;398 #[cfg(feature = "nightly")]399 type IterLazy<'t> = ExtendedArrayLazyIter<'t>;400 #[cfg(feature = "nightly")]401 type IterCheap<'t> = ExtendedArrayCheapIter<'t>;402403 fn get(&self, index: usize) -> Result<Option<Val>> {404 if self.split > index {405 self.a.get(index)406 } else {407 self.b.get(index - self.split)408 }409 }410 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {411 if self.split > index {412 self.a.get_lazy(index)413 } else {414 self.b.get_lazy(index - self.split)415 }416 }417418 fn len(&self) -> usize {419 self.len420 }421422 fn get_cheap(&self, index: usize) -> Option<Val> {423 if self.split > index {424 self.a.get_cheap(index)425 } else {426 self.b.get_cheap(index - self.split)427 }428 }429430 #[cfg(feature = "nightly")]431 fn iter(&self) -> ExtendedArrayIter<'_> {432 WithExactSize(self.a.iter().chain(self.b.iter()), self.len)433 }434 #[cfg(feature = "nightly")]435 fn iter_lazy(&self) -> ExtendedArrayLazyIter<'_> {436 WithExactSize(self.a.iter_lazy().chain(self.b.iter_lazy()), self.len)437 }438 #[cfg(feature = "nightly")]439 fn iter_cheap(&self) -> Option<ExtendedArrayCheapIter<'_>> {440 let a = self.a.iter_cheap()?;441 let b = self.b.iter_cheap()?;442 Some(WithExactSize(a.chain(b), self.len))443 }444}445impl From<ExtendedArray> for ArrValue {446 fn from(value: ExtendedArray) -> Self {447 Self::Extended(Cc::new(value))448 }449}450451#[derive(Trace, Debug, Clone)]452pub struct LazyArray(pub Cc<Vec<Thunk<Val>>>);453#[cfg(feature = "nightly")]454type LazyArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;455#[cfg(feature = "nightly")]456type LazyArrayLazyIter<'t> = impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;457#[cfg(feature = "nightly")]458type LazyArrayCheapIter<'t> = iter::Empty<Val>;459impl ArrayLike for LazyArray {460 #[cfg(feature = "nightly")]461 type Iter<'t> = LazyArrayIter<'t>;462463 #[cfg(feature = "nightly")]464 type IterLazy<'t> = LazyArrayLazyIter<'t>;465466 #[cfg(feature = "nightly")]467 type IterCheap<'t> = LazyArrayCheapIter<'t>;468469 fn len(&self) -> usize {470 self.0.len()471 }472 fn get(&self, index: usize) -> Result<Option<Val>> {473 let Some(v) = self.0.get(index) else {474 return Ok(None);475 };476 v.evaluate().map(Some)477 }478 fn get_cheap(&self, _index: usize) -> Option<Val> {479 None480 }481 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {482 self.0.get(index).cloned()483 }484 #[cfg(feature = "nightly")]485 fn iter(&self) -> LazyArrayIter<'_> {486 self.0.iter().map(Thunk::evaluate)487 }488 #[cfg(feature = "nightly")]489 fn iter_lazy(&self) -> LazyArrayLazyIter<'_> {490 self.0.iter().cloned()491 }492 #[cfg(feature = "nightly")]493 fn iter_cheap(&self) -> Option<LazyArrayCheapIter<'_>> {494 None495 }496}497impl From<LazyArray> for ArrValue {498 fn from(value: LazyArray) -> Self {499 Self::Lazy(value)500 }501}502503#[derive(Trace, Debug, Clone)]504pub struct EagerArray(pub Cc<Vec<Val>>);505#[cfg(feature = "nightly")]506type EagerArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;507#[cfg(feature = "nightly")]508type EagerArrayLazyIter<'t> = impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;509#[cfg(feature = "nightly")]510type EagerArrayCheapIter<'t> = impl DoubleEndedIterator<Item = Val> + ExactSizeIterator + 't;511impl ArrayLike for EagerArray {512 #[cfg(feature = "nightly")]513 type Iter<'t> = EagerArrayIter<'t>;514515 #[cfg(feature = "nightly")]516 type IterLazy<'t> = EagerArrayLazyIter<'t>;517518 #[cfg(feature = "nightly")]519 type IterCheap<'t> = EagerArrayCheapIter<'t>;520521 fn len(&self) -> usize {522 self.0.len()523 }524525 fn get(&self, index: usize) -> Result<Option<Val>> {526 Ok(self.0.get(index).cloned())527 }528529 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {530 self.0.get(index).cloned().map(Thunk::evaluated)531 }532533 fn get_cheap(&self, index: usize) -> Option<Val> {534 self.0.get(index).cloned()535 }536537 #[cfg(feature = "nightly")]538 fn iter(&self) -> EagerArrayIter<'_> {539 self.0.iter().cloned().map(Ok)540 }541542 #[cfg(feature = "nightly")]543 fn iter_lazy(&self) -> EagerArrayLazyIter<'_> {544 self.0.iter().cloned().map(Thunk::evaluated)545 }546547 #[cfg(feature = "nightly")]548 fn iter_cheap(&self) -> Option<EagerArrayCheapIter<'_>> {549 Some(self.0.iter().cloned())550 }551}552impl From<EagerArray> for ArrValue {553 fn from(value: EagerArray) -> Self {554 Self::Eager(value)555 }556}557558/// Inclusive range type559#[derive(Debug, Trace, Clone, PartialEq, Eq)]560pub struct RangeArray {561 start: i32,562 end: i32,563}564impl RangeArray {565 pub fn empty() -> Self {566 Self::new_exclusive(0, 0)567 }568 pub fn new_exclusive(start: i32, end: i32) -> Self {569 end.checked_sub(1)570 .map_or_else(Self::empty, |end| Self { start, end })571 }572 pub fn new_inclusive(start: i32, end: i32) -> Self {573 Self { start, end }574 }575 fn range(&self) -> impl Iterator<Item = i32> + ExactSizeIterator + DoubleEndedIterator {576 WithExactSize(577 self.start..=self.end,578 (self.end as usize)579 .wrapping_sub(self.start as usize)580 .wrapping_add(1),581 )582 }583}584585#[cfg(feature = "nightly")]586type RangeArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;587#[cfg(feature = "nightly")]588type RangeArrayLazyIter<'t> = impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;589#[cfg(feature = "nightly")]590type RangeArrayCheapIter<'t> = impl DoubleEndedIterator<Item = Val> + ExactSizeIterator + 't;591impl ArrayLike for RangeArray {592 #[cfg(feature = "nightly")]593 type Iter<'t> = RangeArrayIter<'t>;594595 #[cfg(feature = "nightly")]596 type IterLazy<'t> = RangeArrayLazyIter<'t>;597598 #[cfg(feature = "nightly")]599 type IterCheap<'t> = RangeArrayCheapIter<'t>;600601 fn len(&self) -> usize {602 self.range().len()603 }604 fn is_empty(&self) -> bool {605 self.range().len() == 0606 }607608 fn get(&self, index: usize) -> Result<Option<Val>> {609 Ok(self.get_cheap(index))610 }611612 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {613 self.get_cheap(index).map(Thunk::evaluated)614 }615616 fn get_cheap(&self, index: usize) -> Option<Val> {617 self.range().nth(index).map(|i| Val::Num(f64::from(i)))618 }619620 #[cfg(feature = "nightly")]621 fn iter(&self) -> RangeArrayIter<'_> {622 self.range().map(|i| Ok(Val::Num(f64::from(i))))623 }624625 #[cfg(feature = "nightly")]626 fn iter_lazy(&self) -> RangeArrayLazyIter<'_> {627 self.range()628 .map(|i| Thunk::evaluated(Val::Num(f64::from(i))))629 }630631 #[cfg(feature = "nightly")]632 fn iter_cheap(&self) -> Option<RangeArrayCheapIter<'_>> {633 Some(self.range().map(|i| Val::Num(f64::from(i))))634 }635}636impl From<RangeArray> for ArrValue {637 fn from(value: RangeArray) -> Self {638 Self::Range(value)639 }640}641642#[derive(Debug, Trace, Clone)]643pub struct ReverseArray(pub ArrValue);644impl ArrayLike for ReverseArray {645 #[cfg(feature = "nightly")]646 type Iter<'t> = iter::Rev<UnknownArrayIter<'t>>;647648 #[cfg(feature = "nightly")]649 type IterLazy<'t> = iter::Rev<UnknownArrayIterLazy<'t>>;650651 #[cfg(feature = "nightly")]652 type IterCheap<'t> = iter::Rev<UnknownArrayIterCheap<'t>>;653654 fn len(&self) -> usize {655 self.0.len()656 }657658 fn get(&self, index: usize) -> Result<Option<Val>> {659 self.0.get(self.0.len() - index - 1)660 }661662 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {663 self.0.get_lazy(self.0.len() - index - 1)664 }665666 fn get_cheap(&self, index: usize) -> Option<Val> {667 self.0.get_cheap(self.0.len() - index - 1)668 }669670 #[cfg(feature = "nightly")]671 fn iter(&self) -> iter::Rev<UnknownArrayIter<'_>> {672 self.0.iter().rev()673 }674675 #[cfg(feature = "nightly")]676 fn iter_lazy(&self) -> iter::Rev<UnknownArrayIterLazy<'_>> {677 self.0.iter_lazy().rev()678 }679680 #[cfg(feature = "nightly")]681 fn iter_cheap(&self) -> Option<iter::Rev<UnknownArrayIterCheap<'_>>> {682 Some(self.0.iter_cheap()?.rev())683 }684 fn reverse(self) -> ArrValue {685 self.0686 }687}688impl From<ReverseArray> for ArrValue {689 fn from(value: ReverseArray) -> Self {690 Self::Reverse(Cc::new(value))691 }692}693694#[derive(Trace, Debug)]695pub struct MappedArrayInner {696 inner: ArrValue,697 cached: RefCell<Vec<ArrayThunk<()>>>,698 mapper: FuncVal,699}700#[derive(Trace, Debug, Clone)]701pub struct MappedArray(Cc<MappedArrayInner>);702impl MappedArray {703 pub fn new(inner: ArrValue, mapper: FuncVal) -> Self {704 let len = inner.len();705 Self(Cc::new(MappedArrayInner {706 inner,707 cached: RefCell::new(vec![ArrayThunk::Waiting(()); len]),708 mapper,709 }))710 }711}712#[cfg(feature = "nightly")]713type MappedArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;714#[cfg(feature = "nightly")]715type MappedArrayLazyIter<'t> = impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;716#[cfg(feature = "nightly")]717type MappedArrayCheapIter<'t> = iter::Empty<Val>;718impl ArrayLike for MappedArray {719 #[cfg(feature = "nightly")]720 type Iter<'t> = MappedArrayIter<'t>;721 #[cfg(feature = "nightly")]722 type IterLazy<'t> = MappedArrayLazyIter<'t>;723 #[cfg(feature = "nightly")]724 type IterCheap<'t> = MappedArrayCheapIter<'t>;725726 fn len(&self) -> usize {727 self.0.cached.borrow().len()728 }729730 fn get(&self, index: usize) -> Result<Option<Val>> {731 if index >= self.len() {732 return Ok(None);733 }734 match &self.0.cached.borrow()[index] {735 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),736 ArrayThunk::Errored(e) => return Err(e.clone()),737 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),738 ArrayThunk::Waiting(..) => {}739 };740741 let ArrayThunk::Waiting(_) = replace(&mut self.0.cached.borrow_mut()[index], ArrayThunk::Pending) else {742 unreachable!()743 };744745 let val = self746 .0747 .inner748 .get(index)749 .transpose()750 .expect("index checked")751 .and_then(|r| self.0.mapper.evaluate_simple(&(r,)));752753 let new_value = match val {754 Ok(v) => v,755 Err(e) => {756 self.0.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());757 return Err(e);758 }759 };760 self.0.cached.borrow_mut()[index] = ArrayThunk::Computed(new_value.clone());761 Ok(Some(new_value))762 }763 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {764 #[derive(Trace)]765 struct ArrayElement {766 arr_thunk: MappedArray,767 index: usize,768 }769770 impl ThunkValue for ArrayElement {771 type Output = Val;772773 fn get(self: Box<Self>) -> Result<Self::Output> {774 self.arr_thunk775 .get(self.index)776 .transpose()777 .expect("index checked")778 }779 }780781 if index >= self.len() {782 return None;783 }784 match &self.0.cached.borrow()[index] {785 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),786 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),787 ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}788 };789790 Some(Thunk::new(ArrayElement {791 arr_thunk: self.clone(),792 index,793 }))794 }795796 fn get_cheap(&self, _index: usize) -> Option<Val> {797 None798 }799800 #[cfg(feature = "nightly")]801 fn iter(&self) -> MappedArrayIter<'_> {802 (0..self.len()).map(|i| self.get(i).transpose().expect("length checked"))803 }804805 #[cfg(feature = "nightly")]806 fn iter_lazy(&self) -> MappedArrayLazyIter<'_> {807 (0..self.len()).map(|i| self.get_lazy(i).expect("length checked"))808 }809810 #[cfg(feature = "nightly")]811 fn iter_cheap(&self) -> Option<Self::IterCheap<'_>> {812 None813 }814}815impl From<MappedArray> for ArrValue {816 fn from(value: MappedArray) -> Self {817 Self::Mapped(value)818 }819}820821#[derive(Trace, Debug)]822pub struct RepeatedArrayInner {823 data: ArrValue,824 repeats: usize,825 total_len: usize,826}827#[derive(Trace, Debug, Clone)]828pub struct RepeatedArray(Cc<RepeatedArrayInner>);829impl RepeatedArray {830 pub fn new(data: ArrValue, repeats: usize) -> Option<Self> {831 let total_len = data.len().checked_mul(repeats)?;832 Some(Self(Cc::new(RepeatedArrayInner {833 data,834 repeats,835 total_len,836 })))837 }838 pub fn is_cheap(&self) -> bool {839 self.0.data.is_cheap()840 }841}842843#[cfg(feature = "nightly")]844type RepeatedArrayIter<'t> = impl DoubleEndedIterator<Item = Result<Val>> + ExactSizeIterator + 't;845#[cfg(feature = "nightly")]846type RepeatedArrayLazyIter<'t> =847 impl DoubleEndedIterator<Item = Thunk<Val>> + ExactSizeIterator + 't;848#[cfg(feature = "nightly")]849type RepeatedArrayCheapIter<'t> = impl DoubleEndedIterator<Item = Val> + ExactSizeIterator + 't;850impl ArrayLike for RepeatedArray {851 #[cfg(feature = "nightly")]852 type Iter<'t> = RepeatedArrayIter<'t>;853 #[cfg(feature = "nightly")]854 type IterLazy<'t> = RepeatedArrayLazyIter<'t>;855 #[cfg(feature = "nightly")]856 type IterCheap<'t> = RepeatedArrayCheapIter<'t>;857858 fn len(&self) -> usize {859 self.0.total_len860 }861862 fn get(&self, index: usize) -> Result<Option<Val>> {863 if index > self.0.total_len {864 return Ok(None);865 }866 self.0.data.get(index % self.0.data.len())867 }868869 fn get_lazy(&self, index: usize) -> Option<Thunk<Val>> {870 if index > self.0.total_len {871 return None;872 }873 self.0.data.get_lazy(index % self.0.data.len())874 }875876 fn get_cheap(&self, index: usize) -> Option<Val> {877 if index > self.0.total_len {878 return None;879 }880 self.0.data.get_cheap(index % self.0.data.len())881 }882883 #[cfg(feature = "nightly")]884 fn iter(&self) -> RepeatedArrayIter<'_> {885 (0..self.0.total_len)886 .map(|i| self.get(i))887 .map(Result::transpose)888 .map(Option::unwrap)889 }890891 #[cfg(feature = "nightly")]892 fn iter_lazy(&self) -> RepeatedArrayLazyIter<'_> {893 (0..self.0.total_len)894 .map(|i| self.get_lazy(i))895 .map(Option::unwrap)896 }897898 #[cfg(feature = "nightly")]899 fn iter_cheap(&self) -> Option<RepeatedArrayCheapIter<'_>> {900 if !self.0.data.is_cheap() {901 return None;902 }903 Some(904 (0..self.0.total_len)905 .map(|i| self.get_cheap(i))906 .map(Option::unwrap),907 )908 }909}910impl From<RepeatedArray> for ArrValue {911 fn from(value: RepeatedArray) -> Self {912 Self::Repeated(value)913 }914}915916#[cfg(feature = "nightly")]917macro_rules! impl_iter_enum {918 ($n:ident => $v:ident) => {919 pub enum $n<'t> {920 Bytes(<BytesArray as ArrayLike>::$v<'t>),921 Expr(<ExprArray as ArrayLike>::$v<'t>),922 Lazy(<LazyArray as ArrayLike>::$v<'t>),923 Eager(<EagerArray as ArrayLike>::$v<'t>),924 Range(<RangeArray as ArrayLike>::$v<'t>),925 Slice(Box<<SliceArray as ArrayLike>::$v<'t>>),926 Extended(Box<<ExtendedArray as ArrayLike>::$v<'t>>),927 Reverse(Box<<ReverseArray as ArrayLike>::$v<'t>>),928 Mapped(Box<<MappedArray as ArrayLike>::$v<'t>>),929 Repeated(Box<<RepeatedArray as ArrayLike>::$v<'t>>),930 }931 };932}933934macro_rules! pass {935 ($t:ident.$m:ident($($ident:ident),*)) => {936 match $t {937 Self::Bytes(e) => e.$m($($ident)*),938 Self::Expr(e) => e.$m($($ident)*),939 Self::Lazy(e) => e.$m($($ident)*),940 Self::Eager(e) => e.$m($($ident)*),941 Self::Range(e) => e.$m($($ident)*),942 Self::Slice(e) => e.$m($($ident)*),943 Self::Extended(e) => e.$m($($ident)*),944 Self::Reverse(e) => e.$m($($ident)*),945 Self::Mapped(e) => e.$m($($ident)*),946 Self::Repeated(e) => e.$m($($ident)*),947 }948 };949}950pub(super) use pass;951952#[cfg(feature = "nightly")]953macro_rules! pass_iter_call {954 ($t:ident.$c:ident $(in $wrap:ident)? => $e:ident) => {955 match $t {956 ArrValue::Bytes(e) => $e::Bytes($($wrap!)?(e.$c())),957 ArrValue::Lazy(e) => $e::Lazy($($wrap!)?(e.$c())),958 ArrValue::Expr(e) => $e::Expr($($wrap!)?(e.$c())),959 ArrValue::Eager(e) => $e::Eager($($wrap!)?(e.$c())),960 ArrValue::Range(e) => $e::Range($($wrap!)?(e.$c())),961 ArrValue::Slice(e) => $e::Slice(Box::new($($wrap!)?(e.$c()))),962 ArrValue::Extended(e) => $e::Extended(Box::new($($wrap!)?(e.$c()))),963 ArrValue::Reverse(e) => $e::Reverse(Box::new($($wrap!)?(e.$c()))),964 ArrValue::Mapped(e) => $e::Mapped(Box::new($($wrap!)?(e.$c()))),965 ArrValue::Repeated(e) => $e::Repeated(Box::new($($wrap!)?(e.$c()))),966 }967 };968}969#[cfg(feature = "nightly")]970pub(super) use pass_iter_call;971972#[cfg(feature = "nightly")]973macro_rules! impl_iter {974 ($t:ident => $out:ty) => {975 impl Iterator for $t<'_> {976 type Item = $out;977978 fn next(&mut self) -> Option<Self::Item> {979 pass!(self.next())980 }981 fn nth(&mut self, count: usize) -> Option<Self::Item> {982 pass!(self.nth(count))983 }984 fn size_hint(&self) -> (usize, Option<usize>) {985 pass!(self.size_hint())986 }987 }988 impl DoubleEndedIterator for $t<'_> {989 fn next_back(&mut self) -> Option<Self::Item> {990 pass!(self.next_back())991 }992 fn nth_back(&mut self, count: usize) -> Option<Self::Item> {993 pass!(self.nth_back(count))994 }995 }996 impl ExactSizeIterator for $t<'_> {997 fn len(&self) -> usize {998 match self {999 Self::Bytes(e) => e.len(),1000 Self::Expr(e) => e.len(),1001 Self::Lazy(e) => e.len(),1002 Self::Eager(e) => e.len(),1003 Self::Range(e) => e.len(),1004 Self::Slice(e) => e.len(),1005 Self::Extended(e) => {1006 e.size_hint().1.expect("overflow is checked in constructor")1007 }1008 Self::Reverse(e) => e.len(),1009 Self::Mapped(e) => e.len(),1010 Self::Repeated(e) => e.len(),1011 }1012 }1013 }1014 };1015}10161017#[cfg(feature = "nightly")]1018impl_iter_enum!(UnknownArrayIter => Iter);1019#[cfg(feature = "nightly")]1020impl_iter!(UnknownArrayIter => Result<Val>);1021#[cfg(feature = "nightly")]1022impl_iter_enum!(UnknownArrayIterLazy => IterLazy);1023#[cfg(feature = "nightly")]1024impl_iter!(UnknownArrayIterLazy => Thunk<Val>);1025#[cfg(feature = "nightly")]1026impl_iter_enum!(UnknownArrayIterCheap => IterCheap);1027#[cfg(feature = "nightly")]1028impl_iter!(UnknownArrayIterCheap => Val);crates/jrsonnet-evaluator/src/async_import.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/async_import.rs
+++ b/crates/jrsonnet-evaluator/src/async_import.rs
@@ -294,7 +294,6 @@
path: handler.resolve(path.as_ref()).await?,
parse: true,
}];
- // let mut resolved = HashMap::<(SourcePath, IStr), (SourcePath, bool)>::new();
while let Some(job) = queue.pop() {
match job {
Job::LoadFile { path, parse } => {
@@ -349,8 +348,8 @@
}
}
}
- s.set_import_resolver(Box::new(ResolvedImportResolver {
+ s.set_import_resolver(ResolvedImportResolver {
resolved: RefCell::new(resolved),
- }));
+ });
Ok(())
}
crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/ctx.rs
+++ b/crates/jrsonnet-evaluator/src/ctx.rs
@@ -39,16 +39,16 @@
.expect("used state from dummy context")
}
- pub fn dollar(&self) -> &Option<ObjValue> {
- &self.0.dollar
+ pub fn dollar(&self) -> Option<&ObjValue> {
+ self.0.dollar.as_ref()
}
- pub fn this(&self) -> &Option<ObjValue> {
- &self.0.this
+ pub fn this(&self) -> Option<&ObjValue> {
+ self.0.this.as_ref()
}
- pub fn super_obj(&self) -> &Option<ObjValue> {
- &self.0.sup
+ pub fn super_obj(&self) -> Option<&ObjValue> {
+ self.0.sup.as_ref()
}
#[cfg(not(feature = "friendly-errors"))]
@@ -130,12 +130,6 @@
}))
}
}
-
-// impl Default for Context {
-// fn default() -> Self {
-// Self::new()
-// }
-// }
impl PartialEq for Context {
fn eq(&self, other: &Self) -> bool {
crates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
@@ -6,7 +6,7 @@
error::{ErrorKind::*, Result},
evaluate, evaluate_method, evaluate_named,
gc::GcHashMap,
- tb, throw,
+ throw,
val::ThunkValue,
Context, Pending, Thunk, Val,
};
@@ -63,11 +63,11 @@
}
}
- let full = Thunk::new(tb!(DataThunk {
+ let full = Thunk::new(DataThunk {
min_len: start.len() + end.len(),
has_rest: rest.is_some(),
parent,
- }));
+ });
{
#[derive(Trace)]
@@ -86,10 +86,10 @@
for (i, d) in start.iter().enumerate() {
destruct(
d,
- Thunk::new(tb!(BaseThunk {
+ Thunk::new(BaseThunk {
full: full.clone(),
index: i,
- })),
+ }),
fctx.clone(),
new_bindings,
)?;
@@ -119,11 +119,11 @@
destruct(
&Destruct::Full(v.clone()),
- Thunk::new(tb!(RestThunk {
+ Thunk::new(RestThunk {
full: full.clone(),
start: start.len(),
end: end.len(),
- })),
+ }),
fctx.clone(),
new_bindings,
)?;
@@ -151,11 +151,11 @@
for (i, d) in end.iter().enumerate() {
destruct(
d,
- Thunk::new(tb!(EndThunk {
+ Thunk::new(EndThunk {
full: full.clone(),
index: i,
end: end.len(),
- })),
+ }),
fctx.clone(),
new_bindings,
)?;
@@ -199,11 +199,11 @@
.filter(|f| f.2.is_none())
.map(|f| f.0.clone())
.collect();
- let full = Thunk::new(tb!(DataThunk {
+ let full = Thunk::new(DataThunk {
parent,
field_names,
- has_rest: rest.is_some()
- }));
+ has_rest: rest.is_some(),
+ });
for (field, d, default) in fields {
#[derive(Trace)]
@@ -225,11 +225,11 @@
}
}
}
- let value = Thunk::new(tb!(FieldThunk {
+ let value = Thunk::new(FieldThunk {
full: full.clone(),
field: field.clone(),
default: default.clone().map(|e| (fctx.clone(), e)),
- }));
+ });
if let Some(d) = d {
destruct(d, value, fctx.clone(), new_bindings)?;
} else {
@@ -268,11 +268,11 @@
)
}
}
- let data = Thunk::new(tb!(EvaluateThunkValue {
+ let data = Thunk::new(EvaluateThunkValue {
name: into.name(),
fctx: fctx.clone(),
expr: value.clone(),
- }));
+ });
destruct(into, data, fctx, new_bindings)?;
}
BindSpec::Function {
@@ -302,12 +302,12 @@
let old = new_bindings.insert(
name.clone(),
- Thunk::new(tb!(MethodThunk {
+ Thunk::new(MethodThunk {
fctx,
name: name.clone(),
params: params.clone(),
- value: value.clone()
- })),
+ value: value.clone(),
+ }),
);
if old.is_some() {
throw!(DuplicateLocalVar(name.clone()))
crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -15,7 +15,7 @@
error::ErrorKind::*,
evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op},
function::{CallLocation, FuncDesc, FuncVal},
- tb, throw,
+ throw,
typed::Typed,
val::{CachedUnbound, IndexableVal, StrValue, Thunk, ThunkValue},
Context, GcHashMap, ObjValue, ObjValueBuilder, ObjectAssertion, Pending, Result, State,
@@ -45,12 +45,12 @@
if n.iter().any(|e| !is_trivial(e)) {
return None;
}
- Val::Arr(ArrValue::eager(Cc::new(
+ Val::Arr(ArrValue::eager(
n.iter()
.map(evaluate_trivial)
.map(|e| e.expect("checked trivial"))
.collect(),
- )))
+ ))
}
Expr::Parened(e) => evaluate_trivial(e)?,
_ => return None,
@@ -136,10 +136,10 @@
let mut new_bindings = GcHashMap::with_capacity(var.capacity_hint());
let value = Thunk::evaluated(Val::Arr(ArrValue::lazy(Cc::new(vec![
Thunk::evaluated(Val::Str(StrValue::Flat(field.clone()))),
- Thunk::new(tb!(ObjectFieldThunk {
+ Thunk::new(ObjectFieldThunk {
field: field.clone(),
obj: obj.clone(),
- })),
+ }),
]))));
destruct(var, value, fctx.clone(), &mut new_bindings)?;
let ctx = ctx
@@ -180,7 +180,7 @@
}
let ctx = self.fctx.unwrap();
- let new_dollar = ctx.dollar().clone().or_else(|| this.clone());
+ let new_dollar = ctx.dollar().cloned().or_else(|| this.clone());
let ctx = ctx
.extend(new_bindings, new_dollar, sup, this)
@@ -230,11 +230,11 @@
.with_add(*plus)
.with_visibility(*visibility)
.with_location(value.1.clone())
- .bindable(tb!(UnboundValue {
+ .bindable(UnboundValue {
uctx,
value: value.clone(),
name,
- }))?;
+ })?;
}
FieldMember {
params: Some(params),
@@ -265,12 +265,12 @@
.member(name.clone())
.with_visibility(*visibility)
.with_location(value.1.clone())
- .bindable(tb!(UnboundMethod {
+ .bindable(UnboundMethod {
uctx,
value: value.clone(),
params: params.clone(),
name,
- }))?;
+ })?;
}
}
Ok(())
@@ -311,10 +311,10 @@
evaluate_assert(ctx, &self.assert)
}
}
- builder.assert(tb!(ObjectAssert {
+ builder.assert(ObjectAssert {
uctx: uctx.clone(),
assert: stmt.clone(),
- }));
+ });
}
Member::BindStmt(_) => {
// Already handled
@@ -420,17 +420,17 @@
let LocExpr(expr, loc) = expr;
Ok(match &**expr {
Literal(LiteralType::This) => {
- Val::Obj(ctx.this().clone().ok_or(CantUseSelfOutsideOfObject)?)
+ Val::Obj(ctx.this().ok_or(CantUseSelfOutsideOfObject)?.clone())
}
Literal(LiteralType::Super) => Val::Obj(
- ctx.super_obj().clone().ok_or(NoSuperFound)?.with_this(
+ ctx.super_obj().ok_or(NoSuperFound)?.with_this(
ctx.this()
- .clone()
- .expect("if super exists - then this should too"),
+ .expect("if super exists - then this should too")
+ .clone(),
),
),
Literal(LiteralType::Dollar) => {
- Val::Obj(ctx.dollar().clone().ok_or(NoTopLevelObjectFound)?)
+ Val::Obj(ctx.dollar().ok_or(NoTopLevelObjectFound)?.clone())
}
Literal(LiteralType::True) => Val::Bool(true),
Literal(LiteralType::False) => Val::Bool(false),
@@ -455,9 +455,8 @@
))
};
ctx.super_obj()
- .clone()
.expect("no super found")
- .get_for(name.into_flat(), ctx.this().clone().expect("no this found"))?
+ .get_for(name.into_flat(), ctx.this().expect("no this found").clone())?
.expect("value not found")
}
Index(value, index) => match (evaluate(ctx.clone(), value)?, evaluate(ctx, index)?) {
@@ -563,12 +562,10 @@
evaluate(self.ctx, &self.item)
}
}
- Val::Arr(ArrValue::lazy(Cc::new(vec![Thunk::new(tb!(
- ArrayElement {
- ctx,
- item: items[0].clone(),
- }
- ))])))
+ Val::Arr(ArrValue::lazy(Cc::new(vec![Thunk::new(ArrayElement {
+ ctx,
+ item: items[0].clone(),
+ })])))
} else {
Val::Arr(ArrValue::expr(ctx, items.iter().cloned()))
}
@@ -579,7 +576,7 @@
out.push(evaluate(ctx, expr)?);
Ok(())
})?;
- Val::Arr(ArrValue::eager(Cc::new(out)))
+ Val::Arr(ArrValue::eager(out))
}
Obj(body) => Val::Obj(evaluate_object(ctx, body)?),
ObjExtend(a, b) => evaluate_add_op(
@@ -623,7 +620,7 @@
fn parse_idx<T: Typed>(
loc: CallLocation<'_>,
ctx: &Context,
- expr: &Option<LocExpr>,
+ expr: Option<&LocExpr>,
desc: &'static str,
) -> Result<Option<T>> {
if let Some(value) = expr {
@@ -640,9 +637,9 @@
let indexable = evaluate(ctx.clone(), value)?;
let loc = CallLocation::new(loc);
- let start = parse_idx(loc, &ctx, &desc.start, "start")?;
- let end = parse_idx(loc, &ctx, &desc.end, "end")?;
- let step = parse_idx(loc, &ctx, &desc.step, "step")?;
+ let start = parse_idx(loc, &ctx, desc.start.as_ref(), "start")?;
+ let end = parse_idx(loc, &ctx, desc.end.as_ref(), "end")?;
+ let step = parse_idx(loc, &ctx, desc.step.as_ref(), "step")?;
IndexableVal::into_untyped(indexable.into_indexable()?.slice(start, end, step)?)?
}
crates/jrsonnet-evaluator/src/function/arglike.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function/arglike.rs
+++ b/crates/jrsonnet-evaluator/src/function/arglike.rs
@@ -7,7 +7,6 @@
error::Result,
evaluate,
gc::GcHashMap,
- tb,
typed::Typed,
val::{StrValue, ThunkValue},
Context, Thunk, Val,
@@ -37,10 +36,10 @@
Ok(if tailstrict {
Thunk::evaluated(evaluate(ctx, self)?)
} else {
- Thunk::new(tb!(EvaluateThunk {
+ Thunk::new(EvaluateThunk {
ctx,
expr: (*self).clone(),
- }))
+ })
})
}
}
@@ -69,10 +68,10 @@
TlaArg::Code(code) => Ok(if tailstrict {
Thunk::evaluated(evaluate(ctx, code)?)
} else {
- Thunk::new(tb!(EvaluateThunk {
+ Thunk::new(EvaluateThunk {
ctx,
expr: code.clone(),
- }))
+ })
}),
TlaArg::Val(val) => Ok(Thunk::evaluated(val.clone())),
}
@@ -128,7 +127,6 @@
}
fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}
}
-impl OptionalContext for Vec<Val> {}
impl ArgsLike for ArgsDesc {
fn unnamed_len(&self) -> usize {
@@ -147,10 +145,10 @@
if tailstrict {
Thunk::evaluated(evaluate(ctx.clone(), arg)?)
} else {
- Thunk::new(tb!(EvaluateThunk {
+ Thunk::new(EvaluateThunk {
ctx: ctx.clone(),
expr: arg.clone(),
- }))
+ })
},
)?;
}
@@ -169,10 +167,10 @@
if tailstrict {
Thunk::evaluated(evaluate(ctx.clone(), arg)?)
} else {
- Thunk::new(tb!(EvaluateThunk {
+ Thunk::new(EvaluateThunk {
ctx: ctx.clone(),
expr: arg.clone(),
- }))
+ })
},
)?;
}
crates/jrsonnet-evaluator/src/function/builtin.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function/builtin.rs
+++ b/crates/jrsonnet-evaluator/src/function/builtin.rs
@@ -3,7 +3,7 @@
use jrsonnet_gcmodule::Trace;
use super::{arglike::ArgsLike, parse::parse_builtin_call, CallLocation};
-use crate::{error::Result, gc::TraceBox, Context, Val};
+use crate::{error::Result, gc::TraceBox, tb, Context, Val};
pub type BuiltinParamName = Cow<'static, str>;
@@ -42,10 +42,7 @@
}
impl NativeCallback {
#[deprecated = "prefer using builtins directly, use this interface only for bindings"]
- pub fn new(
- params: Vec<Cow<'static, str>>,
- handler: TraceBox<dyn NativeCallbackHandler>,
- ) -> Self {
+ pub fn new(params: Vec<Cow<'static, str>>, handler: impl NativeCallbackHandler) -> Self {
Self {
params: params
.into_iter()
@@ -54,7 +51,7 @@
has_default: false,
})
.collect(),
- handler,
+ handler: tb!(handler),
}
}
}
crates/jrsonnet-evaluator/src/function/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function/mod.rs
+++ b/crates/jrsonnet-evaluator/src/function/mod.rs
@@ -12,9 +12,7 @@
native::NativeDesc,
parse::{parse_default_function_call, parse_function_call},
};
-use crate::{
- evaluate, evaluate_trivial, gc::TraceBox, typed::Any, Context, ContextBuilder, Result, Val,
-};
+use crate::{evaluate, evaluate_trivial, gc::TraceBox, tb, Context, ContextBuilder, Result, Val};
pub mod arglike;
pub mod builtin;
@@ -116,6 +114,9 @@
}
impl FuncVal {
+ pub fn builtin(builtin: impl Builtin) -> Self {
+ Self::Builtin(Cc::new(tb!(builtin)))
+ }
/// Amount of non-default required arguments
pub fn params_len(&self) -> usize {
match self {
@@ -148,8 +149,8 @@
Self::Id => {
#[allow(clippy::unnecessary_wraps)]
#[builtin]
- const fn builtin_id(v: Any) -> Result<Any> {
- Ok(v)
+ const fn builtin_id(x: Val) -> Val {
+ x
}
static ID: &builtin_id = &builtin_id {};
crates/jrsonnet-evaluator/src/function/parse.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function/parse.rs
+++ b/crates/jrsonnet-evaluator/src/function/parse.rs
@@ -10,7 +10,7 @@
error::{ErrorKind::*, Result},
evaluate_named,
gc::GcHashMap,
- tb, throw,
+ throw,
val::ThunkValue,
Context, Pending, Thunk, Val,
};
@@ -100,11 +100,11 @@
destruct(
¶m.0,
- Thunk::new(tb!(EvaluateNamedThunk {
+ Thunk::new(EvaluateNamedThunk {
ctx: fctx.clone(),
name: param.0.name().unwrap_or_else(|| "<destruct>".into()),
value: param.1.clone().expect("default exists"),
- })),
+ }),
fctx.clone(),
&mut defaults,
)?;
@@ -250,21 +250,21 @@
if let Some(v) = ¶m.1 {
destruct(
¶m.0.clone(),
- Thunk::new(tb!(EvaluateNamedThunk {
+ Thunk::new(EvaluateNamedThunk {
ctx: fctx.clone(),
name: param.0.name().unwrap_or_else(|| "<destruct>".into()),
value: v.clone(),
- })),
+ }),
fctx.clone(),
&mut bindings,
)?;
} else {
destruct(
¶m.0,
- Thunk::new(tb!(DependsOnUnbound(
+ Thunk::new(DependsOnUnbound(
param.0.name().unwrap_or_else(|| "<destruct>".into()),
- params.clone()
- ))),
+ params.clone(),
+ )),
fctx.clone(),
&mut bindings,
)?;
crates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/integrations/serde.rs
+++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs
@@ -1,6 +1,5 @@
use std::borrow::Cow;
-use jrsonnet_gcmodule::Cc;
use serde::{
de::Visitor,
ser::{Error, SerializeMap, SerializeSeq},
@@ -117,7 +116,7 @@
out.push(val);
}
- Ok(Val::Arr(ArrValue::eager(Cc::new(out))))
+ Ok(Val::Arr(ArrValue::eager(out)))
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -433,10 +433,13 @@
pub fn import_resolver(&self) -> Ref<'_, dyn ImportResolver> {
Ref::map(self.settings(), |s| &*s.import_resolver)
}
- pub fn set_import_resolver(&self, resolver: Box<dyn ImportResolver>) {
- self.settings_mut().import_resolver = TraceBox(resolver);
+ pub fn set_import_resolver(&self, resolver: impl ImportResolver) {
+ self.settings_mut().import_resolver = tb!(resolver);
}
pub fn context_initializer(&self) -> Ref<'_, dyn ContextInitializer> {
Ref::map(self.settings(), |s| &*s.context_initializer)
}
+ pub fn set_context_initializer(&self, initializer: impl ContextInitializer) {
+ self.settings_mut().context_initializer = tb!(initializer);
+ }
}
crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/obj.rs
+++ b/crates/jrsonnet-evaluator/src/obj.rs
@@ -15,7 +15,7 @@
function::CallLocation,
gc::{GcHashMap, GcHashSet, TraceBox},
operator::evaluate_add_op,
- throw, MaybeUnbound, Result, State, Thunk, Unbound, Val,
+ tb, throw, MaybeUnbound, Result, State, Thunk, Unbound, Val,
};
#[cfg(not(feature = "exp-preserve-order"))]
@@ -538,8 +538,8 @@
self
}
- pub fn assert(&mut self, assertion: TraceBox<dyn ObjectAssertion>) -> &mut Self {
- self.assertions.push(assertion);
+ pub fn assert(&mut self, assertion: impl ObjectAssertion + 'static) -> &mut Self {
+ self.assertions.push(tb!(assertion));
self
}
pub fn member(&mut self, name: IStr) -> ObjMemberBuilder<ValueBuilder<'_>> {
@@ -631,8 +631,8 @@
pub fn thunk(self, value: Thunk<Val>) -> Result<()> {
self.binding(MaybeUnbound::Bound(value))
}
- pub fn bindable(self, bindable: TraceBox<dyn Unbound<Bound = Val>>) -> Result<()> {
- self.binding(MaybeUnbound::Unbound(Cc::new(bindable)))
+ pub fn bindable(self, bindable: impl Unbound<Bound = Val>) -> Result<()> {
+ self.binding(MaybeUnbound::Unbound(Cc::new(tb!(bindable))))
}
pub fn binding(self, binding: MaybeUnbound) -> Result<()> {
let (receiver, name, member) = self.build_member(binding);
crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/typed/conversions.rs
+++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs
@@ -29,6 +29,14 @@
const TYPE: &'static ComplexValType;
fn into_untyped(typed: Self) -> Result<Val>;
fn from_untyped(untyped: Val) -> Result<Self>;
+
+ /// Hack to make builtins be able to return non-result values, and make macros able to convert those values to result
+ /// This method returns identity in impl Typed for Result, and should not be overriden
+ #[doc(hidden)]
+ fn into_result(typed: Self) -> Result<Val> {
+ let value = Self::into_untyped(typed)?;
+ Ok(value)
+ }
}
const MAX_SAFE_INTEGER: f64 = ((1u64 << (f64::MANTISSA_DIGITS + 1)) - 1) as f64;
@@ -238,61 +246,54 @@
const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);
fn into_untyped(value: Self) -> Result<Val> {
- let mut o = Vec::with_capacity(value.len());
- for i in value {
- o.push(T::into_untyped(i)?);
- }
- Ok(Val::Arr(o.into()))
+ Ok(Val::Arr(
+ value
+ .into_iter()
+ .map(T::into_untyped)
+ .collect::<Result<ArrValue>>()?,
+ ))
}
fn from_untyped(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
- match value {
- Val::Arr(a) => {
- let mut o = Self::with_capacity(a.len());
- for i in a.iter() {
- o.push(T::from_untyped(i?)?);
- }
- Ok(o)
- }
- _ => unreachable!(),
- }
+ let Val::Arr(a) = value else {
+ <Self as Typed>::TYPE.check(&value)?;
+ unreachable!("typecheck should fail")
+ };
+ a.iter()
+ .map(|r| r.and_then(T::from_untyped))
+ .collect::<Result<Vec<T>>>()
}
}
-/// To be used in Vec<Any>
-/// Regular Val can't be used here, because it has wrong `TryFrom::Error` type
-#[derive(Clone)]
-pub struct Any(pub Val);
-
-impl Typed for Any {
+impl Typed for Val {
const TYPE: &'static ComplexValType = &ComplexValType::Any;
- fn into_untyped(value: Self) -> Result<Val> {
- Ok(value.0)
+ fn into_untyped(typed: Self) -> Result<Val> {
+ Ok(typed)
}
-
- fn from_untyped(value: Val) -> Result<Self> {
- Ok(Self(value))
+ fn from_untyped(untyped: Val) -> Result<Self> {
+ Ok(untyped)
}
}
-/// Specialization, provides faster `TryFrom<VecVal>` for Val
-pub struct VecVal(pub Vec<Val>);
+// Hack
+#[doc(hidden)]
+impl<T> Typed for Result<T>
+where
+ T: Typed,
+{
+ const TYPE: &'static ComplexValType = &ComplexValType::Any;
-impl Typed for VecVal {
- const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);
+ fn into_untyped(_typed: Self) -> Result<Val> {
+ panic!("do not use this conversion")
+ }
- fn into_untyped(value: Self) -> Result<Val> {
- Ok(Val::Arr(ArrValue::eager(Cc::new(value.0))))
+ fn from_untyped(_untyped: Val) -> Result<Self> {
+ panic!("do not use this conversion")
}
- fn from_untyped(value: Val) -> Result<Self> {
- <Self as Typed>::TYPE.check(&value)?;
- match value {
- Val::Arr(a) => Ok(Self(a.iter().collect::<Result<Vec<_>>>()?)),
- _ => unreachable!(),
- }
+ fn into_result(typed: Self) -> Result<Val> {
+ typed.map(T::into_untyped)?
}
}
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -15,7 +15,7 @@
function::FuncVal,
gc::{GcHashMap, TraceBox},
manifest::{ManifestFormat, ToStringFormat},
- throw,
+ tb, throw,
typed::BoundedUsize,
ObjValue, Result, Unbound, WeakObjValue,
};
@@ -41,8 +41,8 @@
pub fn evaluated(val: T) -> Self {
Self(Cc::new(RefCell::new(ThunkInner::Computed(val))))
}
- pub fn new(f: TraceBox<dyn ThunkValue<Output = T>>) -> Self {
- Self(Cc::new(RefCell::new(ThunkInner::Waiting(f))))
+ pub fn new(f: impl ThunkValue<Output = T> + 'static) -> Self {
+ Self(Cc::new(RefCell::new(ThunkInner::Waiting(tb!(f)))))
}
pub fn errored(e: Error) -> Self {
Self(Cc::new(RefCell::new(ThunkInner::Errored(e))))
crates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-macros/src/lib.rs
+++ b/crates/jrsonnet-macros/src/lib.rs
@@ -192,38 +192,27 @@
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let attr = parse_macro_input!(attr as BuiltinAttrs);
- let item: ItemFn = parse_macro_input!(item);
+ let item_fn = item.clone();
+ let item_fn: ItemFn = parse_macro_input!(item_fn);
- match builtin_inner(attr, item) {
+ match builtin_inner(attr, item_fn, item.into()) {
Ok(v) => v.into(),
Err(e) => e.into_compile_error().into(),
}
}
-fn builtin_inner(attr: BuiltinAttrs, fun: ItemFn) -> syn::Result<TokenStream> {
+fn builtin_inner(
+ attr: BuiltinAttrs,
+ fun: ItemFn,
+ item: proc_macro2::TokenStream,
+) -> syn::Result<TokenStream> {
let ReturnType::Type(_, result) = &fun.sig.output else {
return Err(Error::new(
fun.sig.span(),
"builtin should return something",
))
};
-
- let Some(args) = type_is_path(result, "Result") else {
- return Err(Error::new(result.span(), "return value should be result"));
- };
- let PathArguments::AngleBracketed(params) = args else {
- return Err(Error::new(args.span(), "missing result generic"));
- };
- let generic_arg = params.args.iter().next().unwrap();
- // This argument must be a type:
- let GenericArgument::Type(result_inner) = generic_arg else {
- return Err(Error::new(
- generic_arg.span(),
- "option generic should be a type",
- ))
- };
-
let name = fun.sig.ident.to_string();
let args = fun
.sig
@@ -355,7 +344,8 @@
};
Ok(quote! {
- #fun
+ #item
+
#[doc(hidden)]
#[allow(non_camel_case_types)]
#[derive(Clone, jrsonnet_gcmodule::Trace #static_derive_copy)]
@@ -388,8 +378,7 @@
let parsed = parse_builtin_call(ctx.clone(), &PARAMS, args, false)?;
let result: #result = #name(#(#pass)*);
- let result = result?;
- <#result_inner>::into_untyped(result)
+ <_ as Typed>::into_result(result)
}
}
};
crates/jrsonnet-stdlib/src/arrays.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/arrays.rs
+++ b/crates/jrsonnet-stdlib/src/arrays.rs
@@ -2,11 +2,10 @@
error::{ErrorKind::RuntimeError, Result},
function::{builtin, FuncVal},
throw,
- typed::{Any, BoundedI32, BoundedUsize, Either2, NativeFn, Typed},
+ typed::{BoundedI32, BoundedUsize, Either2, NativeFn, Typed},
val::{equals, ArrValue, IndexableVal, StrValue},
Either, IStr, Val,
};
-use jrsonnet_gcmodule::Cc;
#[builtin]
pub fn builtin_make_array(sz: BoundedI32<0, { i32::MAX }>, func: FuncVal) -> Result<ArrValue> {
@@ -18,21 +17,21 @@
for _ in 0..*sz {
out.push(trivial.clone())
}
- Ok(ArrValue::eager(Cc::new(out)))
+ Ok(ArrValue::eager(out))
} else {
Ok(ArrValue::range_exclusive(0, *sz).map(func))
}
}
#[builtin]
-pub fn builtin_repeat(what: Either![IStr, ArrValue], count: usize) -> Result<Any> {
- Ok(Any(match what {
+pub fn builtin_repeat(what: Either![IStr, ArrValue], count: usize) -> Result<Val> {
+ Ok(match what {
Either2::A(s) => Val::Str(StrValue::Flat(s.repeat(count).into())),
Either2::B(arr) => Val::Arr(
ArrValue::repeated(arr, count)
.ok_or_else(|| RuntimeError("repeated length overflow".into()))?,
),
- }))
+ })
}
#[builtin]
@@ -41,8 +40,8 @@
index: Option<BoundedUsize<0, { i32::MAX as usize }>>,
end: Option<BoundedUsize<0, { i32::MAX as usize }>>,
step: Option<BoundedUsize<1, { i32::MAX as usize }>>,
-) -> Result<Any> {
- indexable.slice(index, end, step).map(Val::from).map(Any)
+) -> Result<Val> {
+ indexable.slice(index, end, step).map(Val::from)
}
#[builtin]
@@ -52,7 +51,7 @@
#[builtin]
pub fn builtin_flatmap(
- func: NativeFn<((Either![String, Any],), Any)>,
+ func: NativeFn<((Either![String, Val],), Val)>,
arr: IndexableVal,
) -> Result<IndexableVal> {
use std::fmt::Write;
@@ -60,7 +59,7 @@
IndexableVal::Str(str) => {
let mut out = String::new();
for c in str.chars() {
- match func(Either2::A(c.to_string()))?.0 {
+ match func(Either2::A(c.to_string()))? {
Val::Str(o) => write!(out, "{o}").unwrap(),
Val::Null => continue,
_ => throw!("in std.join all items should be strings"),
@@ -72,7 +71,7 @@
let mut out = Vec::new();
for el in a.iter() {
let el = el?;
- match func(Either2::B(Any(el)))?.0 {
+ match func(Either2::B(el))? {
Val::Arr(o) => {
for oe in o.iter() {
out.push(oe?);
@@ -89,25 +88,25 @@
#[builtin]
pub fn builtin_filter(func: FuncVal, arr: ArrValue) -> Result<ArrValue> {
- arr.filter(|val| bool::from_untyped(func.evaluate_simple(&(Any(val.clone()),))?))
+ arr.filter(|val| bool::from_untyped(func.evaluate_simple(&(val.clone(),))?))
}
#[builtin]
-pub fn builtin_foldl(func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {
- let mut acc = init.0;
+pub fn builtin_foldl(func: FuncVal, arr: ArrValue, init: Val) -> Result<Val> {
+ let mut acc = init;
for i in arr.iter() {
- acc = func.evaluate_simple(&(Any(acc), Any(i?)))?;
+ acc = func.evaluate_simple(&(acc, i?))?;
}
- Ok(Any(acc))
+ Ok(acc)
}
#[builtin]
-pub fn builtin_foldr(func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {
- let mut acc = init.0;
+pub fn builtin_foldr(func: FuncVal, arr: ArrValue, init: Val) -> Result<Val> {
+ let mut acc = init;
for i in arr.iter().rev() {
- acc = func.evaluate_simple(&(Any(i?), Any(acc)))?;
+ acc = func.evaluate_simple(&(i?, acc))?;
}
- Ok(Any(acc))
+ Ok(acc)
}
#[builtin]
@@ -175,8 +174,8 @@
}
#[builtin]
-pub fn builtin_reverse(value: ArrValue) -> Result<ArrValue> {
- Ok(value.reversed())
+pub fn builtin_reverse(arr: ArrValue) -> ArrValue {
+ arr.reversed()
}
#[builtin]
@@ -202,16 +201,16 @@
}
#[builtin]
-pub fn builtin_member(arr: IndexableVal, x: Any) -> Result<bool> {
+pub fn builtin_member(arr: IndexableVal, x: Val) -> Result<bool> {
match arr {
IndexableVal::Str(str) => {
- let x: IStr = IStr::from_untyped(x.0)?;
+ let x: IStr = IStr::from_untyped(x)?;
Ok(!x.is_empty() && str.contains(&*x))
}
IndexableVal::Arr(a) => {
for item in a.iter() {
let item = item?;
- if equals(&item, &x.0)? {
+ if equals(&item, &x)? {
return Ok(true);
}
}
@@ -221,10 +220,10 @@
}
#[builtin]
-pub fn builtin_count(arr: Vec<Any>, v: Any) -> Result<usize> {
+pub fn builtin_count(arr: ArrValue, x: Val) -> Result<usize> {
let mut count = 0;
- for item in &arr {
- if equals(&item.0, &v.0)? {
+ for item in arr.iter() {
+ if equals(&item?, &x)? {
count += 1;
}
}
crates/jrsonnet-stdlib/src/encoding.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/encoding.rs
+++ b/crates/jrsonnet-stdlib/src/encoding.rs
@@ -6,8 +6,8 @@
};
#[builtin]
-pub fn builtin_encode_utf8(str: IStr) -> Result<IBytes> {
- Ok(str.cast_bytes())
+pub fn builtin_encode_utf8(str: IStr) -> IBytes {
+ str.cast_bytes()
}
#[builtin]
@@ -18,24 +18,24 @@
}
#[builtin]
-pub fn builtin_base64(input: Either![IStr, IBytes]) -> Result<String> {
+pub fn builtin_base64(input: Either![IStr, IBytes]) -> String {
use Either2::*;
- Ok(match input {
+ match input {
A(l) => base64::encode(l.as_bytes()),
B(a) => base64::encode(a.as_slice()),
- })
+ }
}
#[builtin]
-pub fn builtin_base64_decode_bytes(input: IStr) -> Result<IBytes> {
- Ok(base64::decode(input.as_bytes())
+pub fn builtin_base64_decode_bytes(str: IStr) -> Result<IBytes> {
+ Ok(base64::decode(str.as_bytes())
.map_err(|_| RuntimeError("bad base64".into()))?
.as_slice()
.into())
}
#[builtin]
-pub fn builtin_base64_decode(input: IStr) -> Result<String> {
- let bytes = base64::decode(input.as_bytes()).map_err(|_| RuntimeError("bad base64".into()))?;
+pub fn builtin_base64_decode(str: IStr) -> Result<String> {
+ let bytes = base64::decode(str.as_bytes()).map_err(|_| RuntimeError("bad base64".into()))?;
Ok(String::from_utf8(bytes).map_err(|_| RuntimeError("bad utf8".into()))?)
}
crates/jrsonnet-stdlib/src/hash.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/hash.rs
+++ b/crates/jrsonnet-stdlib/src/hash.rs
@@ -1,13 +1,13 @@
-use jrsonnet_evaluator::{error::Result, function::builtin, IStr};
+use jrsonnet_evaluator::{function::builtin, IStr};
#[builtin]
-pub fn builtin_md5(str: IStr) -> Result<String> {
- Ok(format!("{:x}", md5::compute(str.as_bytes())))
+pub fn builtin_md5(s: IStr) -> String {
+ format!("{:x}", md5::compute(s.as_bytes()))
}
#[cfg(feature = "exp-more-hashes")]
#[builtin]
-pub fn builtin_sha256(str: IStr) -> Result<String> {
+pub fn builtin_sha256(s: IStr) -> String {
use sha2::digest::Digest;
- Ok(format!("{:?}", sha2::Sha256::digest(str.as_bytes())))
+ format!("{:?}", sha2::Sha256::digest(s.as_bytes()))
}
crates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/lib.rs
+++ b/crates/jrsonnet-stdlib/src/lib.rs
@@ -155,23 +155,21 @@
builder
.member("extVar".into())
.hide()
- .value(Val::Func(FuncVal::Builtin(Cc::new(tb!(builtin_ext_var {
- settings: settings.clone()
- })))))
+ .value(Val::Func(FuncVal::builtin(builtin_ext_var {
+ settings: settings.clone(),
+ })))
.expect("no conflict");
builder
.member("native".into())
.hide()
- .value(Val::Func(FuncVal::Builtin(Cc::new(tb!(builtin_native {
- settings: settings.clone()
- })))))
+ .value(Val::Func(FuncVal::builtin(builtin_native {
+ settings: settings.clone(),
+ })))
.expect("no conflict");
builder
.member("trace".into())
.hide()
- .value(Val::Func(FuncVal::Builtin(Cc::new(tb!(builtin_trace {
- settings
- })))))
+ .value(Val::Func(FuncVal::builtin(builtin_trace { settings })))
.expect("no conflict");
builder
@@ -301,8 +299,10 @@
.insert(name.into(), TlaArg::Code(parsed));
Ok(())
}
- pub fn add_native(&self, name: IStr, cb: Cc<TraceBox<dyn Builtin>>) {
- self.settings_mut().ext_natives.insert(name, cb);
+ pub fn add_native(&self, name: IStr, cb: impl Builtin) {
+ self.settings_mut()
+ .ext_natives
+ .insert(name, Cc::new(tb!(cb)));
}
}
impl jrsonnet_evaluator::ContextInitializer for ContextInitializer {
crates/jrsonnet-stdlib/src/manifest/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/manifest/mod.rs
+++ b/crates/jrsonnet-stdlib/src/manifest/mod.rs
@@ -5,7 +5,6 @@
error::Result,
function::builtin,
manifest::{escape_string_json, JsonFormat},
- typed::Any,
IStr, ObjValue, Val,
};
pub use toml::TomlFormat;
@@ -18,7 +17,7 @@
#[builtin]
pub fn builtin_manifest_json_ex(
- value: Any,
+ value: Val,
indent: IStr,
newline: Option<IStr>,
key_val_sep: Option<IStr>,
@@ -26,7 +25,7 @@
) -> Result<String> {
let newline = newline.as_deref().unwrap_or("\n");
let key_val_sep = key_val_sep.as_deref().unwrap_or(": ");
- value.0.manifest(JsonFormat::std_to_json(
+ value.manifest(JsonFormat::std_to_json(
indent.to_string(),
newline,
key_val_sep,
@@ -37,12 +36,12 @@
#[builtin]
pub fn builtin_manifest_yaml_doc(
- value: Any,
+ value: Val,
indent_array_in_object: Option<bool>,
quote_keys: Option<bool>,
#[cfg(feature = "exp-preserve-order")] preserve_order: Option<bool>,
) -> Result<String> {
- value.0.manifest(YamlFormat::std_to_yaml(
+ value.manifest(YamlFormat::std_to_yaml(
indent_array_in_object.unwrap_or(false),
quote_keys.unwrap_or(true),
#[cfg(feature = "exp-preserve-order")]
crates/jrsonnet-stdlib/src/math.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/math.rs
+++ b/crates/jrsonnet-stdlib/src/math.rs
@@ -1,88 +1,92 @@
-use jrsonnet_evaluator::{error::Result, function::builtin, typed::PositiveF64};
+use jrsonnet_evaluator::{function::builtin, typed::PositiveF64};
#[builtin]
-pub fn builtin_abs(n: f64) -> Result<f64> {
- Ok(n.abs())
+pub fn builtin_abs(n: f64) -> f64 {
+ n.abs()
}
#[builtin]
-pub fn builtin_sign(n: f64) -> Result<f64> {
- Ok(if n == 0. { 0. } else { n.signum() })
+pub fn builtin_sign(n: f64) -> f64 {
+ if n == 0. {
+ 0.
+ } else {
+ n.signum()
+ }
}
#[builtin]
-pub fn builtin_max(a: f64, b: f64) -> Result<f64> {
- Ok(a.max(b))
+pub fn builtin_max(a: f64, b: f64) -> f64 {
+ a.max(b)
}
#[builtin]
-pub fn builtin_min(a: f64, b: f64) -> Result<f64> {
- Ok(a.min(b))
+pub fn builtin_min(a: f64, b: f64) -> f64 {
+ a.min(b)
}
#[builtin]
-pub fn builtin_modulo(a: f64, b: f64) -> Result<f64> {
- Ok(a % b)
+pub fn builtin_modulo(x: f64, y: f64) -> f64 {
+ x % y
}
#[builtin]
-pub fn builtin_floor(x: f64) -> Result<f64> {
- Ok(x.floor())
+pub fn builtin_floor(x: f64) -> f64 {
+ x.floor()
}
#[builtin]
-pub fn builtin_ceil(x: f64) -> Result<f64> {
- Ok(x.ceil())
+pub fn builtin_ceil(x: f64) -> f64 {
+ x.ceil()
}
#[builtin]
-pub fn builtin_log(n: f64) -> Result<f64> {
- Ok(n.ln())
+pub fn builtin_log(x: f64) -> f64 {
+ x.ln()
}
#[builtin]
-pub fn builtin_pow(x: f64, n: f64) -> Result<f64> {
- Ok(x.powf(n))
+pub fn builtin_pow(x: f64, n: f64) -> f64 {
+ x.powf(n)
}
#[builtin]
-pub fn builtin_sqrt(x: PositiveF64) -> Result<f64> {
- Ok(x.0.sqrt())
+pub fn builtin_sqrt(x: PositiveF64) -> f64 {
+ x.0.sqrt()
}
#[builtin]
-pub fn builtin_sin(x: f64) -> Result<f64> {
- Ok(x.sin())
+pub fn builtin_sin(x: f64) -> f64 {
+ x.sin()
}
#[builtin]
-pub fn builtin_cos(x: f64) -> Result<f64> {
- Ok(x.cos())
+pub fn builtin_cos(x: f64) -> f64 {
+ x.cos()
}
#[builtin]
-pub fn builtin_tan(x: f64) -> Result<f64> {
- Ok(x.tan())
+pub fn builtin_tan(x: f64) -> f64 {
+ x.tan()
}
#[builtin]
-pub fn builtin_asin(x: f64) -> Result<f64> {
- Ok(x.asin())
+pub fn builtin_asin(x: f64) -> f64 {
+ x.asin()
}
#[builtin]
-pub fn builtin_acos(x: f64) -> Result<f64> {
- Ok(x.acos())
+pub fn builtin_acos(x: f64) -> f64 {
+ x.acos()
}
#[builtin]
-pub fn builtin_atan(x: f64) -> Result<f64> {
- Ok(x.atan())
+pub fn builtin_atan(x: f64) -> f64 {
+ x.atan()
}
#[builtin]
-pub fn builtin_exp(x: f64) -> Result<f64> {
- Ok(x.exp())
+pub fn builtin_exp(x: f64) -> f64 {
+ x.exp()
}
fn frexp(s: f64) -> (f64, i16) {
@@ -97,11 +101,11 @@
}
#[builtin]
-pub fn builtin_mantissa(x: f64) -> Result<f64> {
- Ok(frexp(x).0)
+pub fn builtin_mantissa(x: f64) -> f64 {
+ frexp(x).0
}
#[builtin]
-pub fn builtin_exponent(x: f64) -> Result<i16> {
- Ok(frexp(x).1)
+pub fn builtin_exponent(x: f64) -> i16 {
+ frexp(x).1
}
crates/jrsonnet-stdlib/src/misc.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/misc.rs
+++ b/crates/jrsonnet-stdlib/src/misc.rs
@@ -4,7 +4,7 @@
error::{ErrorKind::*, Result},
function::{builtin, ArgLike, CallLocation, FuncVal},
throw,
- typed::{Any, Either2, Either4},
+ typed::{Either2, Either4},
val::{equals, ArrValue},
Context, Either, IStr, ObjValue, Thunk, Val,
};
@@ -12,45 +12,41 @@
use crate::{extvar_source, Settings};
#[builtin]
-pub fn builtin_length(x: Either![IStr, ArrValue, ObjValue, FuncVal]) -> Result<usize> {
+pub fn builtin_length(x: Either![IStr, ArrValue, ObjValue, FuncVal]) -> usize {
use Either4::*;
- Ok(match x {
+ match x {
A(x) => x.chars().count(),
B(x) => x.len(),
C(x) => x.len(),
D(f) => f.params_len(),
- })
+ }
}
#[builtin(fields(
settings: Rc<RefCell<Settings>>,
))]
-pub fn builtin_ext_var(this: &builtin_ext_var, ctx: Context, x: IStr) -> Result<Any> {
+pub fn builtin_ext_var(this: &builtin_ext_var, ctx: Context, x: IStr) -> Result<Val> {
let ctx = ctx.state().create_default_context(extvar_source(&x, ""));
- Ok(Any(this
- .settings
+ this.settings
.borrow()
.ext_vars
.get(&x)
.cloned()
.ok_or_else(|| UndefinedExternalVariable(x))?
.evaluate_arg(ctx, true)?
- .evaluate()?))
+ .evaluate()
}
#[builtin(fields(
settings: Rc<RefCell<Settings>>,
))]
-pub fn builtin_native(this: &builtin_native, name: IStr) -> Result<Any> {
- Ok(Any(this
- .settings
+pub fn builtin_native(this: &builtin_native, x: IStr) -> Val {
+ this.settings
.borrow()
.ext_natives
- .get(&name)
+ .get(&x)
.cloned()
- .map_or(Val::Null, |v| {
- Val::Func(FuncVal::Builtin(v.clone()))
- })))
+ .map_or(Val::Null, |v| Val::Func(FuncVal::Builtin(v.clone())))
}
#[builtin(fields(
@@ -61,9 +57,9 @@
loc: CallLocation,
str: IStr,
rest: Thunk<Val>,
-) -> Result<Any> {
+) -> Result<Val> {
this.settings.borrow().trace_printer.print_trace(loc, str);
- Ok(Any(rest.evaluate()?))
+ rest.evaluate()
}
#[allow(clippy::comparison_chain)]
crates/jrsonnet-stdlib/src/objects.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/objects.rs
+++ b/crates/jrsonnet-stdlib/src/objects.rs
@@ -1,7 +1,5 @@
use jrsonnet_evaluator::{
- error::Result,
function::builtin,
- typed::VecVal,
val::{StrValue, Val},
IStr, ObjValue,
};
@@ -9,25 +7,23 @@
#[builtin]
pub fn builtin_object_fields_ex(
obj: ObjValue,
- inc_hidden: bool,
+ hidden: bool,
#[cfg(feature = "exp-preserve-order")] preserve_order: Option<bool>,
-) -> Result<VecVal> {
+) -> Vec<Val> {
#[cfg(feature = "exp-preserve-order")]
let preserve_order = preserve_order.unwrap_or(false);
let out = obj.fields_ex(
- inc_hidden,
+ hidden,
#[cfg(feature = "exp-preserve-order")]
preserve_order,
);
- Ok(VecVal(
- out.into_iter()
- .map(StrValue::Flat)
- .map(Val::Str)
- .collect::<Vec<_>>(),
- ))
+ out.into_iter()
+ .map(StrValue::Flat)
+ .map(Val::Str)
+ .collect::<Vec<_>>()
}
#[builtin]
-pub fn builtin_object_has_ex(obj: ObjValue, f: IStr, inc_hidden: bool) -> Result<bool> {
- Ok(obj.has_field_ex(f, inc_hidden))
+pub fn builtin_object_has_ex(obj: ObjValue, fname: IStr, hidden: bool) -> bool {
+ obj.has_field_ex(fname, hidden)
}
crates/jrsonnet-stdlib/src/operator.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/operator.rs
+++ b/crates/jrsonnet-stdlib/src/operator.rs
@@ -6,34 +6,34 @@
function::builtin,
operator::evaluate_mod_op,
stdlib::std_format,
- typed::{Any, Either, Either2},
+ typed::{Either, Either2},
val::{equals, primitive_equals, StrValue},
IStr, Val,
};
#[builtin]
-pub fn builtin_mod(a: Either![f64, IStr], b: Any) -> Result<Any> {
+pub fn builtin_mod(a: Either![f64, IStr], b: Val) -> Result<Val> {
use Either2::*;
- Ok(Any(evaluate_mod_op(
+ evaluate_mod_op(
&match a {
A(v) => Val::Num(v),
B(s) => Val::Str(StrValue::Flat(s)),
},
- &b.0,
- )?))
+ &b,
+ )
}
#[builtin]
-pub fn builtin_primitive_equals(a: Any, b: Any) -> Result<bool> {
- primitive_equals(&a.0, &b.0)
+pub fn builtin_primitive_equals(x: Val, y: Val) -> Result<bool> {
+ primitive_equals(&x, &y)
}
#[builtin]
-pub fn builtin_equals(a: Any, b: Any) -> Result<bool> {
- equals(&a.0, &b.0)
+pub fn builtin_equals(a: Val, b: Val) -> Result<bool> {
+ equals(&a, &b)
}
#[builtin]
-pub fn builtin_format(str: IStr, vals: Any) -> Result<String> {
- std_format(&str, vals.0)
+pub fn builtin_format(str: IStr, vals: Val) -> Result<String> {
+ std_format(&str, vals)
}
crates/jrsonnet-stdlib/src/parse.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/parse.rs
+++ b/crates/jrsonnet-stdlib/src/parse.rs
@@ -1,23 +1,22 @@
use jrsonnet_evaluator::{
error::{ErrorKind::RuntimeError, Result},
function::builtin,
- typed::Any,
IStr, Val,
};
use serde::Deserialize;
#[builtin]
-pub fn builtin_parse_json(s: IStr) -> Result<Any> {
- let value: Val = serde_json::from_str(&s)
+pub fn builtin_parse_json(str: IStr) -> Result<Val> {
+ let value: Val = serde_json::from_str(&str)
.map_err(|e| RuntimeError(format!("failed to parse json: {}", e).into()))?;
- Ok(Any(value))
+ Ok(value)
}
#[builtin]
-pub fn builtin_parse_yaml(s: IStr) -> Result<Any> {
+pub fn builtin_parse_yaml(str: IStr) -> Result<Val> {
use serde_yaml_with_quirks::DeserializingQuirks;
let value = serde_yaml_with_quirks::Deserializer::from_str_with_quirks(
- &s,
+ &str,
DeserializingQuirks { old_octals: true },
);
let mut out = vec![];
@@ -26,11 +25,11 @@
.map_err(|e| RuntimeError(format!("failed to parse yaml: {}", e).into()))?;
out.push(val);
}
- Ok(Any(if out.is_empty() {
+ Ok(if out.is_empty() {
Val::Null
} else if out.len() == 1 {
out.into_iter().next().unwrap()
} else {
Val::Arr(out.into())
- }))
+ })
}
crates/jrsonnet-stdlib/src/sort.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/sort.rs
+++ b/crates/jrsonnet-stdlib/src/sort.rs
@@ -2,11 +2,9 @@
error::Result,
function::{builtin, CallLocation, FuncVal},
throw,
- typed::Any,
val::ArrValue,
Context, Val,
};
-use jrsonnet_gcmodule::Cc;
#[derive(Copy, Clone)]
enum SortKeyType {
@@ -78,7 +76,7 @@
key_getter.evaluate(
ctx.clone(),
CallLocation::native(),
- &(Any(value.clone()),),
+ &(value.clone(),),
true,
)?,
));
@@ -105,9 +103,9 @@
if arr.len() <= 1 {
return Ok(arr);
}
- Ok(ArrValue::eager(Cc::new(super::sort::sort(
+ Ok(ArrValue::eager(super::sort::sort(
ctx,
arr.iter().collect::<Result<Vec<_>>>()?,
keyF.unwrap_or_else(FuncVal::identity),
- )?)))
+ )?))
}
crates/jrsonnet-stdlib/src/strings.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/strings.rs
+++ b/crates/jrsonnet-stdlib/src/strings.rs
@@ -2,19 +2,19 @@
error::{ErrorKind::*, Result},
function::builtin,
throw,
- typed::{Either2, VecVal, M1},
+ typed::{Either2, M1},
val::{ArrValue, StrValue},
Either, IStr, Val,
};
#[builtin]
-pub const fn builtin_codepoint(str: char) -> Result<u32> {
- Ok(str as u32)
+pub const fn builtin_codepoint(str: char) -> u32 {
+ str as u32
}
#[builtin]
-pub fn builtin_substr(str: IStr, from: usize, len: usize) -> Result<String> {
- Ok(str.chars().skip(from).take(len).collect())
+pub fn builtin_substr(str: IStr, from: usize, len: usize) -> String {
+ str.chars().skip(from).take(len).collect()
}
#[builtin]
@@ -23,14 +23,14 @@
}
#[builtin]
-pub fn builtin_str_replace(str: String, from: IStr, to: IStr) -> Result<String> {
- Ok(str.replace(&from as &str, &to as &str))
+pub fn builtin_str_replace(str: String, from: IStr, to: IStr) -> String {
+ str.replace(&from as &str, &to as &str)
}
#[builtin]
-pub fn builtin_splitlimit(str: IStr, c: IStr, maxsplits: Either![usize, M1]) -> Result<VecVal> {
+pub fn builtin_splitlimit(str: IStr, c: IStr, maxsplits: Either![usize, M1]) -> ArrValue {
use Either2::*;
- Ok(VecVal(match maxsplits {
+ match maxsplits {
A(n) => str
.splitn(n + 1, &c as &str)
.map(|s| Val::Str(StrValue::Flat(s.into())))
@@ -39,23 +39,23 @@
.split(&c as &str)
.map(|s| Val::Str(StrValue::Flat(s.into())))
.collect(),
- }))
+ }
}
#[builtin]
-pub fn builtin_ascii_upper(str: IStr) -> Result<String> {
- Ok(str.to_ascii_uppercase())
+pub fn builtin_ascii_upper(str: IStr) -> String {
+ str.to_ascii_uppercase()
}
#[builtin]
-pub fn builtin_ascii_lower(str: IStr) -> Result<String> {
- Ok(str.to_ascii_lowercase())
+pub fn builtin_ascii_lower(str: IStr) -> String {
+ str.to_ascii_lowercase()
}
#[builtin]
-pub fn builtin_find_substr(pat: IStr, str: IStr) -> Result<ArrValue> {
+pub fn builtin_find_substr(pat: IStr, str: IStr) -> ArrValue {
if pat.is_empty() || str.is_empty() || pat.len() > str.len() {
- return Ok(ArrValue::empty());
+ return ArrValue::empty();
}
let str = str.as_str();
@@ -74,7 +74,7 @@
out.push(Val::Num(ch_idx as f64))
}
}
- Ok(out.into())
+ out.into()
}
#[builtin]
crates/jrsonnet-stdlib/src/types.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/types.rs
+++ b/crates/jrsonnet-stdlib/src/types.rs
@@ -1,31 +1,31 @@
-use jrsonnet_evaluator::{error::Result, function::builtin, typed::Any, IStr, Val};
+use jrsonnet_evaluator::{function::builtin, IStr, Val};
#[builtin]
-pub fn builtin_type(v: Any) -> Result<IStr> {
- Ok(v.0.value_type().name().into())
+pub fn builtin_type(x: Val) -> IStr {
+ x.value_type().name().into()
}
#[builtin]
-pub fn builtin_is_string(v: Any) -> Result<bool> {
- Ok(matches!(v.0, Val::Str(_)))
+pub fn builtin_is_string(v: Val) -> bool {
+ matches!(v, Val::Str(_))
}
#[builtin]
-pub fn builtin_is_number(v: Any) -> Result<bool> {
- Ok(matches!(v.0, Val::Num(_)))
+pub fn builtin_is_number(v: Val) -> bool {
+ matches!(v, Val::Num(_))
}
#[builtin]
-pub fn builtin_is_boolean(v: Any) -> Result<bool> {
- Ok(matches!(v.0, Val::Bool(_)))
+pub fn builtin_is_boolean(v: Val) -> bool {
+ matches!(v, Val::Bool(_))
}
#[builtin]
-pub fn builtin_is_object(v: Any) -> Result<bool> {
- Ok(matches!(v.0, Val::Obj(_)))
+pub fn builtin_is_object(v: Val) -> bool {
+ matches!(v, Val::Obj(_))
}
#[builtin]
-pub fn builtin_is_array(v: Any) -> Result<bool> {
- Ok(matches!(v.0, Val::Arr(_)))
+pub fn builtin_is_array(v: Val) -> bool {
+ matches!(v, Val::Arr(_))
}
#[builtin]
-pub fn builtin_is_function(v: Any) -> Result<bool> {
- Ok(matches!(v.0, Val::Func(_)))
+pub fn builtin_is_function(v: Val) -> bool {
+ matches!(v, Val::Func(_))
}
tests/tests/builtin.rsdiffbeforeafterboth--- a/tests/tests/builtin.rs
+++ b/tests/tests/builtin.rs
@@ -3,11 +3,9 @@
use jrsonnet_evaluator::{
error::Result,
function::{builtin, builtin::Builtin, CallLocation, FuncVal},
- tb,
typed::Typed,
ContextBuilder, State, Thunk, Val,
};
-use jrsonnet_gcmodule::Cc;
use jrsonnet_stdlib::StateExt;
#[builtin]
@@ -63,7 +61,7 @@
#[builtin]
fn curry_add(a: u32) -> Result<FuncVal> {
- Ok(FuncVal::Builtin(Cc::new(tb!(curried_add { a }))))
+ Ok(FuncVal::builtin(curried_add { a }))
}
#[test]
tests/tests/common.rsdiffbeforeafterboth--- a/tests/tests/common.rs
+++ b/tests/tests/common.rs
@@ -1,3 +1,5 @@
+use std::borrow::Cow;
+
use jrsonnet_evaluator::{
error::Result,
function::{builtin, FuncVal},
@@ -53,13 +55,47 @@
Ok(true)
}
+#[builtin]
+fn param_names(fun: FuncVal) -> Vec<String> {
+ match fun {
+ FuncVal::Id => vec!["x".to_string()],
+ FuncVal::Normal(func) => func
+ .params
+ .iter()
+ .map(|p| p.0.name().unwrap_or_else(|| "<unnamed>".into()).to_string())
+ .collect(),
+ FuncVal::StaticBuiltin(b) => b
+ .params()
+ .iter()
+ .map(|p| {
+ p.name
+ .as_ref()
+ .unwrap_or(&Cow::Borrowed("<unnamed>"))
+ .to_string()
+ })
+ .collect(),
+ FuncVal::Builtin(b) => b
+ .params()
+ .iter()
+ .map(|p| {
+ p.name
+ .as_ref()
+ .unwrap_or(&Cow::Borrowed("<unnamed>"))
+ .to_string()
+ })
+ .collect(),
+ }
+}
+
#[allow(dead_code)]
pub fn with_test(s: &State) {
let mut bobj = ObjValueBuilder::new();
bobj.member("assertThrow".into())
.hide()
- .value(Val::Func(FuncVal::StaticBuiltin(assert_throw::INST)))
- .expect("no error");
+ .value_unchecked(Val::Func(FuncVal::StaticBuiltin(assert_throw::INST)));
+ bobj.member("paramNames".into())
+ .hide()
+ .value_unchecked(Val::Func(FuncVal::StaticBuiltin(param_names::INST)));
s.add_global("test".into(), Thunk::evaluated(Val::Obj(bobj.build())))
}
tests/tests/golden.rsdiffbeforeafterboth--- a/tests/tests/golden.rs
+++ b/tests/tests/golden.rs
@@ -16,7 +16,7 @@
let s = State::default();
s.with_stdlib();
common::with_test(&s);
- s.set_import_resolver(Box::new(FileImportResolver::default()));
+ s.set_import_resolver(FileImportResolver::default());
let trace_format = CompactFormat {
resolver: PathResolver::FileName,
max_trace: 20,
tests/tests/suite.rsdiffbeforeafterboth--- a/tests/tests/suite.rs
+++ b/tests/tests/suite.rs
@@ -15,7 +15,7 @@
let s = State::default();
s.with_stdlib();
common::with_test(&s);
- s.set_import_resolver(Box::new(FileImportResolver::default()));
+ s.set_import_resolver(FileImportResolver::default());
let trace_format = CompactFormat::default();
match s.import(file) {