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};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}7273747576pub trait Builtin: Trace {77 78 fn name(&self) -> &str;79 80 fn params(&self) -> &[BuiltinParam];81 82 fn call(&self, ctx: Context, loc: CallLocation<'_>, args: &dyn ArgsLike) -> Result<Val>;8384 fn as_any(&self) -> &dyn Any;85}8687pub trait StaticBuiltin: Builtin + Send + Sync88where89 Self: 'static,90{91 92 93}9495#[derive(Trace)]96pub struct NativeCallback {97 pub(crate) params: Vec<BuiltinParam>,98 handler: TraceBox<dyn NativeCallbackHandler>,99}100impl NativeCallback {101 #[deprecated = "prefer using builtins directly, use this interface only for bindings"]102 pub fn new(params: Vec<String>, handler: impl NativeCallbackHandler) -> Self {103 Self {104 params: params105 .into_iter()106 .map(|n| BuiltinParam {107 name: ParamName::new_dynamic(n),108 default: ParamDefault::Exists,109 })110 .collect(),111 handler: tb!(handler),112 }113 }114}115116impl Builtin for NativeCallback {117 fn name(&self) -> &str {118 119 120 "<native>"121 }122123 fn params(&self) -> &[BuiltinParam] {124 &self.params125 }126127 fn call(&self, ctx: Context, _loc: CallLocation<'_>, args: &dyn ArgsLike) -> Result<Val> {128 let args = parse_builtin_call(ctx, &self.params, args, true)?;129 let args = args130 .into_iter()131 .map(|a| a.expect("legacy natives have no default params"))132 .map(|a| a.evaluate())133 .collect::<Result<Vec<Val>>>()?;134 self.handler.call(&args)135 }136137 fn as_any(&self) -> &dyn Any {138 self139 }140}141142pub trait NativeCallbackHandler: Trace {143 fn call(&self, args: &[Val]) -> Result<Val>;144}