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

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 data11#[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		match &self.0 {31			Some(s) => s.as_bytes() == other.as_bytes(),32			None => false,33		}34	}35}3637#[derive(Clone, Trace)]38pub struct BuiltinParam {39	name: ParamName,40	has_default: bool,41}42impl BuiltinParam {43	pub const fn new(name: ParamName, has_default: bool) -> Self {44		Self { name, has_default }45	}46	/// Parameter name for named call parsing47	pub fn name(&self) -> &ParamName {48		&self.name49	}50	/// Is implementation allowed to return empty value51	pub fn has_default(&self) -> bool {52		self.has_default53	}54}5556/// Description of function defined by native code57///58/// Prefer to use #[builtin] macro, instead of manual implementation of this trait59pub trait Builtin: Trace {60	/// Function name to be used in stack traces61	fn name(&self) -> &str;62	/// Parameter names for named calls63	fn params(&self) -> &[BuiltinParam];64	/// Call the builtin65	fn call(&self, ctx: Context, loc: CallLocation<'_>, args: &dyn ArgsLike) -> Result<Val>;6667	fn as_any(&self) -> &dyn Any;68}6970pub trait StaticBuiltin: Builtin + Send + Sync71where72	Self: 'static,73{74	// In impl, to make it object safe:75	// const INST: &'static Self;76}7778#[derive(Trace)]79pub struct NativeCallback {80	pub(crate) params: Vec<BuiltinParam>,81	handler: TraceBox<dyn NativeCallbackHandler>,82}83impl NativeCallback {84	#[deprecated = "prefer using builtins directly, use this interface only for bindings"]85	pub fn new(params: Vec<String>, handler: impl NativeCallbackHandler) -> Self {86		Self {87			params: params88				.into_iter()89				.map(|n| BuiltinParam {90					name: ParamName::new_dynamic(n.to_string()),91					has_default: false,92				})93				.collect(),94			handler: tb!(handler),95		}96	}97}9899impl Builtin for NativeCallback {100	fn name(&self) -> &str {101		// TODO: standard natives gets their names from definition102		// But builitins should already have them103		"<native>"104	}105106	fn params(&self) -> &[BuiltinParam] {107		&self.params108	}109110	fn call(&self, ctx: Context, _loc: CallLocation<'_>, args: &dyn ArgsLike) -> Result<Val> {111		let args = parse_builtin_call(ctx, &self.params, args, true)?;112		let args = args113			.into_iter()114			.map(|a| a.expect("legacy natives have no default params"))115			.map(|a| a.evaluate())116			.collect::<Result<Vec<Val>>>()?;117		self.handler.call(&args)118	}119120	fn as_any(&self) -> &dyn Any {121		self122	}123}124125pub trait NativeCallbackHandler: Trace {126	fn call(&self, args: &[Val]) -> Result<Val>;127}