git.delta.rocks / jrsonnet / refs/commits / 60607d2bef37

difftreelog

refactor drop special casing of StaticBuiltin and Id functions

lryppxxoYaroslav Bolyukin2026-04-04parent: #a10f2cf.patch.diff
in: master

2 files changed

modifiedcrates/jrsonnet-evaluator/src/function/builtin.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/function/builtin.rs
1use std::any::Any;23use jrsonnet_gcmodule::{Trace, TraceBox, cc_dyn};4use jrsonnet_ir::function::{FunctionSignature, ParamDefault, ParamName, ParamParse};56use super::CallLocation;7use crate::{Result, Thunk, Val};89#[macro_export]10macro_rules! params {11	(@name unnamed) => { ParamName::Unnamed };12	(@name named $name:literal) => { ParamName::Named($crate::IStr::from($name)) };13	($($(#[$meta:meta])* [$kind:ident $(($lit:literal))? => $default:expr]),* $(,)?) => {14		thread_local! {15			static PARAMS: FunctionSignature = FunctionSignature::new([16				$($(#[$meta])* ParamParse::new(params!(@name $kind $($lit)?), $default)),*17			].into());18		}19	};20}2122cc_dyn!(23	#[derive(Clone)]24	BuiltinFunc,25	Builtin,26	pub(crate) fn new() {...}27);28impl Builtin for BuiltinFunc {29	fn name(&self) -> &str {30		self.0.name()31	}3233	fn params(&self) -> FunctionSignature {34		self.0.params()35	}3637	fn call(&self, loc: CallLocation<'_>, args: &[Option<Thunk<Val>>]) -> Result<Val> {38		self.0.call(loc, args)39	}4041	fn as_any(&self) -> &dyn Any {42		self.0.as_any()43	}44}4546/// Description of function defined by native code47///48/// Prefer to use #[builtin] macro, instead of manual implementation of this trait49pub trait Builtin: Trace {50	/// Function name to be used in stack traces51	fn name(&self) -> &str;52	/// Parameter names for named calls53	fn params(&self) -> FunctionSignature;54	/// Call the builtin55	fn call(&self, loc: CallLocation<'_>, args: &[Option<Thunk<Val>>]) -> Result<Val>;5657	fn as_any(&self) -> &dyn Any;58}5960pub trait StaticBuiltin: Builtin + Send + Sync61where62	Self: 'static,63{64	// In impl, to make it object safe:65	// const INST: &'static Self;66}6768#[derive(Trace)]69pub struct NativeCallback {70	pub(crate) params: FunctionSignature,71	handler: TraceBox<dyn NativeCallbackHandler>,72}73impl NativeCallback {74	#[deprecated = "prefer using builtins directly, use this interface only for bindings"]75	pub fn new(params: Vec<String>, handler: impl NativeCallbackHandler) -> Self {76		Self {77			params: FunctionSignature::new(78				params79					.into_iter()80					.map(|n| ParamParse::new(ParamName::Named(n.into()), ParamDefault::None))81					.collect(),82			),83			handler: TraceBox(Box::new(handler)),84		}85	}86}8788impl Builtin for NativeCallback {89	fn name(&self) -> &'static str {90		// TODO: standard natives gets their names from definition91		// But builitins should already have them92		"<native>"93	}9495	fn params(&self) -> FunctionSignature {96		self.params.clone()97	}9899	fn call(&self, _loc: CallLocation<'_>, args: &[Option<Thunk<Val>>]) -> Result<Val> {100		let args = args101			.iter()102			.map(|a| a.as_ref().expect("legacy natives have no default params"))103			.map(Thunk::evaluate)104			.collect::<Result<Vec<Val>>>()?;105		self.handler.call(&args)106	}107108	fn as_any(&self) -> &dyn Any {109		self110	}111}112113pub trait NativeCallbackHandler: Trace {114	fn call(&self, args: &[Val]) -> Result<Val>;115}
modifiedcrates/jrsonnet-evaluator/src/function/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/function/mod.rs
+++ b/crates/jrsonnet-evaluator/src/function/mod.rs
@@ -7,13 +7,13 @@
 pub use jrsonnet_macros::builtin;
 
 use self::{
-	builtin::{Builtin, StaticBuiltin},
+	builtin::Builtin,
 	parse::{parse_builtin_call, parse_default_function_call, parse_function_call},
-	prepared::{PreparedCall, parse_prepared_builtin_call, parse_prepared_function_call},
+	prepared::{parse_prepared_builtin_call, parse_prepared_function_call, PreparedCall},
 };
 use crate::{
-	Context, Result, Thunk, Val, bail, error::ErrorKind::*, evaluate, evaluate_trivial,
-	function::builtin::BuiltinFunc,
+	bail, error::ErrorKind::*, evaluate, evaluate_trivial, function::builtin::BuiltinFunc, Context,
+	Result, Thunk, Val,
 };
 
 pub mod builtin;
