1use crate::{2 create_error, evaluate, function::inline_parse_function_call, Context, Error, ObjValue, Result,3};4use jsonnet_parser::{ArgsDesc, LocExpr, ParamsDesc};5use std::{6 cell::RefCell,7 fmt::{Debug, Display},8 rc::Rc,9};1011struct LazyValInternals {12 pub f: Option<Box<dyn Fn() -> Result<Val>>>,13 pub cached: RefCell<Option<Val>>,14}15#[derive(Clone)]16pub struct LazyVal(Rc<LazyValInternals>);17impl LazyVal {18 pub fn new(f: Box<dyn Fn() -> Result<Val>>) -> Self {19 LazyVal(Rc::new(LazyValInternals {20 f: Some(f),21 cached: RefCell::new(None),22 }))23 }24 pub fn new_resolved(val: Val) -> Self {25 LazyVal(Rc::new(LazyValInternals {26 f: None,27 cached: RefCell::new(Some(val)),28 }))29 }30 pub fn evaluate(&self) -> Result<Val> {31 {32 let cached = self.0.cached.borrow();33 if cached.is_some() {34 return Ok(cached.clone().unwrap());35 }36 }37 let result = (self.0.f.as_ref().unwrap())()?;38 self.0.cached.borrow_mut().replace(result.clone());39 Ok(result)40 }41}4243#[macro_export]44macro_rules! lazy_val {45 ($f: expr) => {46 $crate::LazyVal::new(Box::new($f))47 };48}49#[macro_export]50macro_rules! resolved_lazy_val {51 ($f: expr) => {52 $crate::LazyVal::new_resolved($f)53 };54}55impl Debug for LazyVal {56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {57 if self.0.cached.borrow().is_some() {58 write!(f, "{:?}", self.0.cached.borrow().clone().unwrap())59 } else {60 write!(f, "Lazy")61 }62 }63}64impl PartialEq for LazyVal {65 fn eq(&self, other: &Self) -> bool {66 Rc::ptr_eq(&self.0, &other.0)67 }68}6970#[derive(Debug, PartialEq, Clone)]71pub struct FuncDesc {72 pub ctx: Context,73 pub params: ParamsDesc,74 pub body: LocExpr,75}76impl FuncDesc {77 78 79 #[inline(always)]80 pub fn evaluate(&self, call_ctx: Context, args: &ArgsDesc, tailstrict: bool) -> Result<Val> {81 let ctx = inline_parse_function_call(82 call_ctx,83 Some(self.ctx.clone()),84 &self.params,85 args,86 tailstrict,87 )?;88 evaluate(ctx, &self.body)89 }90}9192#[derive(Debug)]93pub enum ValType {94 Bool,95 Null,96 Str,97 Num,98 Arr,99 Obj,100 Func,101}102impl ValType {103 pub fn name(&self) -> &'static str {104 use ValType::*;105 match self {106 Bool => "boolean",107 Null => "null",108 Str => "string",109 Num => "number",110 Arr => "array",111 Obj => "object",112 Func => "function",113 }114 }115}116impl Display for ValType {117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {118 write!(f, "{}", self.name())119 }120}121122#[derive(Debug, PartialEq, Clone)]123pub enum Val {124 Bool(bool),125 Null,126 Str(String),127 Num(f64),128 Lazy(LazyVal),129 Arr(Vec<Val>),130 Obj(ObjValue),131 Func(FuncDesc),132133 134 Intristic(String, String),135}136impl Val {137 pub fn try_cast_bool(self, context: &'static str) -> Result<bool> {138 match self.unwrap_if_lazy()? {139 Val::Bool(v) => Ok(v),140 v => create_error(Error::TypeMismatch(141 context,142 vec![ValType::Bool],143 v.value_type()?,144 )),145 }146 }147 pub fn try_cast_str(self, context: &'static str) -> Result<String> {148 match self.unwrap_if_lazy()? {149 Val::Str(v) => Ok(v),150 v => create_error(Error::TypeMismatch(151 context,152 vec![ValType::Str],153 v.value_type()?,154 )),155 }156 }157 pub fn unwrap_if_lazy(self) -> Result<Self> {158 Ok(if let Val::Lazy(v) = self {159 v.evaluate()?.unwrap_if_lazy()?160 } else {161 self162 })163 }164 pub fn value_type(&self) -> Result<ValType> {165 Ok(match self {166 Val::Str(..) => ValType::Str,167 Val::Num(..) => ValType::Num,168 Val::Arr(..) => ValType::Arr,169 Val::Obj(..) => ValType::Obj,170 Val::Func(..) => ValType::Func,171 Val::Bool(_) => ValType::Bool,172 Val::Null => ValType::Null,173 Val::Intristic(_, _) => ValType::Func,174 Val::Lazy(_) => self.clone().unwrap_if_lazy()?.value_type()?,175 })176 }177}