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};891011#[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 62 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}96979899100pub trait Builtin: Trace {101 102 fn name(&self) -> &str;103 104 fn params(&self) -> &[BuiltinParam];105 106 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 116 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 143 144 "<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}