git.delta.rocks / jrsonnet / refs/commits / cbdee48b2528

difftreelog

refactor drop OptionalContext marker

wvzyqxsnYaroslav Bolyukin2026-03-21parent: #c0a2148.patch.diff
in: master

1 file changed

modifiedcrates/jrsonnet-evaluator/src/function/arglike.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/function/arglike.rs
1use std::collections::HashMap;2use std::rc::Rc;34use jrsonnet_gcmodule::Trace;5use jrsonnet_interner::IStr;6use jrsonnet_parser::{ArgsDesc, Expr, SourceFifo, SourcePath, Spanned};78use crate::{evaluate, typed::Typed, with_state, Context, Result, Thunk, Val};910/// Marker for arguments, which can be evaluated with context set to None11pub trait OptionalContext {}1213pub trait ArgLike {14	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;15}1617impl ArgLike for &Rc<Spanned<Expr>> {18	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {19		Ok(if tailstrict {20			Thunk::evaluated(evaluate(ctx, self)?)21		} else {22			let expr = (*self).clone();23			Thunk!(move || evaluate(ctx, &expr))24		})25	}26}2728impl<T> ArgLike for T29where30	T: Typed + Clone,31{32	fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {33		if T::provides_lazy() && !tailstrict {34			return Ok(T::into_lazy_untyped(self.clone()));35		}36		let val = T::into_untyped(self.clone())?;37		Ok(Thunk::evaluated(val))38	}39}40impl<T> OptionalContext for T where T: Typed + Clone {}4142#[derive(Clone, Trace)]43pub enum TlaArg {44	String(IStr),45	Val(Val),46	Lazy(Thunk<Val>),47	Import(String),48	ImportStr(String),49	InlineCode(String),50}51impl TlaArg {52	pub fn evaluate_tailstrict(&self) -> Result<Val> {53		match self {54			Self::String(s) => Ok(Val::string(s.clone())),55			Self::Val(val) => Ok(val.clone()),56			Self::Lazy(lazy) => Ok(lazy.evaluate()?),57			Self::Import(p) => with_state(|s| {58				let resolved = s.resolve_from_default(&p.as_str())?;59				s.import_resolved(resolved)60			}),61			Self::ImportStr(p) => with_state(|s| {62				let resolved = s.resolve_from_default(&p.as_str())?;63				s.import_resolved_str(resolved).map(Val::string)64			}),65			Self::InlineCode(p) => with_state(|s| {66				let resolved =67					SourcePath::new(SourceFifo("<inline code>".to_owned(), p.as_bytes().into()));68				s.import_resolved(resolved)69			}),70		}71	}72	pub fn evaluate(&self) -> Result<Thunk<Val>> {73		match self {74			Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),75			Self::Val(val) => Ok(Thunk::evaluated(val.clone())),76			Self::Lazy(lazy) => Ok(lazy.clone()),77			Self::Import(p) => with_state(|s| {78				let resolved = s.resolve_from_default(&p.as_str())?;79				Ok(Thunk!(move || s.import_resolved(resolved)))80			}),81			Self::ImportStr(p) => with_state(|s| {82				let resolved = s.resolve_from_default(&p.as_str())?;83				Ok(Thunk!(move || s84					.import_resolved_str(resolved)85					.map(Val::string)))86			}),87			Self::InlineCode(p) => with_state(|s| {88				let resolved =89					SourcePath::new(SourceFifo("<inline code>".to_owned(), p.as_bytes().into()));90				Ok(Thunk!(move || s.import_resolved(resolved)))91			}),92		}93	}94}9596// TODO: Is this implementation really required, as there is no Context to use?97// Maybe something a bit stricter is possible to add, especially with precompiled calls?98impl ArgLike for TlaArg {99	fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {100		if tailstrict {101			self.evaluate_tailstrict().map(Thunk::evaluated)102		} else {103			self.evaluate()104		}105	}106}107108pub trait ArgsLike {109	fn unnamed_len(&self) -> usize;110	fn unnamed_iter(111		&self,112		ctx: Context,113		tailstrict: bool,114		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,115	) -> Result<()>;116	fn named_iter(117		&self,118		ctx: Context,119		tailstrict: bool,120		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,121	) -> Result<()>;122	fn named_names(&self, handler: &mut dyn FnMut(&IStr));123	fn is_empty(&self) -> bool;124}125126impl ArgsLike for Vec<Val> {127	fn unnamed_len(&self) -> usize {128		self.len()129	}130	fn unnamed_iter(131		&self,132		_ctx: Context,133		_tailstrict: bool,134		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,135	) -> Result<()> {136		for (idx, el) in self.iter().enumerate() {137			handler(idx, Thunk::evaluated(el.clone()))?;138		}139		Ok(())140	}141	fn named_iter(142		&self,143		_ctx: Context,144		_tailstrict: bool,145		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,146	) -> Result<()> {147		Ok(())148	}149	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}150	fn is_empty(&self) -> bool {151		self.is_empty()152	}153}154155impl ArgsLike for ArgsDesc {156	fn unnamed_len(&self) -> usize {157		self.unnamed.len()158	}159160	fn unnamed_iter(161		&self,162		ctx: Context,163		tailstrict: bool,164		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,165	) -> Result<()> {166		for (id, arg) in self.unnamed.iter().enumerate() {167			handler(168				id,169				if tailstrict {170					Thunk::evaluated(evaluate(ctx.clone(), arg)?)171				} else {172					let ctx = ctx.clone();173					let arg = arg.clone();174175					Thunk!(move || evaluate(ctx, &arg))176				},177			)?;178		}179		Ok(())180	}181182	fn named_iter(183		&self,184		ctx: Context,185		tailstrict: bool,186		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,187	) -> Result<()> {188		for (name, arg) in &self.named {189			handler(190				name,191				if tailstrict {192					Thunk::evaluated(evaluate(ctx.clone(), arg)?)193				} else {194					let ctx = ctx.clone();195					let arg = arg.clone();196197					Thunk!(move || evaluate(ctx, &arg))198				},199			)?;200		}201		Ok(())202	}203204	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {205		for (name, _) in &self.named {206			handler(name);207		}208	}209210	fn is_empty(&self) -> bool {211		self.unnamed.is_empty() && self.named.is_empty()212	}213}214215impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {216	fn unnamed_len(&self) -> usize {217		0218	}219220	fn unnamed_iter(221		&self,222		_ctx: Context,223		_tailstrict: bool,224		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,225	) -> Result<()> {226		Ok(())227	}228229	fn named_iter(230		&self,231		ctx: Context,232		tailstrict: bool,233		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,234	) -> Result<()> {235		for (name, value) in self {236			handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;237		}238		Ok(())239	}240241	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {242		for name in self.keys() {243			handler(name);244		}245	}246247	fn is_empty(&self) -> bool {248		self.is_empty()249	}250}251impl<V, S> OptionalContext for HashMap<IStr, V, S> where V: ArgLike + OptionalContext {}252253macro_rules! impl_args_like {254	($count:expr; $($gen:ident)*) => {255		impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {256			fn unnamed_len(&self) -> usize {257				$count258			}259			#[allow(non_snake_case, unused_assignments)]260			fn unnamed_iter(261				&self,262				ctx: Context,263				tailstrict: bool,264				handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,265			) -> Result<()> {266				let mut i = 0usize;267				let ($($gen,)*) = self;268				$(269					handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;270					i+=1;271				)*272				Ok(())273			}274			fn named_iter(275				&self,276				_ctx: Context,277				_tailstrict: bool,278				_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,279			) -> Result<()> {280				Ok(())281			}282			fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}283284			fn is_empty(&self) -> bool {285				// impl_args_like only implements non-empty tuples.286				false287			}288		}289		impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}290	};291	($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {292		impl_args_like!($count; $($cur)*);293		impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);294	};295	($count:expr; $($cur:ident)* @) => {296		impl_args_like!($count; $($cur)*);297	}298}299impl_args_like! {300	// First argument is already in position, so count starts from 1301	1usize; A @ B C D E F G H I J K L302}303304impl ArgsLike for () {305	fn unnamed_len(&self) -> usize {306		0307	}308309	fn unnamed_iter(310		&self,311		_ctx: Context,312		_tailstrict: bool,313		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,314	) -> Result<()> {315		Ok(())316	}317318	fn named_iter(319		&self,320		_ctx: Context,321		_tailstrict: bool,322		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,323	) -> Result<()> {324		Ok(())325	}326327	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}328	fn is_empty(&self) -> bool {329		true330	}331}332impl OptionalContext for () {}
after · crates/jrsonnet-evaluator/src/function/arglike.rs
1use std::collections::HashMap;2use std::rc::Rc;34use jrsonnet_gcmodule::Trace;5use jrsonnet_interner::IStr;6use jrsonnet_parser::{ArgsDesc, Expr, SourceFifo, SourcePath, Spanned};78use crate::{evaluate, typed::Typed, with_state, Context, Result, Thunk, Val};910pub trait ArgLike {11	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;12}1314impl ArgLike for &Rc<Spanned<Expr>> {15	fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {16		Ok(if tailstrict {17			Thunk::evaluated(evaluate(ctx, self)?)18		} else {19			let expr = (*self).clone();20			Thunk!(move || evaluate(ctx, &expr))21		})22	}23}2425impl<T> ArgLike for T26where27	T: Typed + Clone,28{29	fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {30		if T::provides_lazy() && !tailstrict {31			return Ok(T::into_lazy_untyped(self.clone()));32		}33		let val = T::into_untyped(self.clone())?;34		Ok(Thunk::evaluated(val))35	}36}3738#[derive(Clone, Trace)]39pub enum TlaArg {40	String(IStr),41	Val(Val),42	Lazy(Thunk<Val>),43	Import(String),44	ImportStr(String),45	InlineCode(String),46}47impl TlaArg {48	pub fn evaluate_tailstrict(&self) -> Result<Val> {49		match self {50			Self::String(s) => Ok(Val::string(s.clone())),51			Self::Val(val) => Ok(val.clone()),52			Self::Lazy(lazy) => Ok(lazy.evaluate()?),53			Self::Import(p) => with_state(|s| {54				let resolved = s.resolve_from_default(&p.as_str())?;55				s.import_resolved(resolved)56			}),57			Self::ImportStr(p) => with_state(|s| {58				let resolved = s.resolve_from_default(&p.as_str())?;59				s.import_resolved_str(resolved).map(Val::string)60			}),61			Self::InlineCode(p) => with_state(|s| {62				let resolved =63					SourcePath::new(SourceFifo("<inline code>".to_owned(), p.as_bytes().into()));64				s.import_resolved(resolved)65			}),66		}67	}68	pub fn evaluate(&self) -> Result<Thunk<Val>> {69		match self {70			Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),71			Self::Val(val) => Ok(Thunk::evaluated(val.clone())),72			Self::Lazy(lazy) => Ok(lazy.clone()),73			Self::Import(p) => with_state(|s| {74				let resolved = s.resolve_from_default(&p.as_str())?;75				Ok(Thunk!(move || s.import_resolved(resolved)))76			}),77			Self::ImportStr(p) => with_state(|s| {78				let resolved = s.resolve_from_default(&p.as_str())?;79				Ok(Thunk!(move || s80					.import_resolved_str(resolved)81					.map(Val::string)))82			}),83			Self::InlineCode(p) => with_state(|s| {84				let resolved =85					SourcePath::new(SourceFifo("<inline code>".to_owned(), p.as_bytes().into()));86				Ok(Thunk!(move || s.import_resolved(resolved)))87			}),88		}89	}90}9192// TODO: Is this implementation really required, as there is no Context to use?93// Maybe something a bit stricter is possible to add, especially with precompiled calls?94impl ArgLike for TlaArg {95	fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {96		if tailstrict {97			self.evaluate_tailstrict().map(Thunk::evaluated)98		} else {99			self.evaluate()100		}101	}102}103104pub trait ArgsLike {105	fn unnamed_len(&self) -> usize;106	fn unnamed_iter(107		&self,108		ctx: Context,109		tailstrict: bool,110		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,111	) -> Result<()>;112	fn named_iter(113		&self,114		ctx: Context,115		tailstrict: bool,116		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,117	) -> Result<()>;118	fn named_names(&self, handler: &mut dyn FnMut(&IStr));119	fn is_empty(&self) -> bool;120}121122impl ArgsLike for Vec<Val> {123	fn unnamed_len(&self) -> usize {124		self.len()125	}126	fn unnamed_iter(127		&self,128		_ctx: Context,129		_tailstrict: bool,130		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,131	) -> Result<()> {132		for (idx, el) in self.iter().enumerate() {133			handler(idx, Thunk::evaluated(el.clone()))?;134		}135		Ok(())136	}137	fn named_iter(138		&self,139		_ctx: Context,140		_tailstrict: bool,141		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,142	) -> Result<()> {143		Ok(())144	}145	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}146	fn is_empty(&self) -> bool {147		self.is_empty()148	}149}150151impl ArgsLike for ArgsDesc {152	fn unnamed_len(&self) -> usize {153		self.unnamed.len()154	}155156	fn unnamed_iter(157		&self,158		ctx: Context,159		tailstrict: bool,160		handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,161	) -> Result<()> {162		for (id, arg) in self.unnamed.iter().enumerate() {163			handler(164				id,165				if tailstrict {166					Thunk::evaluated(evaluate(ctx.clone(), arg)?)167				} else {168					let ctx = ctx.clone();169					let arg = arg.clone();170171					Thunk!(move || evaluate(ctx, &arg))172				},173			)?;174		}175		Ok(())176	}177178	fn named_iter(179		&self,180		ctx: Context,181		tailstrict: bool,182		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,183	) -> Result<()> {184		for (name, arg) in &self.named {185			handler(186				name,187				if tailstrict {188					Thunk::evaluated(evaluate(ctx.clone(), arg)?)189				} else {190					let ctx = ctx.clone();191					let arg = arg.clone();192193					Thunk!(move || evaluate(ctx, &arg))194				},195			)?;196		}197		Ok(())198	}199200	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {201		for (name, _) in &self.named {202			handler(name);203		}204	}205206	fn is_empty(&self) -> bool {207		self.unnamed.is_empty() && self.named.is_empty()208	}209}210211impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {212	fn unnamed_len(&self) -> usize {213		0214	}215216	fn unnamed_iter(217		&self,218		_ctx: Context,219		_tailstrict: bool,220		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,221	) -> Result<()> {222		Ok(())223	}224225	fn named_iter(226		&self,227		ctx: Context,228		tailstrict: bool,229		handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,230	) -> Result<()> {231		for (name, value) in self {232			handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;233		}234		Ok(())235	}236237	fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {238		for name in self.keys() {239			handler(name);240		}241	}242243	fn is_empty(&self) -> bool {244		self.is_empty()245	}246}247248macro_rules! impl_args_like {249	($count:expr; $($gen:ident)*) => {250		impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {251			fn unnamed_len(&self) -> usize {252				$count253			}254			#[allow(non_snake_case, unused_assignments)]255			fn unnamed_iter(256				&self,257				ctx: Context,258				tailstrict: bool,259				handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,260			) -> Result<()> {261				let mut i = 0usize;262				let ($($gen,)*) = self;263				$(264					handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;265					i+=1;266				)*267				Ok(())268			}269			fn named_iter(270				&self,271				_ctx: Context,272				_tailstrict: bool,273				_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,274			) -> Result<()> {275				Ok(())276			}277			fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}278279			fn is_empty(&self) -> bool {280				// impl_args_like only implements non-empty tuples.281				false282			}283		}284	};285	($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {286		impl_args_like!($count; $($cur)*);287		impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);288	};289	($count:expr; $($cur:ident)* @) => {290		impl_args_like!($count; $($cur)*);291	}292}293impl_args_like! {294	// First argument is already in position, so count starts from 1295	1usize; A @ B C D E F G H I J K L296}297298impl ArgsLike for () {299	fn unnamed_len(&self) -> usize {300		0301	}302303	fn unnamed_iter(304		&self,305		_ctx: Context,306		_tailstrict: bool,307		_handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,308	) -> Result<()> {309		Ok(())310	}311312	fn named_iter(313		&self,314		_ctx: Context,315		_tailstrict: bool,316		_handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,317	) -> Result<()> {318		Ok(())319	}320321	fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}322	fn is_empty(&self) -> bool {323		true324	}325}