git.delta.rocks / jrsonnet / refs/commits / 150f28648ad3

difftreelog

refactor always use prepared calls

wulxrvxzYaroslav Bolyukin2026-04-04parent: #0f5b614.patch.diff
in: master

17 files changed

modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
19 destructure::evaluate_dest,19 destructure::evaluate_dest,
20 error::{ErrorKind::*, suggest_object_fields},20 error::{ErrorKind::*, suggest_object_fields},
21 evaluate::operator::{evaluate_binary_op_special, evaluate_unary_op},21 evaluate::operator::{evaluate_binary_op_special, evaluate_unary_op},
22 function::{CallLocation, FuncDesc, FuncVal},22 function::{CallLocation, FuncDesc, FuncVal, PreparedFuncVal},
23 gc::WithCapacityExt as _,23 gc::WithCapacityExt as _,
24 in_frame,24 in_frame,
25 typed::{FromUntyped, IntoUntyped as _, Typed},25 typed::{FromUntyped, IntoUntyped as _, Typed},
430 let value = evaluate(ctx.clone(), value)?;430 let value = evaluate(ctx.clone(), value)?;
431 Ok(match value {431 Ok(match value {
432 Val::Func(f) => {432 Val::Func(f) => {
433 let name = f.name();
434 let prepare = PreparedFuncVal::new(f, args.unnamed.len(), &args.names)?;
435 let unnamed = args
436 .unnamed
437 .iter()
438 .cloned()
439 .map(|un| evaluate_thunk(ctx.clone(), un, tailstrict))
440 .collect::<Result<Vec<_>>>()?;
441 let named = args
442 .values
443 .iter()
444 .cloned()
445 .map(|un| evaluate_thunk(ctx.clone(), un, tailstrict))
446 .collect::<Result<Vec<_>>>()?;
433 let body = || f.evaluate(ctx, loc, args, tailstrict);447 let body = || prepare.call(loc, &unnamed, &named);
434 if tailstrict {448 if tailstrict {
435 body()?449 body()?
436 } else {450 } else {
437 in_frame(loc, || format!("function <{}> call", f.name()), body)?451 in_frame(loc, || format!("function <{name}> call"), body)?
438 }452 }
439 }453 }
440 v => bail!(OnlyFunctionsCanBeCalledGot(v.value_type())),454 v => bail!(OnlyFunctionsCanBeCalledGot(v.value_type())),
479 })493 })
480}494}
481495
496pub fn evaluate_thunk(ctx: Context, expr: Rc<Expr>, tailstrict: bool) -> Result<Thunk<Val>> {
497 Ok(if tailstrict {
498 Thunk::evaluated(evaluate(ctx, &expr)?)
499 } else {
500 Thunk!(move || { evaluate(ctx, &expr) })
501 })
502}
482#[allow(clippy::too_many_lines)]503#[allow(clippy::too_many_lines)]
483pub fn evaluate(ctx: Context, expr: &Expr) -> Result<Val> {504pub fn evaluate(ctx: Context, expr: &Expr) -> Result<Val> {
484 use Expr::*;505 use Expr::*;
modifiedcrates/jrsonnet-evaluator/src/function/mod.rsdiffbeforeafterboth
3use educe::Educe;3use educe::Educe;
4use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_gcmodule::{Cc, Trace};
5use jrsonnet_interner::IStr;5use jrsonnet_interner::IStr;
6use jrsonnet_ir::{ArgsDesc, Destruct, Expr, ExprParams, Span};6use jrsonnet_ir::{Destruct, Expr, ExprParams, Span};
7pub use jrsonnet_macros::builtin;7pub use jrsonnet_macros::builtin;
88
9use self::{9use self::{
10 builtin::Builtin,10 builtin::Builtin,
11 parse::{parse_builtin_call, parse_default_function_call, parse_function_call},11 parse::parse_default_function_call,
12 prepared::{PreparedCall, parse_prepared_builtin_call, parse_prepared_function_call},12 prepared::{PreparedCall, parse_prepared_builtin_call, parse_prepared_function_call},
13};13};
14use crate::{14use crate::{
2222
23pub use jrsonnet_ir::function::*;23pub use jrsonnet_ir::function::*;
24pub use native::NativeFn;24pub use native::NativeFn;
25pub use prepared::PreparedFuncVal;25pub(crate) use prepared::PreparedFuncVal;
2626
27/// Function callsite location.27/// Function callsite location.
28/// Either from other jsonnet code, specified by expression location, or from native (without location).28/// Either from other jsonnet code, specified by expression location, or from native (without location).
77 parse_default_function_call(self.ctx.clone(), &self.params)77 parse_default_function_call(self.ctx.clone(), &self.params)
78 }78 }
79
80 /// Create context, with which body code will run
81 pub(crate) fn call_body_context(
82 &self,
83 call_ctx: Context,
84 args: &ArgsDesc,
85 tailstrict: bool,
86 ) -> Result<Context> {
87 parse_function_call(call_ctx, self.ctx.clone(), &self.params, args, tailstrict)
88 }
8979
90 pub fn evaluate_trivial(&self) -> Option<Val> {80 pub fn evaluate_trivial(&self) -> Option<Val> {
91 evaluate_trivial(&self.body)81 evaluate_trivial(&self.body)
139 Self::Builtin(builtin) => builtin.name().into(),129 Self::Builtin(builtin) => builtin.name().into(),
140 }130 }
141 }131 }
142 /// Call function using arguments evaluated in specified `call_ctx` [`Context`].
143 ///
144 /// If `tailstrict` is specified - then arguments will be evaluated before being passed to function body.
145 pub fn evaluate(
146 &self,
147 call_ctx: Context,
148 loc: CallLocation<'_>,
149 args: &ArgsDesc,
150 tailstrict: bool,
151 ) -> Result<Val> {
152 match self {
153 Self::Normal(func) => {
154 let body_ctx = func.call_body_context(call_ctx, args, tailstrict)?;
155 evaluate(body_ctx, &func.body)
156 }
157 Self::Builtin(b) => {
158 let args = parse_builtin_call(call_ctx, b.params(), args, tailstrict)?;
159 b.call(loc, &args)
160 }
161 }
162 }
163132
164 pub(crate) fn evaluate_prepared(133 pub(crate) fn evaluate_prepared(
165 &self,134 &self,
modifiedcrates/jrsonnet-evaluator/src/function/native.rsdiffbeforeafterboth
36 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);36 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);
37 }37 }
3838
39 impl<$($gen,)* O> FromUntyped for NativeFn<($($gen,)* O,)> {39 impl<$($gen,)* O> FromUntyped for NativeFn<($($gen,)* O,)> {
40 fn from_untyped(untyped: Val) -> Result<Self> {40 fn from_untyped(untyped: Val) -> Result<Self> {
41 let func = FuncVal::from_untyped(untyped)?;
42 Self::try_from(func)
43 }
44 }
45 impl<$($gen,)* O> TryFrom<FuncVal> for NativeFn<($($gen,)* O,)> {
41 let func = FuncVal::from_untyped(untyped)?;46 type Error = crate::Error;
47 fn try_from(v: FuncVal) -> Result<Self> {
42 Ok(Self(48 Ok(Self(
43 PreparedFuncVal::new(func, $i, &[])?,49 PreparedFuncVal::new(v, $i, &[])?,
44 PhantomData,50 PhantomData,
45 ))51 ))
52 }
46 }53 }
47 }54
48 };55 };
49 ($i:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {56 ($i:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {
50 impl_native_desc!($i; $($cur)*);57 impl_native_desc!($i; $($cur)*);
modifiedcrates/jrsonnet-evaluator/src/function/parse.rsdiffbeforeafterboth
1use std::rc::Rc;
2
3use jrsonnet_ir::{1use jrsonnet_ir::ExprParams;
4 ArgsDesc, Expr, ExprParams,
5 function::{FunctionSignature, ParamName},
6};
7use rustc_hash::FxHashMap;2use rustc_hash::FxHashMap;
83
9use crate::{4use crate::{
10 Context, Pending, Thunk, Val, bail,5 Context, Thunk,
11 destructure::destruct,6 destructure::destruct,
12 error::{ErrorKind::*, Result},7 error::{ErrorKind::*, Result},
13 evaluate, evaluate_named_param,8 evaluate_named_param,
14 gc::WithCapacityExt as _,9 gc::WithCapacityExt as _,
15};10};
16
17fn eval_arg(ctx: Context, arg: &Rc<Expr>, tailstrict: bool) -> Result<Thunk<Val>> {
18 if tailstrict {
19 Ok(Thunk::evaluated(evaluate(ctx, arg)?))
20 } else {
21 let arg = arg.clone();
22 Ok(Thunk!(move || evaluate(ctx, &arg)))
23 }
24}
25
26/// Creates correct [context](Context) for function body evaluation returning error on invalid call.
27///
28/// ## Parameters
29/// * `ctx`: used for passed argument expressions' execution and for body execution (if `body_ctx` is not set)
30/// * `body_ctx`: used for default parameter values' execution and for body execution (if set)
31/// * `params`: function parameters' definition
32/// * `args`: passed function arguments
33/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily
34pub(crate) fn parse_function_call(
35 ctx: Context,
36 body_ctx: Context,
37 params: &ExprParams,
38 args: &ArgsDesc,
39 tailstrict: bool,
40) -> Result<Context> {
41 let mut passed_args = FxHashMap::with_capacity(params.binds_len());
42 if args.unnamed.len() > params.signature.len() {
43 bail!(TooManyArgsFunctionHas(
44 params.signature.len(),
45 params.signature.clone(),
46 ))
47 }
48
49 let mut filled_named = 0;
50 let mut filled_positionals = 0;
51
52 for (id, arg) in args.unnamed.iter().enumerate() {
53 destruct(
54 &params.exprs[id].destruct,
55 eval_arg(ctx.clone(), arg, tailstrict)?,
56 Pending::new_filled(ctx.clone()),
57 &mut passed_args,
58 )?;
59 filled_positionals += 1;
60 }
61
62 for (name, value) in &args.named {
63 // FIXME: O(n) for arg existence check
64 if !params.exprs.iter().any(|p| &p.destruct.name() == name) {
65 bail!(UnknownFunctionParameter(name.clone()));
66 }
67 if passed_args
68 .insert(name.clone(), eval_arg(ctx.clone(), value, tailstrict)?)
69 .is_some()
70 {
71 bail!(BindingParameterASecondTime(name.clone()));
72 }
73 filled_named += 1;
74 }
75
76 if filled_named + filled_positionals < params.len() {
77 // Some args are unset, but maybe we have defaults for them
78 // Default values should be created in newly created context
79 let fctx = Context::new_future();
80 let mut defaults =
81 FxHashMap::with_capacity(params.binds_len() - filled_named - filled_positionals);
82
83 for (idx, into, default) in params
84 .exprs
85 .iter()
86 .enumerate()
87 .filter_map(|(i, p)| Some((i, &p.destruct, p.default.as_ref()?)))
88 {
89 if let ParamName::Named(name) = into.name() {
90 if passed_args.contains_key(&name) {
91 continue;
92 }
93 } else if idx < filled_positionals {
94 continue;
95 }
96
97 destruct(
98 into,
99 {
100 let ctx = fctx.clone();
101 let name = into.name();
102 let value = default.clone();
103 Thunk!(move || evaluate_named_param(ctx.unwrap(), &value, name))
104 },
105 fctx.clone(),
106 &mut defaults,
107 )?;
108 if into.name().is_named() {
109 filled_named += 1;
110 } else {
111 filled_positionals += 1;
112 }
113 }
114
115 // Some args still weren't filled
116 if filled_named + filled_positionals != params.len() {
117 for param in params.exprs.iter().skip(args.unnamed.len()) {
118 let mut found = false;
119 for (name, _) in &args.named {
120 if &param.destruct.name() == name {
121 found = true;
122 }
123 }
124 if !found {
125 bail!(FunctionParameterNotBoundInCall(
126 param.destruct.name(),
127 params.signature.clone()
128 ));
129 }
130 }
131 unreachable!();
132 }
133
134 Ok(body_ctx
135 .extend_bindings(passed_args)
136 .extend_bindings(defaults)
137 .into_future(fctx))
138 } else {
139 let body_ctx = body_ctx.extend_bindings(passed_args);
140 Ok(body_ctx)
141 }
142}
143
144/// You shouldn't probally use this function, use `jrsonnet_macros::builtin` instead
145///
146/// ## Parameters
147/// * `ctx`: used for passed argument expressions' execution and for body execution (if `body_ctx` is not set)
148/// * `params`: function parameters' definition
149/// * `args`: passed function arguments
150/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily
151pub fn parse_builtin_call(
152 ctx: Context,
153 params: FunctionSignature,
154 args: &ArgsDesc,
155 tailstrict: bool,
156) -> Result<Vec<Option<Thunk<Val>>>> {
157 let mut passed_args: Vec<Option<Thunk<Val>>> = vec![None; params.len()];
158 if args.unnamed.len() > params.len() {
159 bail!(TooManyArgsFunctionHas(params.len(), params,))
160 }
161
162 let mut filled_args = 0;
163
164 for (id, arg) in args.unnamed.iter().enumerate() {
165 passed_args[id] = Some(eval_arg(ctx.clone(), arg, tailstrict)?);
166 filled_args += 1;
167 }
168
169 for (name, arg) in &args.named {
170 // FIXME: O(n) for arg existence check
171 let id = params
172 .iter()
173 .position(|p| p.name() == name)
174 .ok_or_else(|| UnknownFunctionParameter(name.clone()))?;
175 if passed_args[id]
176 .replace(eval_arg(ctx.clone(), arg, tailstrict)?)
177 .is_some()
178 {
179 bail!(BindingParameterASecondTime(name.clone()));
180 }
181 filled_args += 1;
182 }
183
184 if filled_args < params.len() {
185 for (id, _) in params.iter().enumerate().filter(|(_, p)| p.has_default()) {
186 if passed_args[id].is_some() {
187 continue;
188 }
189 filled_args += 1;
190 }
191
192 // Some args still wasn't filled
193 if filled_args != params.len() {
194 for param in params.iter().skip(args.unnamed.len()) {
195 let mut found = false;
196 for (name, _) in &args.named {
197 if param.name() == name {
198 found = true;
199 }
200 }
201 if !found {
202 bail!(FunctionParameterNotBoundInCall(
203 param.name().clone(),
204 params,
205 ));
206 }
207 }
208 unreachable!();
209 }
210 }
211 Ok(passed_args)
212}
21311
214/// Creates Context, which has all argument default values applied12/// Creates Context, which has all argument default values applied
215/// and with unbound values causing error to be returned13/// and with unbound values causing error to be returned
modifiedcrates/jrsonnet-ir-parser/src/lib.rsdiffbeforeafterboth
416416
417fn args(p: &mut Parser<'_>) -> Result<ArgsDesc> {417fn args(p: &mut Parser<'_>) -> Result<ArgsDesc> {
418 if p.at(T![')']) {418 if p.at(T![')']) {
419 return Ok(ArgsDesc::new(Vec::new(), Vec::new()));419 return Ok(ArgsDesc::new(Vec::new(), Vec::new(), Vec::new()));
420 }420 }
421 let mut unnamed = Vec::new();421 let mut unnamed = Vec::new();
422 let mut named = Vec::new();422 let mut names = Vec::new();
423 let mut values = Vec::new();
423 let mut named_started = false;424 let mut named_started = false;
424 loop {425 loop {
425 let is_named = p.at(SyntaxKind::IDENT) && {426 let is_named = p.at(SyntaxKind::IDENT) && {
430 let name: IStr = ident(p)?;431 let name: IStr = ident(p)?;
431 p.eat(T![=])?;432 p.eat(T![=])?;
432 let value = Rc::new(expr(p)?);433 let value = Rc::new(expr(p)?);
434
433 named.push((name, value));435 names.push(name);
436 values.push(value);
434 named_started = true;437 named_started = true;
435 } else {438 } else {
436 if named_started {439 if named_started {
445 break;448 break;
446 }449 }
447 }450 }
448 Ok(ArgsDesc::new(unnamed, named))451 Ok(ArgsDesc::new(unnamed, names, values))
449}452}
450453
451fn bind(p: &mut Parser<'_>) -> Result<BindSpec> {454fn bind(p: &mut Parser<'_>) -> Result<BindSpec> {
modifiedcrates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__function_and_call.snapdiffbeforeafterboth
66 2.0,66 2.0,
67 ),67 ),
68 ],68 ],
69 named: [69 names: [
70 (70 "y",
71 "y",
72 Num(71 ],
73 3.0,72 values: [
73 Num(
74 ),74 3.0,
75 ),75 ),
76 ],76 ],
77 } from virtual:<test>:26-34,77 } from virtual:<test>:26-34,
modifiedcrates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__index_and_suffix.snapdiffbeforeafterboth
23 2.0,23 2.0,
24 ),24 ),
25 ],25 ],
26 named: [],26 names: [],
27 values: [],
27 } from virtual:<test>:8-11,28 } from virtual:<test>:8-11,
28 false,29 false,
29 ),30 ),
modifiedcrates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@array_comp.jsonnet.snapdiffbeforeafterboth
26 "x" from virtual:<test>:16-17,26 "x" from virtual:<test>:16-17,
27 ),27 ),
28 ],28 ],
29 named: [],29 names: [],
30 values: [],
30 } from virtual:<test>:15-18,31 } from virtual:<test>:15-18,
31 false,32 false,
32 ),33 ),
modifiedcrates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@reserved.jsonnet.snapdiffbeforeafterboth
24 "null_fields" from virtual:<test>:20-31,24 "null_fields" from virtual:<test>:20-31,
25 ),25 ),
26 ],26 ],
27 named: [],27 names: [],
28 values: [],
28 } from virtual:<test>:16-32,29 } from virtual:<test>:16-32,
29 false,30 false,
30 ),31 ),
modifiedcrates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@suffix.jsonnet.snapdiffbeforeafterboth
28 2.0,28 2.0,
29 ),29 ),
30 ],30 ],
31 named: [],31 names: [],
32 values: [],
32 } from virtual:<test>:15-18,33 } from virtual:<test>:15-18,
33 false,34 false,
34 ),35 ),
52 2.0,53 2.0,
53 ),54 ),
54 ],55 ],
55 named: [],56 names: [],
57 values: [],
56 } from virtual:<test>:28-31,58 } from virtual:<test>:28-31,
57 false,59 false,
58 ),60 ),
modifiedcrates/jrsonnet-ir/src/expr.rsdiffbeforeafterboth
195#[derive(Debug, PartialEq, Acyclic)]195#[derive(Debug, PartialEq, Acyclic)]
196pub struct ArgsDesc {196pub struct ArgsDesc {
197 pub unnamed: Vec<Rc<Expr>>,197 pub unnamed: Vec<Rc<Expr>>,
198 pub names: Vec<IStr>,
198 pub named: Vec<(IStr, Rc<Expr>)>,199 pub values: Vec<Rc<Expr>>,
199}200}
200impl ArgsDesc {201impl ArgsDesc {
201 pub fn new(unnamed: Vec<Rc<Expr>>, named: Vec<(IStr, Rc<Expr>)>) -> Self {202 pub fn new(unnamed: Vec<Rc<Expr>>, names: Vec<IStr>, values: Vec<Rc<Expr>>) -> Self {
202 Self { unnamed, named }203 Self {
204 unnamed,
205 names,
206 values,
207 }
203 }208 }
204}209}
modifiedcrates/jrsonnet-ir/src/visit.rsdiffbeforeafterboth
216 }216 }
217 Expr::Apply(expr, spanned, _) => {217 Expr::Apply(expr, spanned, _) => {
218 v.visit_expr(expr);218 v.visit_expr(expr);
219 let ArgsDesc { unnamed, named } = &**spanned;219 let ArgsDesc {
220 unnamed,
221 names: _,
222 values,
223 } = &**spanned;
220 for unnamed in unnamed {224 for unnamed in unnamed {
221 v.visit_expr(unnamed);225 v.visit_expr(unnamed);
222 }226 }
223 for (_name, named) in named {227 for named in values {
224 v.visit_expr(named);228 v.visit_expr(named);
225 }229 }
226 }230 }
modifiedcrates/jrsonnet-peg-parser/src/lib.rsdiffbeforeafterboth
73 = args:arg(s)**comma() comma()? {?73 = args:arg(s)**comma() comma()? {?
74 let unnamed_count = args.iter().take_while(|(n, _)| n.is_none()).count();74 let unnamed_count = args.iter().take_while(|(n, _)| n.is_none()).count();
75 let mut unnamed = Vec::with_capacity(unnamed_count);75 let mut unnamed = Vec::with_capacity(unnamed_count);
76 let mut named = Vec::with_capacity(args.len() - unnamed_count);76 let mut names = Vec::with_capacity(args.len() - unnamed_count);
77 let mut values = Vec::with_capacity(args.len() - unnamed_count);
77 let mut named_started = false;78 let mut named_started = false;
78 for (name, value) in args {79 for (name, value) in args {
79 if let Some(name) = name {80 if let Some(name) = name {
80 named_started = true;81 named_started = true;
81 named.push((name, value));82 names.push(name);
83 values.push(value);
82 } else {84 } else {
83 if named_started {85 if named_started {
84 return Err("<named argument>")86 return Err("<named argument>")
85 }87 }
86 unnamed.push(value);88 unnamed.push(value);
87 }89 }
88 }90 }
89 Ok(ArgsDesc::new(unnamed, named))91 Ok(ArgsDesc{unnamed, names, values})
90 }92 }
9193
92 pub rule destruct_rest() -> DestructRest94 pub rule destruct_rest() -> DestructRest
modifiedcrates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@array_comp.jsonnet.snapdiffbeforeafterboth
26 "x" from virtual:<test>:16-17,26 "x" from virtual:<test>:16-17,
27 ),27 ),
28 ],28 ],
29 named: [],29 names: [],
30 values: [],
30 } from virtual:<test>:15-18,31 } from virtual:<test>:15-18,
31 false,32 false,
32 ),33 ),
modifiedcrates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@reserved.jsonnet.snapdiffbeforeafterboth
24 "null_fields" from virtual:<test>:20-31,24 "null_fields" from virtual:<test>:20-31,
25 ),25 ),
26 ],26 ],
27 named: [],27 names: [],
28 values: [],
28 } from virtual:<test>:16-32,29 } from virtual:<test>:16-32,
29 false,30 false,
30 ),31 ),
modifiedcrates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@suffix.jsonnet.snapdiffbeforeafterboth
28 2.0,28 2.0,
29 ),29 ),
30 ],30 ],
31 named: [],31 names: [],
32 values: [],
32 } from virtual:<test>:15-18,33 } from virtual:<test>:15-18,
33 false,34 false,
34 ),35 ),
52 2.0,53 2.0,
53 ),54 ),
54 ],55 ],
55 named: [],56 names: [],
57 values: [],
56 } from virtual:<test>:28-31,58 } from virtual:<test>:28-31,
57 false,59 false,
58 ),60 ),
modifiedcrates/jrsonnet-stdlib/src/keyf.rsdiffbeforeafterboth
1use jrsonnet_evaluator::{1use jrsonnet_evaluator::{
2 Error, Result, Thunk, Val,2 Error, Result, Thunk, Val,
3 function::{CallLocation, FuncVal, PreparedFuncVal},3 function::{FuncVal, NativeFn},
4 typed::{ComplexValType, FromUntyped, Typed, ValType},4 typed::{ComplexValType, FromUntyped, Typed, ValType},
5};5};
6
7type PreparedKeyF = NativeFn!((Thunk<Val>) -> Val);
68
7#[derive(Default, Clone)]9#[derive(Default, Clone)]
8pub enum KeyF {10pub enum KeyF {
9 #[default]11 #[default]
10 Identity,12 Identity,
11 Prepared(PreparedFuncVal),13 Prepared(PreparedKeyF),
12 PrepareFailure(Error),14 PrepareFailure(Error),
13}15}
14impl KeyF {16impl KeyF {
19 if val.is_identity() {21 if val.is_identity() {
20 Self::Identity22 Self::Identity
21 } else {23 } else {
22 PreparedFuncVal::new(val, 1, &[]).map_or_else(Self::PrepareFailure, Self::Prepared)24 PreparedKeyF::try_from(val).map_or_else(Self::PrepareFailure, Self::Prepared)
23 }25 }
24 }26 }
25 pub fn eval(&self, val: impl Into<Thunk<Val>>) -> Result<Val> {27 pub fn eval(&self, val: impl Into<Thunk<Val>>) -> Result<Val> {
26 match self {28 match self {
27 KeyF::Identity => val.into().evaluate(),29 KeyF::Identity => val.into().evaluate(),
28 KeyF::Prepared(p) => p.call(CallLocation::native(), &[val.into()], &[]),30 KeyF::Prepared(p) => p.call(val.into()),
29 KeyF::PrepareFailure(e) => Err(e.clone()),31 KeyF::PrepareFailure(e) => Err(e.clone()),
30 }32 }
31 }33 }