git.delta.rocks / jrsonnet / refs/commits / 562e7b71e322

difftreelog

refactor remove manual ThunkValue implementations

Yaroslav Bolyukin2024-08-30parent: #7cd3ab4.patch.diff
in: master

3 files changed

modifiedcrates/jrsonnet-evaluator/src/function/arglike.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/function/arglike.rs
1use 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 () {}
after · crates/jrsonnet-evaluator/src/function/arglike.rs
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 () {}
modifiedcrates/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(
 				&param.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) = &param.1 {
 			destruct(
 				&param.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,
 			)?;
modifiednix/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