--- 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 --- 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 }), ) } --- 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(), } } --- 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. --- 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(()) --- 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>) -> Self { - Self::Eager(EagerArray(values)) + pub fn eager(values: Vec) -> Self { + Self::Eager(EagerArray(Cc::new(values))) } pub fn repeated(data: ArrValue, repeats: usize) -> Option { @@ -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> for ArrValue { fn from(value: Vec) -> Self { - Self::eager(Cc::new(value)) + Self::eager(value) } } impl From>> for ArrValue { @@ -243,6 +243,11 @@ Self::lazy(Cc::new(value)) } } +impl FromIterator for ArrValue { + fn from_iter>(iter: T) -> Self { + Self::eager(iter.into_iter().collect()) + } +} #[cfg(target_pointer_width = "64")] static_assertions::assert_eq_size!(ArrValue, [u8; 16]); --- a/crates/jrsonnet-evaluator/src/arr/spec.rs +++ b/crates/jrsonnet-evaluator/src/arr/spec.rs @@ -7,10 +7,10 @@ use jrsonnet_interner::IBytes; use jrsonnet_parser::LocExpr; -use super::{ArrValue, ArrayLikeIter}; +use super::ArrValue; use crate::{ - error::ErrorKind::InfiniteRecursionDetected, evaluate, function::FuncVal, tb, typed::Any, - val::ThunkValue, Context, Error, Result, Thunk, Val, + error::ErrorKind::InfiniteRecursionDetected, evaluate, function::FuncVal, val::ThunkValue, + Context, Error, Result, Thunk, Val, }; pub trait ArrayLike: Sized + Into { @@ -75,7 +75,7 @@ } #[cfg(not(feature = "nightly"))] - fn iter_cheap(&self) -> Option + '_> { + fn iter_cheap(&self) -> Option + '_> { Some( self.inner .iter_cheap()? @@ -300,10 +300,10 @@ ArrayThunk::Waiting(_) | ArrayThunk::Pending => {} }; - Some(Thunk::new(tb!(ArrayElement { + Some(Thunk::new(ArrayElement { arr_thunk: self.clone(), index, - }))) + })) } fn get_cheap(&self, _index: usize) -> Option { None @@ -748,7 +748,7 @@ .get(index) .transpose() .expect("index checked") - .and_then(|r| self.0.mapper.evaluate_simple(&(Any(r),))); + .and_then(|r| self.0.mapper.evaluate_simple(&(r,))); let new_value = match val { Ok(v) => v, @@ -787,10 +787,10 @@ ArrayThunk::Waiting(_) | ArrayThunk::Pending => {} }; - Some(Thunk::new(tb!(ArrayElement { + Some(Thunk::new(ArrayElement { arr_thunk: self.clone(), index, - }))) + })) } fn get_cheap(&self, _index: usize) -> Option { --- 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(()) } --- 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 { - &self.0.dollar + pub fn dollar(&self) -> Option<&ObjValue> { + self.0.dollar.as_ref() } - pub fn this(&self) -> &Option { - &self.0.this + pub fn this(&self) -> Option<&ObjValue> { + self.0.this.as_ref() } - pub fn super_obj(&self) -> &Option { - &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 { --- 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())) --- 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( loc: CallLocation<'_>, ctx: &Context, - expr: &Option, + expr: Option<&LocExpr>, desc: &'static str, ) -> Result> { 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)?)? } --- 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 {} 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(), - })) + }) }, )?; } --- 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>, - handler: TraceBox, - ) -> Self { + pub fn new(params: Vec>, handler: impl NativeCallbackHandler) -> Self { Self { params: params .into_iter() @@ -54,7 +51,7 @@ has_default: false, }) .collect(), - handler, + handler: tb!(handler), } } } --- 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 { - Ok(v) + const fn builtin_id(x: Val) -> Val { + x } static ID: &builtin_id = &builtin_id {}; --- 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(|| "".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(|| "".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(|| "".into()), - params.clone() - ))), + params.clone(), + )), fctx.clone(), &mut bindings, )?; --- 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(self, mut map: A) -> Result --- 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) { - 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); + } } --- 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) -> &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> { @@ -631,8 +631,8 @@ pub fn thunk(self, value: Thunk) -> Result<()> { self.binding(MaybeUnbound::Bound(value)) } - pub fn bindable(self, bindable: TraceBox>) -> Result<()> { - self.binding(MaybeUnbound::Unbound(Cc::new(bindable))) + pub fn bindable(self, bindable: impl Unbound) -> Result<()> { + self.binding(MaybeUnbound::Unbound(Cc::new(tb!(bindable)))) } pub fn binding(self, binding: MaybeUnbound) -> Result<()> { let (receiver, name, member) = self.build_member(binding); --- 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; fn from_untyped(untyped: Val) -> Result; + + /// 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 { + 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 { - 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::>()?, + )) } fn from_untyped(value: Val) -> Result { - ::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 { + ::TYPE.check(&value)?; + unreachable!("typecheck should fail") + }; + a.iter() + .map(|r| r.and_then(T::from_untyped)) + .collect::>>() } } -/// To be used in Vec -/// 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 { - Ok(value.0) + fn into_untyped(typed: Self) -> Result { + Ok(typed) } - - fn from_untyped(value: Val) -> Result { - Ok(Self(value)) + fn from_untyped(untyped: Val) -> Result { + Ok(untyped) } } -/// Specialization, provides faster `TryFrom` for Val -pub struct VecVal(pub Vec); +// Hack +#[doc(hidden)] +impl Typed for Result +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 { + panic!("do not use this conversion") + } - fn into_untyped(value: Self) -> Result { - Ok(Val::Arr(ArrValue::eager(Cc::new(value.0)))) + fn from_untyped(_untyped: Val) -> Result { + panic!("do not use this conversion") } - fn from_untyped(value: Val) -> Result { - ::TYPE.check(&value)?; - match value { - Val::Arr(a) => Ok(Self(a.iter().collect::>>()?)), - _ => unreachable!(), - } + fn into_result(typed: Self) -> Result { + typed.map(T::into_untyped)? } } --- 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>) -> Self { - Self(Cc::new(RefCell::new(ThunkInner::Waiting(f)))) + pub fn new(f: impl ThunkValue + '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)))) --- 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 { +fn builtin_inner( + attr: BuiltinAttrs, + fun: ItemFn, + item: proc_macro2::TokenStream, +) -> syn::Result { 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) } } }; --- 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 { @@ -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 { - Ok(Any(match what { +pub fn builtin_repeat(what: Either![IStr, ArrValue], count: usize) -> Result { + 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>, end: Option>, step: Option>, -) -> Result { - indexable.slice(index, end, step).map(Val::from).map(Any) +) -> Result { + 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 { 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 { - 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 { - let mut acc = init.0; +pub fn builtin_foldl(func: FuncVal, arr: ArrValue, init: Val) -> Result { + 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 { - let mut acc = init.0; +pub fn builtin_foldr(func: FuncVal, arr: ArrValue, init: Val) -> Result { + 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 { - 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 { +pub fn builtin_member(arr: IndexableVal, x: Val) -> Result { 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, v: Any) -> Result { +pub fn builtin_count(arr: ArrValue, x: Val) -> Result { 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; } } --- 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 { - 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 { +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 { - Ok(base64::decode(input.as_bytes()) +pub fn builtin_base64_decode_bytes(str: IStr) -> Result { + Ok(base64::decode(str.as_bytes()) .map_err(|_| RuntimeError("bad base64".into()))? .as_slice() .into()) } #[builtin] -pub fn builtin_base64_decode(input: IStr) -> Result { - let bytes = base64::decode(input.as_bytes()).map_err(|_| RuntimeError("bad base64".into()))?; +pub fn builtin_base64_decode(str: IStr) -> Result { + let bytes = base64::decode(str.as_bytes()).map_err(|_| RuntimeError("bad base64".into()))?; Ok(String::from_utf8(bytes).map_err(|_| RuntimeError("bad utf8".into()))?) } --- 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 { - 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 { +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())) } --- 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>) { - 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 { --- 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, key_val_sep: Option, @@ -26,7 +25,7 @@ ) -> Result { 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, quote_keys: Option, #[cfg(feature = "exp-preserve-order")] preserve_order: Option, ) -> Result { - 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")] --- 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 { - Ok(n.abs()) +pub fn builtin_abs(n: f64) -> f64 { + n.abs() } #[builtin] -pub fn builtin_sign(n: f64) -> Result { - 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 { - 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 { - 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 { - Ok(a % b) +pub fn builtin_modulo(x: f64, y: f64) -> f64 { + x % y } #[builtin] -pub fn builtin_floor(x: f64) -> Result { - Ok(x.floor()) +pub fn builtin_floor(x: f64) -> f64 { + x.floor() } #[builtin] -pub fn builtin_ceil(x: f64) -> Result { - Ok(x.ceil()) +pub fn builtin_ceil(x: f64) -> f64 { + x.ceil() } #[builtin] -pub fn builtin_log(n: f64) -> Result { - Ok(n.ln()) +pub fn builtin_log(x: f64) -> f64 { + x.ln() } #[builtin] -pub fn builtin_pow(x: f64, n: f64) -> Result { - Ok(x.powf(n)) +pub fn builtin_pow(x: f64, n: f64) -> f64 { + x.powf(n) } #[builtin] -pub fn builtin_sqrt(x: PositiveF64) -> Result { - Ok(x.0.sqrt()) +pub fn builtin_sqrt(x: PositiveF64) -> f64 { + x.0.sqrt() } #[builtin] -pub fn builtin_sin(x: f64) -> Result { - Ok(x.sin()) +pub fn builtin_sin(x: f64) -> f64 { + x.sin() } #[builtin] -pub fn builtin_cos(x: f64) -> Result { - Ok(x.cos()) +pub fn builtin_cos(x: f64) -> f64 { + x.cos() } #[builtin] -pub fn builtin_tan(x: f64) -> Result { - Ok(x.tan()) +pub fn builtin_tan(x: f64) -> f64 { + x.tan() } #[builtin] -pub fn builtin_asin(x: f64) -> Result { - Ok(x.asin()) +pub fn builtin_asin(x: f64) -> f64 { + x.asin() } #[builtin] -pub fn builtin_acos(x: f64) -> Result { - Ok(x.acos()) +pub fn builtin_acos(x: f64) -> f64 { + x.acos() } #[builtin] -pub fn builtin_atan(x: f64) -> Result { - Ok(x.atan()) +pub fn builtin_atan(x: f64) -> f64 { + x.atan() } #[builtin] -pub fn builtin_exp(x: f64) -> Result { - 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 { - Ok(frexp(x).0) +pub fn builtin_mantissa(x: f64) -> f64 { + frexp(x).0 } #[builtin] -pub fn builtin_exponent(x: f64) -> Result { - Ok(frexp(x).1) +pub fn builtin_exponent(x: f64) -> i16 { + frexp(x).1 } --- 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 { +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>, ))] -pub fn builtin_ext_var(this: &builtin_ext_var, ctx: Context, x: IStr) -> Result { +pub fn builtin_ext_var(this: &builtin_ext_var, ctx: Context, x: IStr) -> Result { 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>, ))] -pub fn builtin_native(this: &builtin_native, name: IStr) -> Result { - 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, -) -> Result { +) -> Result { this.settings.borrow().trace_printer.print_trace(loc, str); - Ok(Any(rest.evaluate()?)) + rest.evaluate() } #[allow(clippy::comparison_chain)] --- 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, -) -> Result { +) -> Vec { #[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::>(), - )) + out.into_iter() + .map(StrValue::Flat) + .map(Val::Str) + .collect::>() } #[builtin] -pub fn builtin_object_has_ex(obj: ObjValue, f: IStr, inc_hidden: bool) -> Result { - 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) } --- 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 { +pub fn builtin_mod(a: Either![f64, IStr], b: Val) -> Result { 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 { - primitive_equals(&a.0, &b.0) +pub fn builtin_primitive_equals(x: Val, y: Val) -> Result { + primitive_equals(&x, &y) } #[builtin] -pub fn builtin_equals(a: Any, b: Any) -> Result { - equals(&a.0, &b.0) +pub fn builtin_equals(a: Val, b: Val) -> Result { + equals(&a, &b) } #[builtin] -pub fn builtin_format(str: IStr, vals: Any) -> Result { - std_format(&str, vals.0) +pub fn builtin_format(str: IStr, vals: Val) -> Result { + std_format(&str, vals) } --- 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 { - let value: Val = serde_json::from_str(&s) +pub fn builtin_parse_json(str: IStr) -> Result { + 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 { +pub fn builtin_parse_yaml(str: IStr) -> Result { 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()) - })) + }) } --- 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::>>()?, keyF.unwrap_or_else(FuncVal::identity), - )?))) + )?)) } --- 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 { - 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 { - 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 { - 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 { +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 { - 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 { - 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 { +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] --- 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - Ok(matches!(v.0, Val::Func(_))) +pub fn builtin_is_function(v: Val) -> bool { + matches!(v, Val::Func(_)) } --- 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 { - Ok(FuncVal::Builtin(Cc::new(tb!(curried_add { a })))) + Ok(FuncVal::builtin(curried_add { a })) } #[test] --- 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 { + match fun { + FuncVal::Id => vec!["x".to_string()], + FuncVal::Normal(func) => func + .params + .iter() + .map(|p| p.0.name().unwrap_or_else(|| "".into()).to_string()) + .collect(), + FuncVal::StaticBuiltin(b) => b + .params() + .iter() + .map(|p| { + p.name + .as_ref() + .unwrap_or(&Cow::Borrowed("")) + .to_string() + }) + .collect(), + FuncVal::Builtin(b) => b + .params() + .iter() + .map(|p| { + p.name + .as_ref() + .unwrap_or(&Cow::Borrowed("")) + .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()))) } --- 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, --- 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) {