difftreelog
refactor get rid of LazyBinding variants
in: master
5 files changed
crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth1use crate::{2 error::Error::*, map::LayeredHashMap, rc_fn_helper, resolved_lazy_val, FutureWrapper,3 LazyBinding, LazyVal, ObjValue, Result, Val,4};5use jrsonnet_interner::IStr;6use rustc_hash::FxHashMap;7use std::hash::BuildHasherDefault;8use std::{collections::HashMap, fmt::Debug, rc::Rc};910rc_fn_helper!(11 ContextCreator,12 context_creator,13 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Result<Context>14);1516struct ContextInternals {17 dollar: Option<ObjValue>,18 this: Option<ObjValue>,19 super_obj: Option<ObjValue>,20 bindings: LayeredHashMap<LazyVal>,21}22impl Debug for ContextInternals {23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {24 f.debug_struct("Context")25 .field("this", &self.this.as_ref().map(|e| Rc::as_ptr(&e.0)))26 .field("bindings", &self.bindings)27 .finish()28 }29}3031#[derive(Debug, Clone)]32pub struct Context(Rc<ContextInternals>);33impl Context {34 pub fn new_future() -> FutureWrapper<Context> {35 FutureWrapper::new()36 }3738 pub fn dollar(&self) -> &Option<ObjValue> {39 &self.0.dollar40 }4142 pub fn this(&self) -> &Option<ObjValue> {43 &self.0.this44 }4546 pub fn super_obj(&self) -> &Option<ObjValue> {47 &self.0.super_obj48 }4950 pub fn new() -> Self {51 Self(Rc::new(ContextInternals {52 dollar: None,53 this: None,54 super_obj: None,55 bindings: LayeredHashMap::default(),56 }))57 }5859 pub fn binding(&self, name: IStr) -> Result<LazyVal> {60 Ok(self61 .062 .bindings63 .get(&name)64 .cloned()65 .ok_or(VariableIsNotDefined(name))?)66 }67 pub fn into_future(self, ctx: FutureWrapper<Context>) -> Self {68 {69 ctx.0.borrow_mut().replace(self);70 }71 ctx.unwrap()72 }7374 pub fn with_var(self, name: IStr, value: Val) -> Self {75 let mut new_bindings =76 FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());77 new_bindings.insert(name, resolved_lazy_val!(value));78 self.extend(new_bindings, None, None, None)79 }8081 pub fn extend(82 self,83 new_bindings: FxHashMap<IStr, LazyVal>,84 new_dollar: Option<ObjValue>,85 new_this: Option<ObjValue>,86 new_super_obj: Option<ObjValue>,87 ) -> Self {88 match Rc::try_unwrap(self.0) {89 Ok(mut ctx) => {90 // Extended context aren't used by anything else, we can freely mutate it without cloning91 if let Some(dollar) = new_dollar {92 ctx.dollar = Some(dollar);93 }94 if let Some(this) = new_this {95 ctx.this = Some(this);96 }97 if let Some(super_obj) = new_super_obj {98 ctx.super_obj = Some(super_obj);99 }100 if !new_bindings.is_empty() {101 ctx.bindings = ctx.bindings.extend(new_bindings);102 }103 Self(Rc::new(ctx))104 }105 Err(ctx) => {106 let dollar = new_dollar.or_else(|| ctx.dollar.clone());107 let this = new_this.or_else(|| ctx.this.clone());108 let super_obj = new_super_obj.or_else(|| ctx.super_obj.clone());109 let bindings = if new_bindings.is_empty() {110 ctx.bindings.clone()111 } else {112 ctx.bindings.clone().extend(new_bindings)113 };114 Self(Rc::new(ContextInternals {115 dollar,116 this,117 super_obj,118 bindings,119 }))120 }121 }122 }123 pub fn extend_unbound(124 self,125 new_bindings: HashMap<IStr, LazyBinding>,126 new_dollar: Option<ObjValue>,127 new_this: Option<ObjValue>,128 new_super_obj: Option<ObjValue>,129 ) -> Result<Self> {130 let this = new_this.or_else(|| self.0.this.clone());131 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());132 let mut new =133 FxHashMap::with_capacity_and_hasher(new_bindings.len(), BuildHasherDefault::default());134 for (k, v) in new_bindings.into_iter() {135 new.insert(k, v.evaluate(this.clone(), super_obj.clone())?);136 }137 Ok(self.extend(new, new_dollar, this, super_obj))138 }139 #[cfg(feature = "unstable")]140 pub fn into_weak(self) -> WeakContext {141 WeakContext(Rc::downgrade(&self.0))142 }143}144145impl Default for Context {146 fn default() -> Self {147 Self::new()148 }149}150151impl PartialEq for Context {152 fn eq(&self, other: &Self) -> bool {153 Rc::ptr_eq(&self.0, &other.0)154 }155}156157#[cfg(feature = "unstable")]158#[derive(Debug, Clone)]159pub struct WeakContext(std::rc::Weak<ContextInternals>);160#[cfg(feature = "unstable")]161impl WeakContext {162 pub fn upgrade(&self) -> Context {163 Context(self.0.upgrade().expect("context is removed"))164 }165}166#[cfg(feature = "unstable")]167impl PartialEq for WeakContext {168 fn eq(&self, other: &Self) -> bool {169 self.0.ptr_eq(&other.0)170 }171}1use crate::{2 error::Error::*, map::LayeredHashMap, resolved_lazy_val, FutureWrapper, LazyBinding, LazyVal,3 ObjValue, Result, Val,4};5use jrsonnet_interner::IStr;6use rustc_hash::FxHashMap;7use std::hash::BuildHasherDefault;8use std::{fmt::Debug, rc::Rc};910#[derive(Clone)]11pub struct ContextCreator(pub Context, pub FutureWrapper<FxHashMap<IStr, LazyBinding>>);12impl ContextCreator {13 pub fn create(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<Context> {14 self.0.clone().extend_unbound(15 self.1.clone().unwrap(),16 self.0.dollar().clone().or_else(|| this.clone()),17 this,18 super_obj,19 )20 }21}2223struct ContextInternals {24 dollar: Option<ObjValue>,25 this: Option<ObjValue>,26 super_obj: Option<ObjValue>,27 bindings: LayeredHashMap<LazyVal>,28}29impl Debug for ContextInternals {30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {31 f.debug_struct("Context")32 .field("this", &self.this.as_ref().map(|e| Rc::as_ptr(&e.0)))33 .field("bindings", &self.bindings)34 .finish()35 }36}3738#[derive(Debug, Clone)]39pub struct Context(Rc<ContextInternals>);40impl Context {41 pub fn new_future() -> FutureWrapper<Context> {42 FutureWrapper::new()43 }4445 pub fn dollar(&self) -> &Option<ObjValue> {46 &self.0.dollar47 }4849 pub fn this(&self) -> &Option<ObjValue> {50 &self.0.this51 }5253 pub fn super_obj(&self) -> &Option<ObjValue> {54 &self.0.super_obj55 }5657 pub fn new() -> Self {58 Self(Rc::new(ContextInternals {59 dollar: None,60 this: None,61 super_obj: None,62 bindings: LayeredHashMap::default(),63 }))64 }6566 pub fn binding(&self, name: IStr) -> Result<LazyVal> {67 Ok(self68 .069 .bindings70 .get(&name)71 .cloned()72 .ok_or(VariableIsNotDefined(name))?)73 }74 pub fn into_future(self, ctx: FutureWrapper<Context>) -> Self {75 {76 ctx.0.borrow_mut().replace(self);77 }78 ctx.unwrap()79 }8081 pub fn with_var(self, name: IStr, value: Val) -> Self {82 let mut new_bindings =83 FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());84 new_bindings.insert(name, resolved_lazy_val!(value));85 self.extend(new_bindings, None, None, None)86 }8788 pub fn extend(89 self,90 new_bindings: FxHashMap<IStr, LazyVal>,91 new_dollar: Option<ObjValue>,92 new_this: Option<ObjValue>,93 new_super_obj: Option<ObjValue>,94 ) -> Self {95 match Rc::try_unwrap(self.0) {96 Ok(mut ctx) => {97 // Extended context aren't used by anything else, we can freely mutate it without cloning98 if let Some(dollar) = new_dollar {99 ctx.dollar = Some(dollar);100 }101 if let Some(this) = new_this {102 ctx.this = Some(this);103 }104 if let Some(super_obj) = new_super_obj {105 ctx.super_obj = Some(super_obj);106 }107 if !new_bindings.is_empty() {108 ctx.bindings = ctx.bindings.extend(new_bindings);109 }110 Self(Rc::new(ctx))111 }112 Err(ctx) => {113 let dollar = new_dollar.or_else(|| ctx.dollar.clone());114 let this = new_this.or_else(|| ctx.this.clone());115 let super_obj = new_super_obj.or_else(|| ctx.super_obj.clone());116 let bindings = if new_bindings.is_empty() {117 ctx.bindings.clone()118 } else {119 ctx.bindings.clone().extend(new_bindings)120 };121 Self(Rc::new(ContextInternals {122 dollar,123 this,124 super_obj,125 bindings,126 }))127 }128 }129 }130 pub fn extend_bound(self, new_bindings: FxHashMap<IStr, LazyVal>) -> Self {131 let new_this = self.0.this.clone();132 let new_super_obj = self.0.super_obj.clone();133 self.extend(new_bindings, None, new_this, new_super_obj)134 }135 pub fn extend_unbound(136 self,137 new_bindings: FxHashMap<IStr, LazyBinding>,138 new_dollar: Option<ObjValue>,139 new_this: Option<ObjValue>,140 new_super_obj: Option<ObjValue>,141 ) -> Result<Self> {142 let this = new_this.or_else(|| self.0.this.clone());143 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());144 let mut new =145 FxHashMap::with_capacity_and_hasher(new_bindings.len(), BuildHasherDefault::default());146 for (k, v) in new_bindings.into_iter() {147 new.insert(k, v.evaluate(this.clone(), super_obj.clone())?);148 }149 Ok(self.extend(new, new_dollar, this, super_obj))150 }151 #[cfg(feature = "unstable")]152 pub fn into_weak(self) -> WeakContext {153 WeakContext(Rc::downgrade(&self.0))154 }155}156157impl Default for Context {158 fn default() -> Self {159 Self::new()160 }161}162163impl PartialEq for Context {164 fn eq(&self, other: &Self) -> bool {165 Rc::ptr_eq(&self.0, &other.0)166 }167}168169#[cfg(feature = "unstable")]170#[derive(Debug, Clone)]171pub struct WeakContext(std::rc::Weak<ContextInternals>);172#[cfg(feature = "unstable")]173impl WeakContext {174 pub fn upgrade(&self) -> Context {175 Context(self.0.upgrade().expect("context is removed"))176 }177}178#[cfg(feature = "unstable")]179impl PartialEq for WeakContext {180 fn eq(&self, other: &Self) -> bool {181 self.0.ptr_eq(&other.0)182 }183}crates/jrsonnet-evaluator/src/dynamic.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/dynamic.rs
+++ b/crates/jrsonnet-evaluator/src/dynamic.rs
@@ -12,7 +12,7 @@
}
}
impl<T: Clone> FutureWrapper<T> {
- pub fn unwrap(self) -> T {
+ pub fn unwrap(&self) -> T {
self.0.borrow().as_ref().cloned().unwrap()
}
}
@@ -21,30 +21,4 @@
fn default() -> Self {
Self::new()
}
-}
-
-#[macro_export]
-macro_rules! rc_fn_helper {
- ($name: ident, $macro_name: ident, $fn: ty) => {
- #[derive(Clone)]
- #[doc = "Function wrapper"]
- pub struct $name(pub std::rc::Rc<$fn>);
- impl std::fmt::Debug for $name {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_struct(std::stringify!($name)).finish()
- }
- }
- impl std::cmp::PartialEq for $name {
- fn eq(&self, other: &$name) -> bool {
- std::ptr::eq(&self.0, &other.0)
- }
- }
- #[doc = "Macro to ease wrapper creation"]
- #[macro_export]
- macro_rules! $macro_name {
- ($val: expr) => {
- $crate::$name(std::rc::Rc::new($val))
- };
- }
- };
}
crates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate.rs
@@ -1,6 +1,6 @@
use crate::{
- context_creator, error::Error::*, lazy_val, push, throw, with_state, Context, ContextCreator,
- FuncDesc, FuncVal, FutureWrapper, LazyBinding, LazyVal, ObjMember, ObjValue, Result, Val,
+ error::Error::*, lazy_val, push, throw, with_state, Context, ContextCreator, FuncDesc, FuncVal,
+ FutureWrapper, LazyBinding, LazyVal, ObjMember, ObjValue, Result, Val,
};
use closure::closure;
use jrsonnet_interner::IStr;
@@ -10,8 +10,30 @@
Visibility,
};
use jrsonnet_types::ValType;
-use rustc_hash::FxHashMap;
-use std::{collections::HashMap, rc::Rc};
+use rustc_hash::{FxHashMap, FxHasher};
+use std::{collections::HashMap, hash::BuildHasherDefault, rc::Rc};
+
+pub fn evaluate_binding_in_future(
+ b: &BindSpec,
+ context_creator: FutureWrapper<Context>,
+) -> LazyVal {
+ let b = b.clone();
+ if let Some(params) = &b.params {
+ let params = params.clone();
+ LazyVal::new(Box::new(move || {
+ Ok(evaluate_method(
+ context_creator.unwrap(),
+ b.name.clone(),
+ params.clone(),
+ b.value.clone(),
+ ))
+ }))
+ } else {
+ LazyVal::new(Box::new(move || {
+ evaluate_named(context_creator.unwrap(), &b.value, b.name.clone())
+ }))
+ }
+}
pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (IStr, LazyBinding) {
let b = b.clone();
@@ -22,7 +44,7 @@
LazyBinding::Bindable(Rc::new(move |this, super_obj| {
Ok(lazy_val!(
closure!(clone b, clone params, clone context_creator, || Ok(evaluate_method(
- context_creator.0(this.clone(), super_obj.clone())?,
+ context_creator.create(this.clone(), super_obj.clone())?,
b.name.clone(),
params.clone(),
b.value.clone(),
@@ -35,11 +57,11 @@
b.name.clone(),
LazyBinding::Bindable(Rc::new(move |this, super_obj| {
Ok(lazy_val!(closure!(clone context_creator, clone b, ||
- evaluate_named(
- context_creator.0(this.clone(), super_obj.clone())?,
- &b.value,
- b.name.clone()
- )
+ evaluate_named(
+ context_creator.create(this.clone(), super_obj.clone())?,
+ &b.value,
+ b.name.clone()
+ )
)))
})),
)
@@ -217,18 +239,10 @@
pub fn evaluate_member_list_object(context: Context, members: &[Member]) -> Result<ObjValue> {
let new_bindings = FutureWrapper::new();
let future_this = FutureWrapper::new();
- let context_creator = context_creator!(
- closure!(clone context, clone new_bindings, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {
- context.clone().extend_unbound(
- new_bindings.clone().unwrap(),
- context.dollar().clone().or_else(||this.clone()),
- Some(this.unwrap()),
- super_obj
- )
- })
- );
+ let context_creator = ContextCreator(context.clone(), new_bindings.clone());
{
- let mut bindings: HashMap<IStr, LazyBinding> = HashMap::new();
+ let mut bindings: FxHashMap<IStr, LazyBinding> =
+ FxHashMap::with_capacity_and_hasher(members.len(), BuildHasherDefault::default());
for (n, b) in members
.iter()
.filter_map(|m| match m {
@@ -265,7 +279,7 @@
invoke: LazyBinding::Bindable(Rc::new(
closure!(clone name, clone value, clone context_creator, |this, super_obj| {
Ok(LazyVal::new_resolved(evaluate(
- context_creator.0(this, super_obj)?,
+ context_creator.create(this, super_obj)?,
&value,
)?))
}),
@@ -294,7 +308,7 @@
closure!(clone value, clone context_creator, clone params, clone name, |this, super_obj| {
// TODO: Assert
Ok(LazyVal::new_resolved(evaluate_method(
- context_creator.0(this, super_obj)?,
+ context_creator.create(this, super_obj)?,
name.clone(),
params.clone(),
value.clone(),
@@ -324,17 +338,8 @@
context.clone(),
&|ctx| {
let new_bindings = FutureWrapper::new();
- let context_creator = context_creator!(
- closure!(clone context, clone new_bindings, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {
- context.clone().extend_unbound(
- new_bindings.clone().unwrap(),
- context.dollar().clone().or_else(||this.clone()),
- None,
- super_obj
- )
- })
- );
- let mut bindings: HashMap<IStr, LazyBinding> = HashMap::new();
+ let context_creator = ContextCreator(context.clone(), new_bindings.clone());
+ let mut bindings: FxHashMap<IStr, LazyBinding> = FxHashMap::with_capacity_and_hasher(obj.pre_locals.len() + obj.post_locals.len(), BuildHasherDefault::default());
for (n, b) in obj
.pre_locals
.iter()
@@ -497,22 +502,19 @@
}
}
LocalExpr(bindings, returned) => {
- let mut new_bindings: HashMap<IStr, LazyBinding> = HashMap::new();
+ let mut new_bindings: FxHashMap<IStr, LazyVal> = HashMap::with_capacity_and_hasher(
+ bindings.len(),
+ BuildHasherDefault::<FxHasher>::default(),
+ );
let future_context = Context::new_future();
-
- let context_creator = context_creator!(
- closure!(clone future_context, |_, _| Ok(future_context.clone().unwrap()))
- );
-
- for (k, v) in bindings
- .iter()
- .map(|b| evaluate_binding(b, context_creator.clone()))
- {
- new_bindings.insert(k, v);
+ for b in bindings {
+ new_bindings.insert(
+ b.name.clone(),
+ evaluate_binding_in_future(b, future_context.clone()),
+ );
}
-
let context = context
- .extend_unbound(new_bindings, None, None, None)?
+ .extend_bound(new_bindings)
.into_future(future_context);
evaluate(context, &returned.clone())?
}
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -27,10 +27,12 @@
use jrsonnet_parser::*;
use native::NativeCallback;
pub use obj::*;
+use rustc_hash::FxHashMap;
use std::{
cell::{Ref, RefCell, RefMut},
collections::HashMap,
fmt::Debug,
+ hash::BuildHasherDefault,
path::PathBuf,
rc::Rc,
};
@@ -230,7 +232,7 @@
}
value.parsed.clone()
};
- let value = evaluate(self.create_default_context()?, &expr)?;
+ let value = evaluate(self.create_default_context(), &expr)?;
{
self.data_mut()
.files
@@ -260,16 +262,14 @@
}
/// Creates context with all passed global variables
- pub fn create_default_context(&self) -> Result<Context> {
+ pub fn create_default_context(&self) -> Context {
let globals = &self.settings().globals;
- let mut new_bindings: HashMap<IStr, LazyBinding> = HashMap::new();
+ let mut new_bindings: FxHashMap<IStr, LazyVal> =
+ FxHashMap::with_capacity_and_hasher(globals.len(), BuildHasherDefault::default());
for (name, value) in globals.iter() {
- new_bindings.insert(
- name.clone(),
- LazyBinding::Bound(resolved_lazy_val!(value.clone())),
- );
+ new_bindings.insert(name.clone(), resolved_lazy_val!(value.clone()));
}
- Context::new().extend_unbound(new_bindings, None, None, None)
+ Context::new().extend_bound(new_bindings)
}
/// Executes code creating a new stack frame
@@ -345,7 +345,7 @@
|| "during TLA call".to_owned(),
|| {
func.evaluate_map(
- self.create_default_context()?,
+ self.create_default_context(),
&self.settings().tla_vars,
true,
)
@@ -396,7 +396,7 @@
}
/// Evaluates the parsed expression
pub fn evaluate_expr_raw(&self, code: LocExpr) -> Result<Val> {
- self.run_in_state(|| evaluate(self.create_default_context()?, &code))
+ self.run_in_state(|| evaluate(self.create_default_context(), &code))
}
}
@@ -950,6 +950,23 @@
Ok(())
}
+ #[test]
+ fn comp_self() -> crate::error::Result<()> {
+ assert_eval!(
+ r#"
+ std.objectFields({
+ a:{
+ [name]: name for name in std.objectFields(self)
+ },
+ b: 2,
+ c: 3,
+ }.a) == ['a', 'b', 'c']
+ "#
+ );
+
+ Ok(())
+ }
+
struct TestImportResolver(IStr);
impl crate::import::ImportResolver for TestImportResolver {
fn resolve_file(&self, _: &PathBuf, _: &PathBuf) -> crate::error::Result<Rc<PathBuf>> {
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -535,7 +535,7 @@
pub fn to_yaml(&self, padding: usize) -> Result<IStr> {
with_state(|s| {
let ctx = s
- .create_default_context()?
+ .create_default_context()
.with_var("__tmp__to_json__".into(), self.clone());
evaluate(
ctx,