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

difftreelog

source

crates/jrsonnet-evaluator/src/function/builtin.rs3.1 KiBsourcehistory
1use std::{any::Any, borrow::Cow};23use jrsonnet_gcmodule::Trace;4use jrsonnet_interner::IStr;56use super::{arglike::ArgsLike, parse::parse_builtin_call, CallLocation};7use crate::{gc::TraceBox, tb, Context, Result, Val};89/// Can't have `str` | `IStr`, because constant `BuiltinParam` causes10/// `E0492: constant functions cannot refer to interior mutable data`11#[derive(Clone, Trace)]12pub struct ParamName(Option<Cow<'static, str>>);13impl ParamName {14	pub const ANONYMOUS: Self = Self(None);15	pub const fn new_static(name: &'static str) -> Self {16		Self(Some(Cow::Borrowed(name)))17	}18	pub fn new_dynamic(name: String) -> Self {19		Self(Some(Cow::Owned(name)))20	}21	pub fn as_str(&self) -> Option<&str> {22		self.0.as_deref()23	}24	pub fn is_anonymous(&self) -> bool {25		self.0.is_none()26	}27}28impl PartialEq<IStr> for ParamName {29	fn eq(&self, other: &IStr) -> bool {30		self.031			.as_ref()32			.map_or(false, |s| s.as_bytes() == other.as_bytes())33	}34}3536#[derive(Clone, Trace)]37pub struct BuiltinParam {38	name: ParamName,39	has_default: bool,40}41impl BuiltinParam {42	pub const fn new(name: ParamName, has_default: bool) -> Self {43		Self { name, has_default }44	}45	/// Parameter name for named call parsing46	pub fn name(&self) -> &ParamName {47		&self.name48	}49	/// Is implementation allowed to return empty value50	pub fn has_default(&self) -> bool {51		self.has_default52	}53}5455/// Description of function defined by native code56///57/// Prefer to use #[builtin] macro, instead of manual implementation of this trait58pub trait Builtin: Trace {59	/// Function name to be used in stack traces60	fn name(&self) -> &str;61	/// Parameter names for named calls62	fn params(&self) -> &[BuiltinParam];63	/// Call the builtin64	fn call(&self, ctx: Context, loc: CallLocation<'_>, args: &dyn ArgsLike) -> Result<Val>;6566	fn as_any(&self) -> &dyn Any;67}6869pub trait StaticBuiltin: Builtin + Send + Sync70where71	Self: 'static,72{73	// In impl, to make it object safe:74	// const INST: &'static Self;75}7677#[derive(Trace)]78pub struct NativeCallback {79	pub(crate) params: Vec<BuiltinParam>,80	handler: TraceBox<dyn NativeCallbackHandler>,81}82impl NativeCallback {83	#[deprecated = "prefer using builtins directly, use this interface only for bindings"]84	pub fn new(params: Vec<String>, handler: impl NativeCallbackHandler) -> Self {85		Self {86			params: params87				.into_iter()88				.map(|n| BuiltinParam {89					name: ParamName::new_dynamic(n),90					has_default: false,91				})92				.collect(),93			handler: tb!(handler),94		}95	}96}9798impl Builtin for NativeCallback {99	fn name(&self) -> &str {100		// TODO: standard natives gets their names from definition101		// But builitins should already have them102		"<native>"103	}104105	fn params(&self) -> &[BuiltinParam] {106		&self.params107	}108109	fn call(&self, ctx: Context, _loc: CallLocation<'_>, args: &dyn ArgsLike) -> Result<Val> {110		let args = parse_builtin_call(ctx, &self.params, args, true)?;111		let args = args112			.into_iter()113			.map(|a| a.expect("legacy natives have no default params"))114			.map(|a| a.evaluate())115			.collect::<Result<Vec<Val>>>()?;116		self.handler.call(&args)117	}118119	fn as_any(&self) -> &dyn Any {120		self121	}122}123124pub trait NativeCallbackHandler: Trace {125	fn call(&self, args: &[Val]) -> Result<Val>;126}