@@ -97,14 +97,10 @@
 #[allow(clippy::module_name_repetitions)]
 #[derive(Trace, Clone)]
 pub enum FuncVal {
-	/// Identity function, kept this way for comparsions.
-	Id,
 	/// Plain function implemented in jsonnet.
 	Normal(Cc<FuncDesc>),
 	/// Function without arguments works just as a fancy thunk value.
 	Thunk(Thunk<Val>),
-	/// Standard library function.
-	StaticBuiltin(#[trace(skip)] &'static dyn StaticBuiltin),
 	/// User-provided function.
 	Builtin(BuiltinFunc),
 }
@@ -112,12 +108,8 @@
 impl Debug for FuncVal {
 	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 		match self {
-			Self::Id => f.debug_tuple("Id").finish(),
 			Self::Thunk(arg0) => f.debug_tuple("Thunk").field(arg0).finish(),
 			Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),
-			Self::StaticBuiltin(arg0) => {
-				f.debug_tuple("StaticBuiltin").field(&arg0.name()).finish()
-			}
 			Self::Builtin(arg0) => f.debug_tuple("Builtin").field(&arg0.name()).finish(),
 		}
 	}
@@ -125,23 +117,17 @@
 
 #[allow(clippy::unnecessary_wraps)]
 #[builtin]
-const fn builtin_id(x: Val) -> Val {
+pub const fn builtin_id(x: Thunk<Val>) -> Thunk<Val> {
 	x
 }
-static ID: &builtin_id = &builtin_id {};
 
 impl FuncVal {
 	pub fn builtin(builtin: impl Builtin) -> Self {
 		Self::Builtin(BuiltinFunc::new(builtin))
-	}
-	pub fn static_builtin(static_builtin: &'static dyn StaticBuiltin) -> Self {
-		Self::StaticBuiltin(static_builtin)
 	}
 
 	pub fn params(&self) -> FunctionSignature {
 		match self {
-			Self::Id => ID.params(),
-			Self::StaticBuiltin(i) => i.params(),
 			Self::Builtin(i) => i.params(),
 			Self::Normal(p) => p.params.signature.clone(),
 			Self::Thunk(_) => FunctionSignature::empty(),
@@ -154,9 +140,7 @@
 	/// Function name, as defined in code.
 	pub fn name(&self) -> IStr {
 		match self {
-			Self::Id => "id".into(),
 			Self::Normal(normal) => normal.name.clone(),
-			Self::StaticBuiltin(builtin) => builtin.name().into(),
 			Self::Builtin(builtin) => builtin.name().into(),
 			Self::Thunk(_) => "thunk".into(),
 		}
@@ -182,14 +166,6 @@
 				}
 				thunk.evaluate()
 			}
-			Self::Id => {
-				let args = parse_builtin_call(call_ctx, ID.params(), args, tailstrict)?;
-				ID.call(loc, &args)
-			}
-			Self::StaticBuiltin(b) => {
-				let args = parse_builtin_call(call_ctx, b.params(), args, tailstrict)?;
-				b.call(loc, &args)
-			}
 			Self::Builtin(b) => {
 				let args = parse_builtin_call(call_ctx, b.params(), args, tailstrict)?;
 				b.call(loc, &args)
@@ -217,14 +193,6 @@
 				evaluate(body_ctx, &func.body)
 			}
 			FuncVal::Thunk(t) => t.evaluate(),
-			FuncVal::Id => {
-				let args = parse_prepared_builtin_call(prepared, ID.params(), unnamed, named);
-				ID.call(loc, &args)
-			}
-			FuncVal::StaticBuiltin(b) => {
-				let args = parse_prepared_builtin_call(prepared, b.params(), unnamed, named);
-				b.call(loc, &args)
-			}
 			FuncVal::Builtin(b) => {
 				let args = parse_prepared_builtin_call(prepared, b.params(), unnamed, named);
 				b.call(loc, &args)
@@ -239,7 +207,7 @@
 	/// This function should only be used for optimization, not for the conditional logic, i.e code should work with syntetic identity function too
 	pub fn is_identity(&self) -> bool {
 		match self {
-			Self::Id => true,
+			Self::Builtin(b) => b.as_any().downcast_ref::<builtin_id>().is_some(),
 			Self::Normal(desc) => {
 				if desc.params.len() != 1 {
 					return false;
@@ -257,13 +225,9 @@
 				};
 				matches!(&*desc.body, Expr::Var(v) if &**v == id)
 			}
-			_ => false,
+			Self::Thunk(_) => false,
 		}
 	}
-	/// Identity function value.
-	pub const fn identity() -> Self {
-		Self::Id
-	}
 
 	pub fn evaluate_trivial(&self) -> Option<Val> {
 		match self {
@@ -279,10 +243,5 @@
 {
 	fn from(value: T) -> Self {
 		Self::builtin(value)
-	}
-}
-impl From<&'static dyn StaticBuiltin> for FuncVal {
-	fn from(value: &'static dyn StaticBuiltin) -> Self {
-		Self::static_builtin(value)
 	}
 }