--- a/crates/jrsonnet-evaluator/Cargo.toml +++ b/crates/jrsonnet-evaluator/Cargo.toml @@ -15,9 +15,6 @@ # Allows library authors to throw custom errors anyhow-error = ["anyhow"] -# Unlocks extra features, but works only on unstable -unstable = [] - [dependencies] jrsonnet-interner = { path = "../jrsonnet-interner", version = "0.4.2" } jrsonnet-parser = { path = "../jrsonnet-parser", version = "0.4.2" } --- a/crates/jrsonnet-evaluator/src/ctx.rs +++ b/crates/jrsonnet-evaluator/src/ctx.rs @@ -133,10 +133,6 @@ } Ok(self.extend(new, new_dollar, this, super_obj)) } - #[cfg(feature = "unstable")] - pub fn into_weak(self) -> WeakContext { - WeakContext(Rc::downgrade(&self.0)) - } } impl Default for Context { --- a/crates/jrsonnet-evaluator/src/lib.rs +++ b/crates/jrsonnet-evaluator/src/lib.rs @@ -1,4 +1,3 @@ -#![cfg_attr(feature = "unstable", feature(stmt_expr_attributes))] #![warn(clippy::all, clippy::nursery)] #![allow( macro_expanded_macro_exports_accessed_by_absolute_paths, @@ -31,7 +30,7 @@ pub use evaluate::*; use function::{Builtin, TlaArg}; use gc::{GcHashMap, TraceBox}; -use gcmodule::{Cc, Trace}; +use gcmodule::{Cc, Trace, Weak}; pub use import::*; pub use jrsonnet_interner::IStr; use jrsonnet_parser::*; @@ -653,6 +652,28 @@ std::ptr::eq(a, b) } +fn weak_raw(a: Weak) -> *const () { + unsafe { std::mem::transmute(a) } +} +fn weak_ptr_eq(a: Weak, b: Weak) -> bool { + std::ptr::eq(weak_raw(a), weak_raw(b)) +} + +#[test] +fn weak_unsafe() { + let a = Cc::new(1); + let b = Cc::new(2); + + let aw1 = a.clone().downgrade(); + let aw2 = a.clone().downgrade(); + let aw3 = a.clone().downgrade(); + + let bw = b.clone().downgrade(); + + assert!(weak_ptr_eq(aw1, aw2)); + assert!(!weak_ptr_eq(aw3, bw)); +} + #[cfg(test)] pub mod tests { use super::Val; --- a/crates/jrsonnet-evaluator/src/obj.rs +++ b/crates/jrsonnet-evaluator/src/obj.rs @@ -1,7 +1,7 @@ use crate::gc::{GcHashMap, GcHashSet, TraceBox}; use crate::operator::evaluate_add_op; -use crate::{cc_ptr_eq, Bindable, LazyBinding, LazyVal, Result, Val}; -use gcmodule::{Cc, Trace}; +use crate::{cc_ptr_eq, weak_ptr_eq, weak_raw, Bindable, LazyBinding, LazyVal, Result, Val}; +use gcmodule::{Cc, Trace, Weak}; use jrsonnet_interner::IStr; use jrsonnet_parser::{ExprLocation, Visibility}; use rustc_hash::FxHashMap; @@ -22,7 +22,7 @@ } // Field => This -type CacheKey = (IStr, ObjValue); +type CacheKey = (IStr, WeakObjValue); #[derive(Trace)] #[force_tracking] pub struct ObjValueInternals { @@ -35,6 +35,22 @@ } #[derive(Clone, Trace)] +pub struct WeakObjValue(#[skip_trace] pub(crate) Weak); + +impl PartialEq for WeakObjValue { + fn eq(&self, other: &Self) -> bool { + weak_ptr_eq(self.0.clone(), other.0.clone()) + } +} + +impl Eq for WeakObjValue {} +impl Hash for WeakObjValue { + fn hash(&self, hasher: &mut H) { + hasher.write_usize(weak_raw(self.0.clone()) as usize) + } +} + +#[derive(Clone, Trace)] pub struct ObjValue(pub(crate) Cc); impl Debug for ObjValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -50,14 +66,7 @@ for (name, member) in self.0.this_entries.iter() { debug.field(name, member); } - #[cfg(feature = "unstable")] - { - debug.finish_non_exhaustive() - } - #[cfg(not(feature = "unstable"))] - { - debug.finish() - } + debug.finish_non_exhaustive() } } @@ -217,7 +226,7 @@ fn get_raw(&self, key: IStr, real_this: Option<&Self>) -> Result> { let real_this = real_this.unwrap_or(self); - let cache_key = (key.clone(), real_this.clone()); + let cache_key = (key.clone(), WeakObjValue(real_this.0.downgrade())); if let Some(v) = self.0.value_cache.borrow().get(&cache_key) { return Ok(v.clone());