1use crate::{evaluate_add_op, LazyBinding, Result, Val};2use jrsonnet_gc::{Gc, GcCell, Trace};3use jrsonnet_interner::IStr;4use jrsonnet_parser::{ExprLocation, Visibility};5use rustc_hash::{FxHashMap, FxHashSet};6use std::hash::{Hash, Hasher};7use std::{fmt::Debug, hash::BuildHasherDefault};89#[derive(Debug, Trace)]10#[trivially_drop]11pub struct ObjMember {12 pub add: bool,13 pub visibility: Visibility,14 pub invoke: LazyBinding,15 pub location: Option<ExprLocation>,16}1718pub trait ObjectAssertion: Trace {19 fn run(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<()>;20}212223type CacheKey = (IStr, ObjValue);24#[derive(Trace)]25#[trivially_drop]26pub struct ObjValueInternals {27 super_obj: Option<ObjValue>,28 assertions: Gc<Vec<Box<dyn ObjectAssertion>>>,29 assertions_ran: GcCell<FxHashSet<ObjValue>>,30 this_obj: Option<ObjValue>,31 this_entries: Gc<FxHashMap<IStr, ObjMember>>,32 value_cache: GcCell<FxHashMap<CacheKey, Option<Val>>>,33}3435#[derive(Clone, Trace)]36#[trivially_drop]37pub struct ObjValue(pub(crate) Gc<ObjValueInternals>);38impl Debug for ObjValue {39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {40 if let Some(super_obj) = self.0.super_obj.as_ref() {41 if f.alternate() {42 write!(f, "{:#?}", super_obj)?;43 } else {44 write!(f, "{:?}", super_obj)?;45 }46 write!(f, " + ")?;47 }48 let mut debug = f.debug_struct("ObjValue");49 for (name, member) in self.0.this_entries.iter() {50 debug.field(name, member);51 }52 #[cfg(feature = "unstable")]53 {54 debug.finish_non_exhaustive()55 }56 #[cfg(not(feature = "unstable"))]57 {58 debug.finish()59 }60 }61}6263impl ObjValue {64 pub fn new(65 super_obj: Option<Self>,66 this_entries: Gc<FxHashMap<IStr, ObjMember>>,67 assertions: Gc<Vec<Box<dyn ObjectAssertion>>>,68 ) -> Self {69 Self(Gc::new(ObjValueInternals {70 super_obj,71 assertions,72 assertions_ran: GcCell::new(FxHashSet::default()),73 this_obj: None,74 this_entries,75 value_cache: GcCell::new(FxHashMap::default()),76 }))77 }78 pub fn new_empty() -> Self {79 Self::new(None, Gc::new(FxHashMap::default()), Gc::new(Vec::new()))80 }81 pub fn extend_from(&self, super_obj: Self) -> Self {82 match &self.0.super_obj {83 None => Self::new(84 Some(super_obj),85 self.0.this_entries.clone(),86 self.0.assertions.clone(),87 ),88 Some(v) => Self::new(89 Some(v.extend_from(super_obj)),90 self.0.this_entries.clone(),91 self.0.assertions.clone(),92 ),93 }94 }95 pub fn with_this(&self, this_obj: Self) -> Self {96 Self(Gc::new(ObjValueInternals {97 super_obj: self.0.super_obj.clone(),98 assertions: self.0.assertions.clone(),99 assertions_ran: GcCell::new(FxHashSet::default()),100 this_obj: Some(this_obj),101 this_entries: self.0.this_entries.clone(),102 value_cache: GcCell::new(FxHashMap::default()),103 }))104 }105106 107 pub(crate) fn enum_fields(&self, handler: &mut impl FnMut(&IStr, &Visibility) -> bool) -> bool {108 if let Some(s) = &self.0.super_obj {109 if s.enum_fields(handler) {110 return true;111 }112 }113 for (name, member) in self.0.this_entries.iter() {114 if handler(name, &member.visibility) {115 return true;116 }117 }118 false119 }120121 pub fn fields_visibility(&self) -> FxHashMap<IStr, bool> {122 let mut out = FxHashMap::default();123 self.enum_fields(&mut |name, visibility| {124 match visibility {125 Visibility::Normal => {126 let entry = out.entry(name.to_owned());127 entry.or_insert(true);128 }129 Visibility::Hidden => {130 out.insert(name.to_owned(), false);131 }132 Visibility::Unhide => {133 out.insert(name.to_owned(), true);134 }135 };136 false137 });138 out139 }140 pub fn fields_ex(&self, include_hidden: bool) -> Vec<IStr> {141 let mut fields: Vec<_> = self142 .fields_visibility()143 .into_iter()144 .filter(|(_k, v)| include_hidden || *v)145 .map(|(k, _)| k)146 .collect();147 fields.sort_unstable();148 fields149 }150 pub fn fields(&self) -> Vec<IStr> {151 self.fields_ex(false)152 }153154 pub fn field_visibility(&self, name: IStr) -> Option<Visibility> {155 if let Some(m) = self.0.this_entries.get(&name) {156 Some(match &m.visibility {157 Visibility::Normal => self158 .0159 .super_obj160 .as_ref()161 .and_then(|super_obj| super_obj.field_visibility(name))162 .unwrap_or(Visibility::Normal),163 v => *v,164 })165 } else if let Some(super_obj) = &self.0.super_obj {166 super_obj.field_visibility(name)167 } else {168 None169 }170 }171172 fn has_field_include_hidden(&self, name: IStr) -> bool {173 if self.0.this_entries.contains_key(&name) {174 true175 } else if let Some(super_obj) = &self.0.super_obj {176 super_obj.has_field_include_hidden(name)177 } else {178 false179 }180 }181182 pub fn has_field_ex(&self, name: IStr, include_hidden: bool) -> bool {183 if include_hidden {184 self.has_field_include_hidden(name)185 } else {186 self.has_field(name)187 }188 }189 pub fn has_field(&self, name: IStr) -> bool {190 self.field_visibility(name)191 .map(|v| v.is_visible())192 .unwrap_or(false)193 }194195 pub fn get(&self, key: IStr) -> Result<Option<Val>> {196 self.run_assertions()?;197 self.get_raw(key, self.0.this_obj.as_ref())198 }199200 pub fn extend_with_field(self, key: IStr, value: ObjMember) -> Self {201 let mut new = FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());202 new.insert(key, value);203 Self::new(Some(self), Gc::new(new), Gc::new(Vec::new()))204 }205206 fn get_raw(&self, key: IStr, real_this: Option<&Self>) -> Result<Option<Val>> {207 let real_this = real_this.unwrap_or(self);208 let cache_key = (key.clone(), real_this.clone());209210 if let Some(v) = self.0.value_cache.borrow().get(&cache_key) {211 return Ok(v.clone());212 }213 let value = match (self.0.this_entries.get(&key), &self.0.super_obj) {214 (Some(k), None) => Ok(Some(self.evaluate_this(k, real_this)?)),215 (Some(k), Some(s)) => {216 let our = self.evaluate_this(k, real_this)?;217 if k.add {218 s.get_raw(key, Some(real_this))?219 .map_or(Ok(Some(our.clone())), |v| {220 Ok(Some(evaluate_add_op(&v, &our)?))221 })222 } else {223 Ok(Some(our))224 }225 }226 (None, Some(s)) => s.get_raw(key, Some(real_this)),227 (None, None) => Ok(None),228 }?;229 self.0230 .value_cache231 .borrow_mut()232 .insert(cache_key, value.clone());233 Ok(value)234 }235 fn evaluate_this(&self, v: &ObjMember, real_this: &Self) -> Result<Val> {236 v.invoke237 .evaluate(Some(real_this.clone()), self.0.super_obj.clone())?238 .evaluate()239 }240241 fn run_assertions_raw(&self, real_this: &Self) -> Result<()> {242 if self.0.assertions_ran.borrow_mut().insert(real_this.clone()) {243 for assertion in self.0.assertions.iter() {244 if let Err(e) = assertion.run(Some(real_this.clone()), self.0.super_obj.clone()) {245 self.0.assertions_ran.borrow_mut().remove(real_this);246 return Err(e);247 }248 }249 if let Some(super_obj) = &self.0.super_obj {250 super_obj.run_assertions_raw(real_this)?;251 }252 }253 Ok(())254 }255 pub fn run_assertions(&self) -> Result<()> {256 self.run_assertions_raw(self)257 }258259 pub fn ptr_eq(a: &Self, b: &Self) -> bool {260 Gc::ptr_eq(&a.0, &b.0)261 }262}263264impl PartialEq for ObjValue {265 fn eq(&self, other: &Self) -> bool {266 Gc::ptr_eq(&self.0, &other.0)267 }268}269270impl Eq for ObjValue {}271impl Hash for ObjValue {272 fn hash<H: Hasher>(&self, hasher: &mut H) {273 hasher.write_usize(&*self.0 as *const _ as usize)274 }275}