1use crate::{2 error::Error::*, map::LayeredHashMap, FutureWrapper, LazyBinding, LazyVal, ObjValue, Result,3 Val,4};5use jrsonnet_gc::{Gc, Trace};6use jrsonnet_interner::IStr;7use rustc_hash::FxHashMap;8use std::fmt::Debug;9use std::hash::BuildHasherDefault;1011#[derive(Clone, Trace)]12#[trivially_drop]13pub struct ContextCreator(pub Context, pub FutureWrapper<FxHashMap<IStr, LazyBinding>>);14impl ContextCreator {15 pub fn create(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<Context> {16 self.0.clone().extend_unbound(17 self.1.clone().unwrap(),18 self.0.dollar().clone().or_else(|| this.clone()),19 this,20 super_obj,21 )22 }23}2425#[derive(Trace)]26#[trivially_drop]27struct ContextInternals {28 dollar: Option<ObjValue>,29 this: Option<ObjValue>,30 super_obj: Option<ObjValue>,31 bindings: LayeredHashMap,32}33impl Debug for ContextInternals {34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {35 f.debug_struct("Context").finish()36 }37}3839#[derive(Debug, Clone, Trace)]40#[trivially_drop]41pub struct Context(Gc<ContextInternals>);42impl Context {43 pub fn new_future() -> FutureWrapper<Self> {44 FutureWrapper::new()45 }4647 pub fn dollar(&self) -> &Option<ObjValue> {48 &self.0.dollar49 }5051 pub fn this(&self) -> &Option<ObjValue> {52 &self.0.this53 }5455 pub fn super_obj(&self) -> &Option<ObjValue> {56 &self.0.super_obj57 }5859 pub fn new() -> Self {60 Self(Gc::new(ContextInternals {61 dollar: None,62 this: None,63 super_obj: None,64 bindings: LayeredHashMap::default(),65 }))66 }6768 pub fn binding(&self, name: IStr) -> Result<LazyVal> {69 Ok(self70 .071 .bindings72 .get(&name)73 .cloned()74 .ok_or(VariableIsNotDefined(name))?)75 }76 pub fn contains_binding(&self, name: IStr) -> bool {77 self.0.bindings.contains_key(&name)78 }79 pub fn into_future(self, ctx: FutureWrapper<Self>) -> Self {80 {81 ctx.0.borrow_mut().replace(self);82 }83 ctx.unwrap()84 }8586 pub fn with_var(self, name: IStr, value: Val) -> Self {87 let mut new_bindings =88 FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());89 new_bindings.insert(name, LazyVal::new_resolved(value));90 self.extend(new_bindings, None, None, None)91 }9293 pub fn with_this_super(self, new_this: ObjValue, new_super_obj: Option<ObjValue>) -> Self {94 self.extend(FxHashMap::default(), None, Some(new_this), new_super_obj)95 }9697 pub fn extend(98 self,99 new_bindings: FxHashMap<IStr, LazyVal>,100 new_dollar: Option<ObjValue>,101 new_this: Option<ObjValue>,102 new_super_obj: Option<ObjValue>,103 ) -> Self {104 let ctx = &self.0;105 let dollar = new_dollar.or_else(|| ctx.dollar.clone());106 let this = new_this.or_else(|| ctx.this.clone());107 let super_obj = new_super_obj.or_else(|| ctx.super_obj.clone());108 let bindings = if new_bindings.is_empty() {109 ctx.bindings.clone()110 } else {111 ctx.bindings.clone().extend(new_bindings)112 };113 Self(Gc::new(ContextInternals {114 dollar,115 this,116 super_obj,117 bindings,118 }))119 }120 pub fn extend_bound(self, new_bindings: FxHashMap<IStr, LazyVal>) -> Self {121 let new_this = self.0.this.clone();122 let new_super_obj = self.0.super_obj.clone();123 self.extend(new_bindings, None, new_this, new_super_obj)124 }125 pub fn extend_unbound(126 self,127 new_bindings: FxHashMap<IStr, LazyBinding>,128 new_dollar: Option<ObjValue>,129 new_this: Option<ObjValue>,130 new_super_obj: Option<ObjValue>,131 ) -> Result<Self> {132 let this = new_this.or_else(|| self.0.this.clone());133 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());134 let mut new =135 FxHashMap::with_capacity_and_hasher(new_bindings.len(), BuildHasherDefault::default());136 for (k, v) in new_bindings.into_iter() {137 new.insert(k, v.evaluate(this.clone(), super_obj.clone())?);138 }139 Ok(self.extend(new, new_dollar, this, super_obj))140 }141 #[cfg(feature = "unstable")]142 pub fn into_weak(self) -> WeakContext {143 WeakContext(Rc::downgrade(&self.0))144 }145}146147impl Default for Context {148 fn default() -> Self {149 Self::new()150 }151}152153impl PartialEq for Context {154 fn eq(&self, other: &Self) -> bool {155 Gc::ptr_eq(&self.0, &other.0)156 }157}