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

difftreelog

source

crates/jrsonnet-evaluator/src/function/builtin.rs3.8 KiBsourcehistory
1use std::{any::Any, borrow::Cow};23use jrsonnet_gcmodule::{cc_dyn, Trace, TraceBox};4use jrsonnet_interner::IStr;56use super::{arglike::ArgsLike, parse::parse_builtin_call, CallLocation};7use crate::{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, Copy, Debug, Trace)]37pub enum ParamDefault {38	None,39	Exists,40	Literal(&'static str),41}42impl ParamDefault {43	pub const fn exists(is_exists: bool) -> Self {44		if is_exists {45			Self::Exists46		} else {47			Self::None48		}49	}50}5152#[derive(Clone, Trace)]53pub struct BuiltinParam {54	name: ParamName,55	default: ParamDefault,56}57impl BuiltinParam {58	pub const fn new(name: ParamName, default: ParamDefault) -> Self {59		Self { name, default }60	}61	/// Parameter name for named call parsing62	pub fn name(&self) -> &ParamName {63		&self.name64	}65	pub fn default(&self) -> ParamDefault {66		self.default67	}68	pub fn has_default(&self) -> bool {69		!matches!(self.default, ParamDefault::None)70	}71}7273cc_dyn!(74	#[derive(Clone)]75	BuiltinFunc,76	Builtin,77	pub(crate) fn new() {...}78);79impl Builtin for BuiltinFunc {80	fn name(&self) -> &str {81		self.0.name()82	}8384	fn params(&self) -> &[BuiltinParam] {85		self.0.params()86	}8788	fn call(&self, ctx: Context, loc: CallLocation<'_>, args: &dyn ArgsLike) -> Result<Val> {89		self.0.call(ctx, loc, args)90	}9192	fn as_any(&self) -> &dyn Any {93		self.0.as_any()94	}95}9697/// Description of function defined by native code98///99/// Prefer to use #[builtin] macro, instead of manual implementation of this trait100pub trait Builtin: Trace {101	/// Function name to be used in stack traces102	fn name(&self) -> &str;103	/// Parameter names for named calls104	fn params(&self) -> &[BuiltinParam];105	/// Call the builtin106	fn call(&self, ctx: Context, loc: CallLocation<'_>, args: &dyn ArgsLike) -> Result<Val>;107108	fn as_any(&self) -> &dyn Any;109}110111pub trait StaticBuiltin: Builtin + Send + Sync112where113	Self: 'static,114{115	// In impl, to make it object safe:116	// const INST: &'static Self;117}118119#[derive(Trace)]120pub struct NativeCallback {121	pub(crate) params: Vec<BuiltinParam>,122	handler: TraceBox<dyn NativeCallbackHandler>,123}124impl NativeCallback {125	#[deprecated = "prefer using builtins directly, use this interface only for bindings"]126	pub fn new(params: Vec<String>, handler: impl NativeCallbackHandler) -> Self {127		Self {128			params: params129				.into_iter()130				.map(|n| BuiltinParam {131					name: ParamName::new_dynamic(n),132					default: ParamDefault::None,133				})134				.collect(),135			handler: TraceBox(Box::new(handler)),136		}137	}138}139140impl Builtin for NativeCallback {141	fn name(&self) -> &str {142		// TODO: standard natives gets their names from definition143		// But builitins should already have them144		"<native>"145	}146147	fn params(&self) -> &[BuiltinParam] {148		&self.params149	}150151	fn call(&self, ctx: Context, _loc: CallLocation<'_>, args: &dyn ArgsLike) -> Result<Val> {152		let args = parse_builtin_call(ctx, &self.params, args, true)?;153		let args = args154			.into_iter()155			.map(|a| a.expect("legacy natives have no default params"))156			.map(|a| a.evaluate())157			.collect::<Result<Vec<Val>>>()?;158		self.handler.call(&args)159	}160161	fn as_any(&self) -> &dyn Any {162		self163	}164}165166pub trait NativeCallbackHandler: Trace {167	fn call(&self, args: &[Val]) -> Result<Val>;168}