git.delta.rocks / jrsonnet / refs/commits / 8a16e5a437f6

difftreelog

refactor(stdlib) use IntoUntyped for builtins

vnovounqYaroslav Bolyukin2026-04-25parent: #60607d2.patch.diff
in: master

4 files changed

modifiedcrates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/lib.rs
+++ b/crates/jrsonnet-stdlib/src/lib.rs
@@ -12,15 +12,17 @@
 pub use encoding::*;
 pub use hash::*;
 use jrsonnet_evaluator::{
-	ContextBuilder, IStr, ObjValue, ObjValueBuilder, Thunk, Val,
 	error::Result,
-	function::{CallLocation, FuncVal},
+	function::{builtin_id, CallLocation, FuncVal},
 	tla::TlaArg,
 	trace::PathResolver,
+	typed::SerializeTypedObj as _,
 	val::NumValue,
+	ContextBuilder, IStr, ObjValue, ObjValueBuilder, Thunk, Val,
 };
 use jrsonnet_gcmodule::{Acyclic, Cc, Trace};
 use jrsonnet_ir::Source;
+use jrsonnet_macros::{IntoUntyped, Typed};
 pub use manifest::*;
 pub use math::*;
 pub use misc::*;
@@ -53,196 +55,352 @@
 mod strings;
 mod types;
 
