git.delta.rocks / jrsonnet / refs/commits / 2edd59dfdd9f

difftreelog

source

crates/jsonnet-evaluator/src/val.rs3.7 KiBsourcehistory
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	/// This function is always inlined to make tailstrict work78	#[inline(always)]79	pub fn evaluate(&self, call_ctx: Context, args: &ArgsDesc, tailstrict: bool) -> Result<Val> {80		let ctx = inline_parse_function_call(81			call_ctx,82			Some(self.ctx.clone()),83			&self.params,84			args,85			tailstrict,86		)?;87		evaluate(ctx, &self.body)88	}89}9091#[derive(Debug)]92pub enum ValType {93	Bool,94	Null,95	Str,96	Num,97	Arr,98	Obj,99	Func,100}101impl ValType {102	pub fn name(&self) -> &'static str {103		use ValType::*;104		match self {105			Bool => "boolean",106			Null => "null",107			Str => "string",108			Num => "number",109			Arr => "array",110			Obj => "object",111			Func => "function",112		}113	}114}115impl Display for ValType {116	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {117		write!(f, "{}", self.name())118	}119}120121#[derive(Debug, PartialEq, Clone)]122pub enum Val {123	Bool(bool),124	Null,125	Str(String),126	Num(f64),127	Lazy(LazyVal),128	Arr(Vec<Val>),129	Obj(ObjValue),130	Func(FuncDesc),131132	// Library functions implemented in native133	Intristic(String, String),134}135impl Val {136	pub fn try_cast_bool(self, context: &'static str) -> Result<bool> {137		match self.unwrap_if_lazy()? {138			Val::Bool(v) => Ok(v),139			v => create_error(Error::TypeMismatch(140				context,141				vec![ValType::Bool],142				v.value_type()?,143			)),144		}145	}146	pub fn try_cast_str(self, context: &'static str) -> Result<String> {147		match self.unwrap_if_lazy()? {148			Val::Str(v) => Ok(v),149			v => create_error(Error::TypeMismatch(150				context,151				vec![ValType::Str],152				v.value_type()?,153			)),154		}155	}156	pub fn unwrap_if_lazy(self) -> Result<Self> {157		Ok(if let Val::Lazy(v) = self {158			v.evaluate()?.unwrap_if_lazy()?159		} else {160			self161		})162	}163	pub fn value_type(&self) -> Result<ValType> {164		Ok(match self {165			Val::Str(..) => ValType::Str,166			Val::Num(..) => ValType::Num,167			Val::Arr(..) => ValType::Arr,168			Val::Obj(..) => ValType::Obj,169			Val::Func(..) => ValType::Func,170			Val::Bool(_) => ValType::Bool,171			Val::Null => ValType::Null,172			Val::Intristic(_, _) => ValType::Func,173			Val::Lazy(_) => self.clone().unwrap_if_lazy()?.value_type()?,174		})175	}176}