difftreelog
refactor remove manual ThunkValue implementations
in: master
3 files changed
crates/jrsonnet-evaluator/src/function/arglike.rsdiffbeforeafterboth1use hashbrown::HashMap;2use jrsonnet_gcmodule::Trace;3use jrsonnet_interner::IStr;4use jrsonnet_parser::{ArgsDesc, LocExpr};56use crate::{evaluate, gc::GcHashMap, typed::Typed, val::ThunkValue, Context, Result, Thunk, Val};78/// Marker for arguments, which can be evaluated with context set to None9pub trait OptionalContext {}1011#[derive(Trace)]12struct EvaluateThunk {13 ctx: Context,14 expr: LocExpr,15}16impl ThunkValue for EvaluateThunk {17 type Output = Val;18 fn get(self: Box<Self>) -> Result<Val> {19 evaluate(self.ctx, &self.expr)20 }21}2223pub trait ArgLike {24 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;25}2627impl ArgLike for &LocExpr {28 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {29 Ok(if tailstrict {30 Thunk::evaluated(evaluate(ctx, self)?)31 } else {32 Thunk::new(EvaluateThunk {33 ctx,34 expr: (*self).clone(),35 })36 })37 }38}3940impl<T> ArgLike for T41where42 T: Typed + Clone,43{44 fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {45 if T::provides_lazy() && !tailstrict {46 return Ok(T::into_lazy_untyped(self.clone()));47 }48 let val = T::into_untyped(self.clone())?;49 Ok(Thunk::evaluated(val))50 }51}52impl<T> OptionalContext for T where T: Typed + Clone {}5354#[derive(Clone, Trace)]55pub enum TlaArg {56 String(IStr),57 Code(LocExpr),58 Val(Val),59 Lazy(Thunk<Val>),60}61impl ArgLike for TlaArg {62 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {63 match self {64 Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),65 Self::Code(code) => Ok(if tailstrict {66 Thunk::evaluated(evaluate(ctx, code)?)67 } else {68 Thunk::new(EvaluateThunk {69 ctx,70 expr: code.clone(),71 })72 }),73 Self::Val(val) => Ok(Thunk::evaluated(val.clone())),74 Self::Lazy(lazy) => Ok(lazy.clone()),75 }76 }77}7879pub trait ArgsLike {80 fn unnamed_len(&self) -> usize;81 fn unnamed_iter(82 &self,83 ctx: Context,84 tailstrict: bool,85 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,86 ) -> Result<()>;87 fn named_iter(88 &self,89 ctx: Context,90 tailstrict: bool,91 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,92 ) -> Result<()>;93 fn named_names(&self, handler: &mut dyn FnMut(&IStr));94 fn is_empty(&self) -> bool;95}9697impl ArgsLike for Vec<Val> {98 fn unnamed_len(&self) -> usize {99 self.len()100 }101 fn unnamed_iter(102 &self,103 _ctx: Context,104 _tailstrict: bool,105 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,106 ) -> Result<()> {107 for (idx, el) in self.iter().enumerate() {108 handler(idx, Thunk::evaluated(el.clone()))?;109 }110 Ok(())111 }112 fn named_iter(113 &self,114 _ctx: Context,115 _tailstrict: bool,116 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,117 ) -> Result<()> {118 Ok(())119 }120 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}121 fn is_empty(&self) -> bool {122 self.is_empty()123 }124}125126impl ArgsLike for ArgsDesc {127 fn unnamed_len(&self) -> usize {128 self.unnamed.len()129 }130131 fn unnamed_iter(132 &self,133 ctx: Context,134 tailstrict: bool,135 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,136 ) -> Result<()> {137 for (id, arg) in self.unnamed.iter().enumerate() {138 handler(139 id,140 if tailstrict {141 Thunk::evaluated(evaluate(ctx.clone(), arg)?)142 } else {143 Thunk::new(EvaluateThunk {144 ctx: ctx.clone(),145 expr: arg.clone(),146 })147 },148 )?;149 }150 Ok(())151 }152153 fn named_iter(154 &self,155 ctx: Context,156 tailstrict: bool,157 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,158 ) -> Result<()> {159 for (name, arg) in &self.named {160 handler(161 name,162 if tailstrict {163 Thunk::evaluated(evaluate(ctx.clone(), arg)?)164 } else {165 Thunk::new(EvaluateThunk {166 ctx: ctx.clone(),167 expr: arg.clone(),168 })169 },170 )?;171 }172 Ok(())173 }174175 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {176 for (name, _) in &self.named {177 handler(name);178 }179 }180181 fn is_empty(&self) -> bool {182 self.unnamed.is_empty() && self.named.is_empty()183 }184}185186impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {187 fn unnamed_len(&self) -> usize {188 0189 }190191 fn unnamed_iter(192 &self,193 _ctx: Context,194 _tailstrict: bool,195 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,196 ) -> Result<()> {197 Ok(())198 }199200 fn named_iter(201 &self,202 ctx: Context,203 tailstrict: bool,204 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,205 ) -> Result<()> {206 for (name, value) in self {207 handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;208 }209 Ok(())210 }211212 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {213 for (name, _) in self {214 handler(name);215 }216 }217218 fn is_empty(&self) -> bool {219 self.is_empty()220 }221}222impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}223224impl<A: ArgLike> ArgsLike for GcHashMap<IStr, A> {225 fn unnamed_len(&self) -> usize {226 self.0.unnamed_len()227 }228229 fn unnamed_iter(230 &self,231 ctx: Context,232 tailstrict: bool,233 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,234 ) -> Result<()> {235 self.0.unnamed_iter(ctx, tailstrict, handler)236 }237238 fn named_iter(239 &self,240 ctx: Context,241 tailstrict: bool,242 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,243 ) -> Result<()> {244 self.0.named_iter(ctx, tailstrict, handler)245 }246247 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {248 self.0.named_names(handler);249 }250251 fn is_empty(&self) -> bool {252 self.0.is_empty()253 }254}255256macro_rules! impl_args_like {257 ($count:expr; $($gen:ident)*) => {258 impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {259 fn unnamed_len(&self) -> usize {260 $count261 }262 #[allow(non_snake_case, unused_assignments)]263 fn unnamed_iter(264 &self,265 ctx: Context,266 tailstrict: bool,267 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,268 ) -> Result<()> {269 let mut i = 0usize;270 let ($($gen,)*) = self;271 $(272 handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;273 i+=1;274 )*275 Ok(())276 }277 fn named_iter(278 &self,279 _ctx: Context,280 _tailstrict: bool,281 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,282 ) -> Result<()> {283 Ok(())284 }285 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}286287 fn is_empty(&self) -> bool {288 // impl_args_like only implements non-empty tuples.289 false290 }291 }292 impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}293 };294 ($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {295 impl_args_like!($count; $($cur)*);296 impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);297 };298 ($count:expr; $($cur:ident)* @) => {299 impl_args_like!($count; $($cur)*);300 }301}302impl_args_like! {303 // First argument is already in position, so count starts from 1304 1usize; A @ B C D E F G H I J K L305}306307impl ArgsLike for () {308 fn unnamed_len(&self) -> usize {309 0310 }311312 fn unnamed_iter(313 &self,314 _ctx: Context,315 _tailstrict: bool,316 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,317 ) -> Result<()> {318 Ok(())319 }320321 fn named_iter(322 &self,323 _ctx: Context,324 _tailstrict: bool,325 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,326 ) -> Result<()> {327 Ok(())328 }329330 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}331 fn is_empty(&self) -> bool {332 true333 }334}335impl OptionalContext for () {}1use hashbrown::HashMap;2use jrsonnet_gcmodule::Trace;3use jrsonnet_interner::IStr;4use jrsonnet_parser::{ArgsDesc, LocExpr};56use crate::{evaluate, gc::GcHashMap, typed::Typed, Context, Result, Thunk, Val};78/// Marker for arguments, which can be evaluated with context set to None9pub trait OptionalContext {}1011pub trait ArgLike {12 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;13}1415impl ArgLike for &LocExpr {16 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {17 Ok(if tailstrict {18 Thunk::evaluated(evaluate(ctx, self)?)19 } else {20 let expr = (*self).clone();21 Thunk!(move || evaluate(ctx, &expr))22 })23 }24}2526impl<T> ArgLike for T27where28 T: Typed + Clone,29{30 fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {31 if T::provides_lazy() && !tailstrict {32 return Ok(T::into_lazy_untyped(self.clone()));33 }34 let val = T::into_untyped(self.clone())?;35 Ok(Thunk::evaluated(val))36 }37}38impl<T> OptionalContext for T where T: Typed + Clone {}3940#[derive(Clone, Trace)]41pub enum TlaArg {42 String(IStr),43 Code(LocExpr),44 Val(Val),45 Lazy(Thunk<Val>),46}47impl ArgLike for TlaArg {48 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {49 match self {50 Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),51 Self::Code(code) => Ok(if tailstrict {52 Thunk::evaluated(evaluate(ctx, code)?)53 } else {54 let code = code.clone();55 Thunk!(move || evaluate(ctx, &code))56 }),57 Self::Val(val) => Ok(Thunk::evaluated(val.clone())),58 Self::Lazy(lazy) => Ok(lazy.clone()),59 }60 }61}6263pub trait ArgsLike {64 fn unnamed_len(&self) -> usize;65 fn unnamed_iter(66 &self,67 ctx: Context,68 tailstrict: bool,69 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,70 ) -> Result<()>;71 fn named_iter(72 &self,73 ctx: Context,74 tailstrict: bool,75 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,76 ) -> Result<()>;77 fn named_names(&self, handler: &mut dyn FnMut(&IStr));78 fn is_empty(&self) -> bool;79}8081impl ArgsLike for Vec<Val> {82 fn unnamed_len(&self) -> usize {83 self.len()84 }85 fn unnamed_iter(86 &self,87 _ctx: Context,88 _tailstrict: bool,89 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,90 ) -> Result<()> {91 for (idx, el) in self.iter().enumerate() {92 handler(idx, Thunk::evaluated(el.clone()))?;93 }94 Ok(())95 }96 fn named_iter(97 &self,98 _ctx: Context,99 _tailstrict: bool,100 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,101 ) -> Result<()> {102 Ok(())103 }104 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}105 fn is_empty(&self) -> bool {106 self.is_empty()107 }108}109110impl ArgsLike for ArgsDesc {111 fn unnamed_len(&self) -> usize {112 self.unnamed.len()113 }114115 fn unnamed_iter(116 &self,117 ctx: Context,118 tailstrict: bool,119 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,120 ) -> Result<()> {121 for (id, arg) in self.unnamed.iter().enumerate() {122 handler(123 id,124 if tailstrict {125 Thunk::evaluated(evaluate(ctx.clone(), arg)?)126 } else {127 let ctx = ctx.clone();128 let arg = arg.clone();129130 Thunk!(move || evaluate(ctx, &arg))131 },132 )?;133 }134 Ok(())135 }136137 fn named_iter(138 &self,139 ctx: Context,140 tailstrict: bool,141 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,142 ) -> Result<()> {143 for (name, arg) in &self.named {144 handler(145 name,146 if tailstrict {147 Thunk::evaluated(evaluate(ctx.clone(), arg)?)148 } else {149 let ctx = ctx.clone();150 let arg = arg.clone();151152 Thunk!(move || evaluate(ctx, &arg))153 },154 )?;155 }156 Ok(())157 }158159 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {160 for (name, _) in &self.named {161 handler(name);162 }163 }164165 fn is_empty(&self) -> bool {166 self.unnamed.is_empty() && self.named.is_empty()167 }168}169170impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {171 fn unnamed_len(&self) -> usize {172 0173 }174175 fn unnamed_iter(176 &self,177 _ctx: Context,178 _tailstrict: bool,179 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,180 ) -> Result<()> {181 Ok(())182 }183184 fn named_iter(185 &self,186 ctx: Context,187 tailstrict: bool,188 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,189 ) -> Result<()> {190 for (name, value) in self {191 handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;192 }193 Ok(())194 }195196 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {197 for (name, _) in self {198 handler(name);199 }200 }201202 fn is_empty(&self) -> bool {203 self.is_empty()204 }205}206impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}207208impl<A: ArgLike> ArgsLike for GcHashMap<IStr, A> {209 fn unnamed_len(&self) -> usize {210 self.0.unnamed_len()211 }212213 fn unnamed_iter(214 &self,215 ctx: Context,216 tailstrict: bool,217 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,218 ) -> Result<()> {219 self.0.unnamed_iter(ctx, tailstrict, handler)220 }221222 fn named_iter(223 &self,224 ctx: Context,225 tailstrict: bool,226 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,227 ) -> Result<()> {228 self.0.named_iter(ctx, tailstrict, handler)229 }230231 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {232 self.0.named_names(handler);233 }234235 fn is_empty(&self) -> bool {236 self.0.is_empty()237 }238}239240macro_rules! impl_args_like {241 ($count:expr; $($gen:ident)*) => {242 impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {243 fn unnamed_len(&self) -> usize {244 $count245 }246 #[allow(non_snake_case, unused_assignments)]247 fn unnamed_iter(248 &self,249 ctx: Context,250 tailstrict: bool,251 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,252 ) -> Result<()> {253 let mut i = 0usize;254 let ($($gen,)*) = self;255 $(256 handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;257 i+=1;258 )*259 Ok(())260 }261 fn named_iter(262 &self,263 _ctx: Context,264 _tailstrict: bool,265 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,266 ) -> Result<()> {267 Ok(())268 }269 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}270271 fn is_empty(&self) -> bool {272 // impl_args_like only implements non-empty tuples.273 false274 }275 }276 impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}277 };278 ($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {279 impl_args_like!($count; $($cur)*);280 impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);281 };282 ($count:expr; $($cur:ident)* @) => {283 impl_args_like!($count; $($cur)*);284 }285}286impl_args_like! {287 // First argument is already in position, so count starts from 1288 1usize; A @ B C D E F G H I J K L289}290291impl ArgsLike for () {292 fn unnamed_len(&self) -> usize {293 0294 }295296 fn unnamed_iter(297 &self,298 _ctx: Context,299 _tailstrict: bool,300 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,301 ) -> Result<()> {302 Ok(())303 }304305 fn named_iter(306 &self,307 _ctx: Context,308 _tailstrict: bool,309 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,310 ) -> Result<()> {311 Ok(())312 }313314 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}315 fn is_empty(&self) -> bool {316 true317 }318}319impl OptionalContext for () {}crates/jrsonnet-evaluator/src/function/parse.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/function/parse.rs
+++ b/crates/jrsonnet-evaluator/src/function/parse.rs
@@ -12,24 +12,9 @@
evaluate_named,
function::builtin::ParamDefault,
gc::GcHashMap,
- val::ThunkValue,
Context, Pending, Thunk, Val,
};
-
-#[derive(Trace)]
-struct EvaluateNamedThunk {
- ctx: Pending<Context>,
- name: IStr,
- value: LocExpr,
-}
-impl ThunkValue for EvaluateNamedThunk {
- type Output = Val;
- fn get(self: Box<Self>) -> Result<Val> {
- evaluate_named(self.ctx.unwrap(), &self.value, self.name)
- }
-}
-
/// Creates correct [context](Context) for function body evaluation returning error on invalid call.
///
/// ## Parameters
@@ -105,11 +90,12 @@
destruct(
¶m.0,
- Thunk::new(EvaluateNamedThunk {
- ctx: fctx.clone(),
- name: param.0.name().unwrap_or_else(|| "<destruct>".into()),
- value: param.1.clone().expect("default exists"),
- }),
+ {
+ let ctx = fctx.clone();
+ let name = param.0.name().unwrap_or_else(|| "<destruct>".into());
+ let value = param.1.clone().expect("default exists");
+ Thunk!(move || evaluate_named(ctx.unwrap(), &value, name))
+ },
fctx.clone(),
&mut defaults,
)?;
@@ -241,11 +227,12 @@
if let Some(v) = ¶m.1 {
destruct(
¶m.0.clone(),
- Thunk::new(EvaluateNamedThunk {
- ctx: fctx.clone(),
- name: param.0.name().unwrap_or_else(|| "<destruct>".into()),
- value: v.clone(),
- }),
+ {
+ let ctx = fctx.clone();
+ let name = param.0.name().unwrap_or_else(|| "<destruct>".into());
+ let value = v.clone();
+ Thunk!(move || evaluate_named(ctx.unwrap(), &value, name))
+ },
fctx.clone(),
&mut bindings,
)?;
nix/benchmarks.nixdiffbeforeafterboth--- a/nix/benchmarks.nix
+++ b/nix/benchmarks.nix
@@ -52,6 +52,7 @@
mkdir -p $out
cp -r ${src}/* $out/
cd $out
+ chmod u+w jsonnetfile.lock.json
mkdir vendor
${jsonnet-bundler}/bin/jb install
'';
@@ -125,7 +126,7 @@
go-jsonnet $path > generated.jsonnet
path=generated.jsonnet
''}
- hyperfine -N -w4 -m20 --output=pipe --style=basic --export-markdown result.md \
+ hyperfine -N -w4 -m20 --output=pipe --style=basic --export-asciidoc result.adoc \
${concatStringsSep " " (forEach jrsonnetVariants (
variant: "\"${variant.drv}/bin/jrsonnet $path${optionalString (vendor != "") " -J${vendor}"}\" -n \"Rust${
if variant.name != ""
@@ -137,7 +138,7 @@
${optionalString (skipGo == "") "\"go-jsonnet $path${optionalString (vendor != "") " -J ${vendor}"}\" -n \"Go\""} \
${optionalString (skipScala == "") "\"sjsonnet $path${optionalString (vendor != "") " -J ${vendor}"}\" -n \"Scala\""} \
${optionalString (skipCpp == "") "\"jsonnet $path${optionalString (vendor != "") " -J ${vendor}"}\" -n \"C++\""}
- cat result.md >> $out
+ cat result.adoc >> $out
'';
in ''
set -oux