+#[derive(Typed, IntoUntyped, Default)]
+#[allow(non_snake_case)]
+struct Builtins {
+	#[typed(method)]
+	id: builtin_id,
+	// Types
+	#[typed(method, rename = "type")]
+	r#type: builtin_type,
+	#[typed(method)]
+	isString: builtin_is_string,
+	#[typed(method)]
+	isNumber: builtin_is_number,
+	#[typed(method)]
+	isBoolean: builtin_is_boolean,
+	#[typed(method)]
+	isObject: builtin_is_object,
+	#[typed(method)]
+	isArray: builtin_is_array,
+	#[typed(method)]
+	isFunction: builtin_is_function,
+	#[typed(method)]
+	isNull: builtin_is_null,
+	// Arrays
+	#[typed(method)]
+	makeArray: builtin_make_array,
+	#[typed(method)]
+	repeat: builtin_repeat,
+	#[typed(method)]
+	slice: builtin_slice,
+	#[typed(method)]
+	map: builtin_map,
+	#[typed(method)]
+	mapWithIndex: builtin_map_with_index,
+	#[typed(method)]
+	mapWithKey: builtin_map_with_key,
+	#[typed(method)]
+	flatMap: builtin_flatmap,
+	#[typed(method)]
+	filter: builtin_filter,
+	#[typed(method)]
+	foldl: builtin_foldl,
+	#[typed(method)]
+	foldr: builtin_foldr,
+	#[typed(method)]
+	range: builtin_range,
+	#[typed(method)]
+	join: builtin_join,
+	#[typed(method)]
+	lines: builtin_lines,
+	#[typed(method)]
+	resolvePath: builtin_resolve_path,
+	#[typed(method)]
+	deepJoin: builtin_deep_join,
+	#[typed(method)]
+	reverse: builtin_reverse,
+	#[typed(method)]
+	any: builtin_any,
+	#[typed(method)]
+	all: builtin_all,
+	#[typed(method)]
+	member: builtin_member,
+	#[typed(method)]
+	find: builtin_find,
+	#[typed(method)]
+	contains: builtin_contains,
+	#[typed(method)]
+	count: builtin_count,
+	#[typed(method)]
+	avg: builtin_avg,
+	#[typed(method)]
+	removeAt: builtin_remove_at,
+	#[typed(method)]
+	remove: builtin_remove,
+	#[typed(method)]
+	flattenArrays: builtin_flatten_arrays,
+	#[typed(method)]
+	flattenDeepArray: builtin_flatten_deep_array,
+	#[typed(method)]
+	prune: builtin_prune,
+	#[typed(method)]
+	filterMap: builtin_filter_map,
+	// Math
+	#[typed(method)]
+	abs: builtin_abs,
+	#[typed(method)]
+	sign: builtin_sign,
+	#[typed(method)]
+	max: builtin_max,
+	#[typed(method)]
+	min: builtin_min,
+	#[typed(method)]
+	clamp: builtin_clamp,
+	#[typed(method)]
+	sum: builtin_sum,
+	#[typed(method)]
+	modulo: builtin_modulo,
+	#[typed(method)]
+	floor: builtin_floor,
+	#[typed(method)]
+	ceil: builtin_ceil,
+	#[typed(method)]
+	log: builtin_log,
+	#[typed(method)]
+	log2: builtin_log2,
+	#[typed(method)]
+	log10: builtin_log10,
+	#[typed(method)]
+	pow: builtin_pow,
+	#[typed(method)]
+	sqrt: builtin_sqrt,
+	#[typed(method)]
+	sin: builtin_sin,
+	#[typed(method)]
+	cos: builtin_cos,
+	#[typed(method)]
+	tan: builtin_tan,
+	#[typed(method)]
+	asin: builtin_asin,
+	#[typed(method)]
+	acos: builtin_acos,
+	#[typed(method)]
+	atan: builtin_atan,
+	#[typed(method)]
+	atan2: builtin_atan2,
+	#[typed(method)]
+	exp: builtin_exp,
+	#[typed(method)]
+	mantissa: builtin_mantissa,
+	#[typed(method)]
+	exponent: builtin_exponent,
+	#[typed(method)]
+	round: builtin_round,
+	#[typed(method)]
+	isEven: builtin_is_even,
+	#[typed(method)]
+	isOdd: builtin_is_odd,
+	#[typed(method)]
+	isInteger: builtin_is_integer,
+	#[typed(method)]
+	isDecimal: builtin_is_decimal,
+	#[typed(method)]
+	deg2rad: builtin_deg2rad,
+	#[typed(method)]
+	rad2deg: builtin_rad2deg,
+	#[typed(method)]
+	hypot: builtin_hypot,
+	// Operator
+	#[typed(rename = "mod", method)]
+	r#mod: builtin_mod,
+	#[typed(method)]
+	primitiveEquals: builtin_primitive_equals,
+	#[typed(method)]
+	equals: builtin_equals,
+	#[typed(method)]
+	xor: builtin_xor,
+	#[typed(method)]
+	xnor: builtin_xnor,
+	#[typed(method)]
+	format: builtin_format,
+	// Sort
+	#[typed(method)]
+	sort: builtin_sort,
+	#[typed(method)]
+	uniq: builtin_uniq,
+	#[typed(method)]
+	set: builtin_set,
+	#[typed(method)]
+	minArray: builtin_min_array,
+	#[typed(method)]
+	maxArray: builtin_max_array,
+	// Hash
+	#[typed(method)]
+	md5: builtin_md5,
+	#[typed(method)]
+	sha1: builtin_sha1,
+	#[typed(method)]
+	sha256: builtin_sha256,
+	#[typed(method)]
+	sha512: builtin_sha512,
+	#[typed(method)]
+	sha3: builtin_sha3,
+	// Encoding
+	#[typed(method)]
+	encodeUTF8: builtin_encode_utf8,
+	#[typed(method)]
+	decodeUTF8: builtin_decode_utf8,
+	#[typed(method)]
+	base64: builtin_base64,
+	#[typed(method)]
+	base64Decode: builtin_base64_decode,
+	#[typed(method)]
+	base64DecodeBytes: builtin_base64_decode_bytes,
+	// Objects
+	#[typed(method)]
+	objectFieldsEx: builtin_object_fields_ex,
+	#[typed(method)]
+	objectFields: builtin_object_fields,
+	#[typed(method)]
+	objectFieldsAll: builtin_object_fields_all,
+	#[typed(method)]
+	objectValues: builtin_object_values,
+	#[typed(method)]
+	objectValuesAll: builtin_object_values_all,
+	#[typed(method)]
+	objectKeysValues: builtin_object_keys_values,
+	#[typed(method)]
+	objectKeysValuesAll: builtin_object_keys_values_all,
+	#[typed(method)]
+	objectHasEx: builtin_object_has_ex,
+	#[typed(method)]
+	objectHas: builtin_object_has,
+	#[typed(method)]
+	objectHasAll: builtin_object_has_all,
+	#[typed(method)]
+	objectRemoveKey: builtin_object_remove_key,
+	// Manifest
+	#[typed(method)]
+	escapeStringJson: builtin_escape_string_json,
+	#[typed(method)]
+	escapeStringPython: builtin_escape_string_python,
+	#[typed(method)]
+	escapeStringXML: builtin_escape_string_xml,
+	#[typed(method)]
+	manifestJsonEx: builtin_manifest_json_ex,
+	#[typed(method)]
+	manifestJson: builtin_manifest_json,
+	#[typed(method)]
+	manifestJsonMinified: builtin_manifest_json_minified,
+	#[typed(method)]
+	manifestYamlDoc: builtin_manifest_yaml_doc,
+	#[typed(method)]
+	manifestYamlStream: builtin_manifest_yaml_stream,
+	#[typed(method)]
+	manifestTomlEx: builtin_manifest_toml_ex,
+	#[typed(method)]
+	manifestToml: builtin_manifest_toml,
+	#[typed(method)]
+	toString: builtin_to_string,
+	#[typed(method)]
+	manifestPython: builtin_manifest_python,
+	#[typed(method)]
+	manifestPythonVars: builtin_manifest_python_vars,
+	#[typed(method)]
+	manifestXmlJsonml: builtin_manifest_xml_jsonml,
+	#[typed(method)]
+	manifestIni: builtin_manifest_ini,
+	// Parse
+	#[typed(method)]
+	parseJson: builtin_parse_json,
+	#[typed(method)]
+	parseYaml: builtin_parse_yaml,
+	// Strings
+	#[typed(method)]
+	codepoint: builtin_codepoint,
+	#[typed(method)]
+	substr: builtin_substr,
+	#[typed(method)]
+	char: builtin_char,
+	#[typed(method)]
+	strReplace: builtin_str_replace,
+	#[typed(method)]
+	escapeStringBash: builtin_escape_string_bash,
+	#[typed(method)]
+	escapeStringDollars: builtin_escape_string_dollars,
+	#[typed(method)]
+	isEmpty: builtin_is_empty,
+	#[typed(method)]
+	equalsIgnoreCase: builtin_equals_ignore_case,
+	#[typed(method)]
+	splitLimit: builtin_splitlimit,
+	#[typed(method)]
+	splitLimitR: builtin_splitlimitr,
+	#[typed(method)]
+	split: builtin_split,
+	#[typed(method)]
+	asciiUpper: builtin_ascii_upper,
+	#[typed(method)]
+	asciiLower: builtin_ascii_lower,
+	#[typed(method)]
+	findSubstr: builtin_find_substr,
+	#[typed(method)]
+	parseInt: builtin_parse_int,
+	#[cfg(feature = "exp-bigint")]
+	#[typed(method)]
+	bigint: builtin_bigint,
+	#[typed(method)]
+	parseOctal: builtin_parse_octal,
+	#[typed(method)]
+	parseHex: builtin_parse_hex,
+	#[typed(method)]
+	stringChars: builtin_string_chars,
+	#[typed(method)]
+	lstripChars: builtin_lstrip_chars,
+	#[typed(method)]
+	rstripChars: builtin_rstrip_chars,
+	#[typed(method)]
+	stripChars: builtin_strip_chars,
+	#[typed(method)]
+	trim: builtin_trim,
+	// Misc
+	#[typed(method)]
+	length: builtin_length,
+	#[typed(method)]
+	get: builtin_get,
+	#[typed(method)]
+	startsWith: builtin_starts_with,
+	#[typed(method)]
+	endsWith: builtin_ends_with,
+	#[typed(method)]
+	assertEqual: builtin_assert_equal,
+	#[typed(method)]
+	mergePatch: builtin_merge_patch,
+	// Sets
+	#[typed(method)]
+	setMember: builtin_set_member,
+	#[typed(method)]
+	setInter: builtin_set_inter,
+	#[typed(method)]
+	setDiff: builtin_set_diff,
+	#[typed(method)]
+	setUnion: builtin_set_union,
+	// Regex
+	#[cfg(feature = "exp-regex")]
+	#[typed(method)]
+	regexQuoteMeta: builtin_regex_quote_meta,
+	// Compat
+	#[typed(method)]
+	__compare: builtin___compare,
+	#[typed(method)]
+	__compare_array: builtin___compare_array,
+	#[typed(method)]
+	__array_less: builtin___array_less,
+	#[typed(method)]
+	__array_greater: builtin___array_greater,
+	#[typed(method)]
+	__array_less_or_equal: builtin___array_less_or_equal,
+	#[typed(method)]
+	__array_greater_or_equal: builtin___array_greater_or_equal,
+}
+
 #[allow(clippy::too_many_lines)]
 pub fn stdlib_uncached(settings: Cc<RefCell<Settings>>) -> ObjValue {
 	let mut builder = ObjValueBuilder::new();
 
-	// FIXME: Use PHF
-	for (name, builtin) in [
-		// Types
-		("type", builtin_type::INST),
-		("isString", builtin_is_string::INST),
-		("isNumber", builtin_is_number::INST),
-		("isBoolean", builtin_is_boolean::INST),
-		("isObject", builtin_is_object::INST),
-		("isArray", builtin_is_array::INST),
-		("isFunction", builtin_is_function::INST),
-		("isNull", builtin_is_null::INST),
-		// Arrays
-		("makeArray", builtin_make_array::INST),
-		("repeat", builtin_repeat::INST),
-		("slice", builtin_slice::INST),
-		("map", builtin_map::INST),
-		("mapWithIndex", builtin_map_with_index::INST),
-		("mapWithKey", builtin_map_with_key::INST),
-		("flatMap", builtin_flatmap::INST),
-		("filter", builtin_filter::INST),
-		("foldl", builtin_foldl::INST),
-		("foldr", builtin_foldr::INST),
-		("range", builtin_range::INST),
-		("join", builtin_join::INST),
-		("lines", builtin_lines::INST),
-		("resolvePath", builtin_resolve_path::INST),
-		("deepJoin", builtin_deep_join::INST),
-		("reverse", builtin_reverse::INST),
-		("any", builtin_any::INST),
-		("all", builtin_all::INST),
-		("member", builtin_member::INST),
-		("find", builtin_find::INST),
-		("contains", builtin_contains::INST),
-		("count", builtin_count::INST),
-		("avg", builtin_avg::INST),
-		("removeAt", builtin_remove_at::INST),
-		("remove", builtin_remove::INST),
-		("flattenArrays", builtin_flatten_arrays::INST),
-		("flattenDeepArray", builtin_flatten_deep_array::INST),
-		("prune", builtin_prune::INST),
-		("filterMap", builtin_filter_map::INST),
-		// Math
-		("abs", builtin_abs::INST),
-		("sign", builtin_sign::INST),
-		("max", builtin_max::INST),
-		("min", builtin_min::INST),
-		("clamp", builtin_clamp::INST),
-		("sum", builtin_sum::INST),
-		("modulo", builtin_modulo::INST),
-		("floor", builtin_floor::INST),
-		("ceil", builtin_ceil::INST),
-		("log", builtin_log::INST),
-		("log2", builtin_log2::INST),
-		("log10", builtin_log10::INST),
-		("pow", builtin_pow::INST),
-		("sqrt", builtin_sqrt::INST),
-		("sin", builtin_sin::INST),
-		("cos", builtin_cos::INST),
-		("tan", builtin_tan::INST),
-		("asin", builtin_asin::INST),
-		("acos", builtin_acos::INST),
-		("atan", builtin_atan::INST),
-		("atan2", builtin_atan2::INST),
-		("exp", builtin_exp::INST),
-		("mantissa", builtin_mantissa::INST),
-		("exponent", builtin_exponent::INST),
-		("round", builtin_round::INST),
-		("isEven", builtin_is_even::INST),
-		("isOdd", builtin_is_odd::INST),
-		("isInteger", builtin_is_integer::INST),
-		("isDecimal", builtin_is_decimal::INST),
-		("deg2rad", builtin_deg2rad::INST),
-		("rad2deg", builtin_rad2deg::INST),
-		("hypot", builtin_hypot::INST),
-		// Operator
-		("mod", builtin_mod::INST),
-		("primitiveEquals", builtin_primitive_equals::INST),
-		("equals", builtin_equals::INST),
-		("xor", builtin_xor::INST),
-		("xnor", builtin_xnor::INST),
-		("format", builtin_format::INST),
-		// Sort
-		("sort", builtin_sort::INST),
-		("uniq", builtin_uniq::INST),
-		("set", builtin_set::INST),
-		("minArray", builtin_min_array::INST),
-		("maxArray", builtin_max_array::INST),
-		// Hash
-		("md5", builtin_md5::INST),
-		("sha1", builtin_sha1::INST),
-		("sha256", builtin_sha256::INST),
-		("sha512", builtin_sha512::INST),
-		("sha3", builtin_sha3::INST),
-		// Encoding
-		("encodeUTF8", builtin_encode_utf8::INST),
-		("decodeUTF8", builtin_decode_utf8::INST),
-		("base64", builtin_base64::INST),
-		("base64Decode", builtin_base64_decode::INST),
-		("base64DecodeBytes", builtin_base64_decode_bytes::INST),
-		// Objects
-		("objectFieldsEx", builtin_object_fields_ex::INST),
-		("objectFields", builtin_object_fields::INST),
-		("objectFieldsAll", builtin_object_fields_all::INST),
-		("objectValues", builtin_object_values::INST),
-		("objectValuesAll", builtin_object_values_all::INST),
-		("objectKeysValues", builtin_object_keys_values::INST),
-		("objectKeysValuesAll", builtin_object_keys_values_all::INST),
-		("objectHasEx", builtin_object_has_ex::INST),
-		("objectHas", builtin_object_has::INST),
-		("objectHasAll", builtin_object_has_all::INST),
-		("objectRemoveKey", builtin_object_remove_key::INST),
-		// Manifest
-		("escapeStringJson", builtin_escape_string_json::INST),
-		("escapeStringPython", builtin_escape_string_python::INST),
-		("escapeStringXML", builtin_escape_string_xml::INST),
-		("manifestJsonEx", builtin_manifest_json_ex::INST),
-		("manifestJson", builtin_manifest_json::INST),
-		("manifestJsonMinified", builtin_manifest_json_minified::INST),
-		("manifestYamlDoc", builtin_manifest_yaml_doc::INST),
-		("manifestYamlStream", builtin_manifest_yaml_stream::INST),
-		("manifestTomlEx", builtin_manifest_toml_ex::INST),
-		("manifestToml", builtin_manifest_toml::INST),
-		("toString", builtin_to_string::INST),
-		("manifestPython", builtin_manifest_python::INST),
-		("manifestPythonVars", builtin_manifest_python_vars::INST),
-		("manifestXmlJsonml", builtin_manifest_xml_jsonml::INST),
-		("manifestIni", builtin_manifest_ini::INST),
-		// Parse
-		("parseJson", builtin_parse_json::INST),
-		("parseYaml", builtin_parse_yaml::INST),
-		// Strings
-		("codepoint", builtin_codepoint::INST),
-		("substr", builtin_substr::INST),
-		("char", builtin_char::INST),
-		("strReplace", builtin_str_replace::INST),
-		("escapeStringBash", builtin_escape_string_bash::INST),
-		("escapeStringDollars", builtin_escape_string_dollars::INST),
-		("isEmpty", builtin_is_empty::INST),
-		("equalsIgnoreCase", builtin_equals_ignore_case::INST),
-		("splitLimit", builtin_splitlimit::INST),
-		("splitLimitR", builtin_splitlimitr::INST),
-		("split", builtin_split::INST),
-		("asciiUpper", builtin_ascii_upper::INST),
-		("asciiLower", builtin_ascii_lower::INST),
-		("findSubstr", builtin_find_substr::INST),
-		("parseInt", builtin_parse_int::INST),
-		#[cfg(feature = "exp-bigint")]
-		("bigint", builtin_bigint::INST),
-		("parseOctal", builtin_parse_octal::INST),
-		("parseHex", builtin_parse_hex::INST),
-		("stringChars", builtin_string_chars::INST),
-		("lstripChars", builtin_lstrip_chars::INST),
-		("rstripChars", builtin_rstrip_chars::INST),
-		("stripChars", builtin_strip_chars::INST),
-		("trim", builtin_trim::INST),
-		// Misc
-		("length", builtin_length::INST),
-		("get", builtin_get::INST),
-		("startsWith", builtin_starts_with::INST),
-		("endsWith", builtin_ends_with::INST),
-		("assertEqual", builtin_assert_equal::INST),
-		("mergePatch", builtin_merge_patch::INST),
-		// Sets
-		("setMember", builtin_set_member::INST),
-		("setInter", builtin_set_inter::INST),
-		("setDiff", builtin_set_diff::INST),
-		("setUnion", builtin_set_union::INST),
-		// Regex
-		#[cfg(feature = "exp-regex")]
-		("regexQuoteMeta", builtin_regex_quote_meta::INST),
-		// Compat
-		("__compare", builtin___compare::INST),
-		("__compare_array", builtin___compare_array::INST),
-		("__array_less", builtin___array_less::INST),
-		("__array_greater", builtin___array_greater::INST),
-		("__array_less_or_equal", builtin___array_less_or_equal::INST),
-		(
-			"__array_greater_or_equal",
-			builtin___array_greater_or_equal::INST,
-		),
-	]
-	.iter()
-	.copied()
-	{
-		builder.method(name, builtin);
-	}
+	let builtins = Builtins::default();
+	builtins.serialize(&mut builder).expect("no conflicts");
 
 	builder.method(
 		"extVar",
@@ -257,7 +415,6 @@
 		},
 	);
 	builder.method("trace", builtin_trace { settings });
