git.delta.rocks / jrsonnet / refs/commits / 4aecc221ffa5

difftreelog

source

crates/jsonnet-evaluator/src/val.rs4.3 KiBsourcehistory
1use crate::{lazy_binding, Context, FunctionDefault, FunctionRhs, LazyBinding, ObjValue};2use closure::closure;3use jsonnet_parser::ParamsDesc;4use std::{5	cell::RefCell,6	collections::HashMap,7	fmt::{Debug, Display},8	rc::Rc,9};1011struct LazyValInternals {12	pub f: Box<dyn Fn() -> 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() -> Val>) -> Self {19		LazyVal(Rc::new(LazyValInternals {20			f,21			cached: RefCell::new(None),22		}))23	}24	pub fn evaluate(&self) -> Val {25		{26			let cached = self.0.cached.borrow();27			if cached.is_some() {28				return cached.clone().unwrap();29			}30		}31		let result = (self.0.f)();32		self.0.cached.borrow_mut().replace(result.clone());33		result34	}35}36#[macro_export]37macro_rules! lazy_val {38	($f: expr) => {39		$crate::LazyVal::new(Box::new($f))40	};41}42impl Debug for LazyVal {43	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {44		write!(f, "Lazy")45	}46}47impl PartialEq for LazyVal {48	fn eq(&self, other: &Self) -> bool {49		Rc::ptr_eq(&self.0, &other.0)50	}51}5253#[derive(Debug, PartialEq, Clone)]54pub struct FuncDesc {55	pub ctx: Context,56	pub params: ParamsDesc,57	pub eval_rhs: FunctionRhs,58	pub eval_default: FunctionDefault,59}60impl FuncDesc {61	// TODO: Check for unset variables62	pub fn evaluate(&self, args: Vec<(Option<String>, Val)>) -> Val {63		let mut new_bindings: HashMap<String, LazyBinding> = HashMap::new();64		let future_ctx = Context::new_future();6566		// self.params67		// 	.with_defaults()68		// 	.into_iter()69		// 	.for_each(|Param(name, default)| {70		// 		let default = Rc::new(*default.unwrap());71		// 		new_bindings.insert(72		// 			name,73		// 			binding!(move |_, _| Val::Lazy(lazy_val!(|| self74		// 				.eval_default75		// 				.076		// 				.default(future_ctx.unwrap(), *default.clone())))),77		// 		);78		// 	});79		for (name, val) in args.clone().into_iter().filter(|e| e.0.is_some()) {80			new_bindings.insert(81				name.as_ref().unwrap().clone(),82				lazy_binding!(83					closure!(clone val, |_, _| lazy_val!(closure!(clone val, || val.clone())))84				),85			);86		}87		for (i, param) in self.params.0.iter().enumerate() {88			if let Some((None, val)) = args.get(i) {89				new_bindings.insert(90					param.0.clone(),91					lazy_binding!(92						closure!(clone val, |_, _| lazy_val!(closure!(clone val, || val.clone())))93					),94				);95			}96		}97		let ctx = self98			.ctx99			.extend(new_bindings, None, None, None)100			.into_future(future_ctx);101		self.eval_rhs.0(ctx)102	}103}104105#[derive(Debug, PartialEq, Clone)]106pub enum Val {107	Bool(bool),108	Null,109	Str(String),110	Num(f64),111	Lazy(LazyVal),112	Arr(Vec<Val>),113	Obj(ObjValue),114	Func(FuncDesc),115116	// Library functions implemented in native117	Intristic(String, String),118}119impl Val {120	pub fn try_cast_bool(self) -> bool {121		match self.unwrap_if_lazy() {122			Val::Bool(v) => v,123			v => panic!("expected bool, got {:?}", v),124		}125	}126	pub fn try_cast_str(self) -> String {127		match self.unwrap_if_lazy() {128			Val::Str(v) => v,129			v => panic!("expected bool, got {:?}", v),130		}131	}132	pub fn unwrap_if_lazy(self) -> Self {133		if let Val::Lazy(v) = self {134			v.evaluate().unwrap_if_lazy()135		} else {136			self137		}138	}139	pub fn type_of(&self) -> &'static str {140		match self {141			Val::Str(..) => "string",142			Val::Num(..) => "number",143			Val::Arr(..) => "array",144			Val::Obj(..) => "object",145			Val::Func(..) => "function",146			_ => panic!("no native type found"),147		}148	}149}150impl Display for Val {151	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {152		match self {153			Val::Str(str) => write!(f, "\"{}\"", str)?,154			Val::Num(n) => write!(f, "{}", n)?,155			Val::Arr(values) => {156				write!(f, "[")?;157				let mut first = true;158				for value in values {159					if first {160						first = false;161					} else {162						write!(f, ",")?;163					}164					write!(f, "{}", value)?;165				}166				write!(f, "]")?;167			}168			Val::Obj(value) => {169				write!(f, "{{")?;170				let mut first = true;171				for field in value.fields() {172					if first {173						first = false;174					} else {175						write!(f, ",")?;176					}177					write!(f, "\"{}\":", field)?;178					write!(f, "{}", value.get(&field).unwrap())?;179				}180				write!(f, "}}")?;181			}182			Val::Lazy(lazy) => {183				write!(f, "{}", lazy.evaluate())?;184			}185			Val::Func(_) => {186				write!(f, "<<FUNC>>")?;187			}188			v => panic!("no json equivalent for {:?}", v),189		};190		Ok(())191	}192}193194pub fn bool_val(v: bool) -> Val {195	Val::Bool(v)196}