-	builder.method("id", FuncVal::Id);
 
 	builder.field("pi").hide().value(Val::Num(
 		NumValue::new(f64::consts::PI).expect("pi is finite"),
modifiedtests/tests/builtin.rsdiffbeforeafterboth
before · tests/tests/builtin.rs
1mod common;23use jrsonnet_evaluator::{4	ContextBuilder, ContextInitializer, FileImportResolver, Result, State, Thunk, Val,5	function::{CallLocation, FuncVal, builtin, builtin::Builtin},6	parser::Source,7	trace::PathResolver,8	typed::FromUntyped,9};10use jrsonnet_gcmodule::Trace;11use jrsonnet_stdlib::ContextInitializer as StdContextInitializer;1213#[builtin]14fn a() -> u32 {15	116}1718#[test]19fn basic_function() -> Result<()> {20	let a: a = a {};21	let v = u32::from_untyped(a.call(CallLocation::native(), &[])?)?;2223	ensure_eq!(v, 1);24	Ok(())25}2627#[builtin]28fn native_add(a: u32, b: u32) -> u32 {29	a + b30}31#[derive(Trace)]32struct NativeAddContextInitializer;33impl ContextInitializer for NativeAddContextInitializer {34	fn populate(&self, _for_file: Source, builder: &mut ContextBuilder) {35		builder.bind(36			"nativeAdd",37			Thunk::evaluated(Val::function(native_add::INST)),38		);39	}4041	fn as_any(&self) -> &dyn std::any::Any {42		self43	}44}4546#[test]47fn call_from_code() -> Result<()> {48	let mut s = State::builder();49	s.context_initializer((50		StdContextInitializer::new(PathResolver::new_cwd_fallback()),51		NativeAddContextInitializer,52	))53	.import_resolver(FileImportResolver::default());54	let s = s.build();5556	let v = s.evaluate_snippet(57		"snip".to_owned(),58		"59            assert nativeAdd(1, 2) == 3;60            assert nativeAdd(100, 200) == 300;61            null62        ",63	)?;64	ensure_val_eq!(v, Val::Null);65	Ok(())66}6768#[builtin(fields(69    a: u3270))]71fn curried_add(this: &curried_add, b: u32) -> u32 {72	this.a + b73}7475#[builtin]76fn curry_add(a: u32) -> FuncVal {77	FuncVal::builtin(curried_add { a })78}79#[derive(Trace)]80struct CurryAddContextInitializer;81impl ContextInitializer for CurryAddContextInitializer {82	fn populate(&self, _for_file: Source, builder: &mut ContextBuilder) {83		builder.bind("curryAdd", Thunk::evaluated(Val::function(curry_add::INST)));84	}8586	fn as_any(&self) -> &dyn std::any::Any {87		self88	}89}9091#[test]92fn nonstatic_builtin() -> Result<()> {93	let mut s = State::builder();94	s.context_initializer((95		StdContextInitializer::new(PathResolver::new_cwd_fallback()),96		CurryAddContextInitializer,97	))98	.import_resolver(FileImportResolver::default());99	let s = s.build();100101	let v = s.evaluate_snippet(102		"snip".to_owned(),103		"104            local a = curryAdd(1);105            local b = curryAdd(4);106107            assert a(2) == 3;108            assert a(200) == 201;109110            assert b(2) == 6;111            assert b(200) == 204;112            null113        ",114	)?;115	ensure_val_eq!(v, Val::Null);116	Ok(())117}
after · tests/tests/builtin.rs
1mod common;23use jrsonnet_evaluator::{4	ContextBuilder, ContextInitializer, FileImportResolver, Result, State, Thunk, Val,5	function::{CallLocation, FuncVal, builtin, builtin::Builtin},6	parser::Source,7	trace::PathResolver,8	typed::FromUntyped,9};10use jrsonnet_gcmodule::Trace;11use jrsonnet_stdlib::ContextInitializer as StdContextInitializer;1213#[builtin]14fn a() -> u32 {15	116}1718#[test]19fn basic_function() -> Result<()> {20	let a: a = a {};21	let v = u32::from_untyped(a.call(CallLocation::native(), &[])?)?;2223	ensure_eq!(v, 1);24	Ok(())25}2627#[builtin]28fn native_add(a: u32, b: u32) -> u32 {29	a + b30}31#[derive(Trace)]32struct NativeAddContextInitializer;33impl ContextInitializer for NativeAddContextInitializer {34	fn populate(&self, _for_file: Source, builder: &mut ContextBuilder) {35		builder.bind("nativeAdd", Thunk::evaluated(Val::function(native_add {})));36	}3738	fn as_any(&self) -> &dyn std::any::Any {39		self40	}41}4243#[test]44fn call_from_code() -> Result<()> {45	let mut s = State::builder();46	s.context_initializer((47		StdContextInitializer::new(PathResolver::new_cwd_fallback()),48		NativeAddContextInitializer,49	))50	.import_resolver(FileImportResolver::default());51	let s = s.build();5253	let v = s.evaluate_snippet(54		"snip".to_owned(),55		"56            assert nativeAdd(1, 2) == 3;57            assert nativeAdd(100, 200) == 300;58            null59        ",60	)?;61	ensure_val_eq!(v, Val::Null);62	Ok(())63}6465#[builtin(fields(66    a: u3267))]68fn curried_add(this: &curried_add, b: u32) -> u32 {69	this.a + b70}7172#[builtin]73fn curry_add(a: u32) -> FuncVal {74	FuncVal::builtin(curried_add { a })75}76#[derive(Trace)]77struct CurryAddContextInitializer;78impl ContextInitializer for CurryAddContextInitializer {79	fn populate(&self, _for_file: Source, builder: &mut ContextBuilder) {80		builder.bind("curryAdd", Thunk::evaluated(Val::function(curry_add {})));81	}8283	fn as_any(&self) -> &dyn std::any::Any {84		self85	}86}8788#[test]89fn nonstatic_builtin() -> Result<()> {90	let mut s = State::builder();91	s.context_initializer((92		StdContextInitializer::new(PathResolver::new_cwd_fallback()),93		CurryAddContextInitializer,94	))95	.import_resolver(FileImportResolver::default());96	let s = s.build();9798	let v = s.evaluate_snippet(99		"snip".to_owned(),100		"101            local a = curryAdd(1);102            local b = curryAdd(4);103104            assert a(2) == 3;105            assert a(200) == 201;106107            assert b(2) == 6;108            assert b(200) == 204;109            null110        ",111	)?;112	ensure_val_eq!(v, Val::Null);113	Ok(())114}
modifiedtests/tests/common.rsdiffbeforeafterboth
--- a/tests/tests/common.rs
+++ b/tests/tests/common.rs
@@ -70,8 +70,8 @@
 impl ContextInitializerT for ContextInitializer {
 	fn populate(&self, _for_file: Source, builder: &mut ContextBuilder) {
 		let mut bobj = ObjValueBuilder::new();
-		bobj.method("assertThrow", assert_throw::INST);
-		bobj.method("paramNames", param_names::INST);
+		bobj.method("assertThrow", assert_throw {});
+		bobj.method("paramNames", param_names {});
 
 		builder.bind("test", Thunk::evaluated(Val::Obj(bobj.build())));
 	}
modifiedtests/tests/std_native.rsdiffbeforeafterboth
--- a/tests/tests/std_native.rs
+++ b/tests/tests/std_native.rs
@@ -10,7 +10,7 @@
 fn std_native() {
 	let mut state = State::builder();
 	let std = ContextInitializer::new(PathResolver::Absolute);
-	std.add_native("example", example_native::INST);
+	std.add_native("example", example_native {});
 	state.context_initializer(std);
 	let state = state.build();