From 1c69f1ac7855b1b93d1a67a9fe2b5bba417ce3a4 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Sat, 07 Feb 2026 23:46:26 +0000 Subject: [PATCH] refactor: move state to global --- --- a/bindings/jsonnet/src/lib.rs +++ b/bindings/jsonnet/src/lib.rs @@ -247,7 +247,7 @@ match vm .state .import(filename) - .and_then(|val| apply_tla(vm.state.clone(), &vm.tla_args, val)) + .and_then(|val| apply_tla(&vm.tla_args, val)) .and_then(|val| val.manifest(&vm.manifest_format)) { Ok(v) => { @@ -282,7 +282,7 @@ match vm .state .evaluate_snippet(filename.to_str().unwrap(), snippet.to_str().unwrap()) - .and_then(|val| apply_tla(vm.state.clone(), &vm.tla_args, val)) + .and_then(|val| apply_tla(&vm.tla_args, val)) .and_then(|val| val.manifest(&vm.manifest_format)) { Ok(v) => { @@ -340,7 +340,7 @@ match vm .state .import(filename) - .and_then(|val| apply_tla(vm.state.clone(), &vm.tla_args, val)) + .and_then(|val| apply_tla(&vm.tla_args, val)) .and_then(|val| val_to_multi(val, &vm.manifest_format)) { Ok(v) => { @@ -369,7 +369,7 @@ match vm .state .evaluate_snippet(filename.to_str().unwrap(), snippet.to_str().unwrap()) - .and_then(|val| apply_tla(vm.state.clone(), &vm.tla_args, val)) + .and_then(|val| apply_tla(&vm.tla_args, val)) .and_then(|val| val_to_multi(val, &vm.manifest_format)) { Ok(v) => { @@ -422,7 +422,7 @@ match vm .state .import(filename) - .and_then(|val| apply_tla(vm.state.clone(), &vm.tla_args, val)) + .and_then(|val| apply_tla(&vm.tla_args, val)) .and_then(|val| val_to_stream(val, &vm.manifest_format)) { Ok(v) => { @@ -451,7 +451,7 @@ match vm .state .evaluate_snippet(filename.to_str().unwrap(), snippet.to_str().unwrap()) - .and_then(|val| apply_tla(vm.state.clone(), &vm.tla_args, val)) + .and_then(|val| apply_tla(&vm.tla_args, val)) .and_then(|val| val_to_stream(val, &vm.manifest_format)) { Ok(v) => { --- a/cmds/jrsonnet/src/main.rs +++ b/cmds/jrsonnet/src/main.rs @@ -173,6 +173,7 @@ let mut s = State::builder(); s.import_resolver(import_resolver).context_initializer(std); let s = s.build(); + let _s = s.enter(); let input = opts.input.input.ok_or(Error::MissingInputArgument)?; let val = if opts.input.exec { @@ -192,7 +193,7 @@ unused_mut, clippy::redundant_clone, )] - let mut val = apply_tla(s.clone(), &tla, val)?; + let mut val = apply_tla(&tla, val)?; #[cfg(feature = "exp-apply")] for apply in opts.input.exp_apply { --- a/crates/jrsonnet-evaluator/src/ctx.rs +++ b/crates/jrsonnet-evaluator/src/ctx.rs @@ -6,12 +6,11 @@ use crate::{ error::ErrorKind::*, gc::WithCapacityExt as _, map::LayeredHashMap, ObjValue, Pending, Result, - State, Thunk, Val, + Thunk, Val, }; #[derive(Trace)] struct ContextInternals { - state: Option, dollar: Option, sup: Option, this: Option, @@ -33,13 +32,6 @@ Pending::new() } - pub fn state(&self) -> &State { - self.0 - .state - .as_ref() - .expect("used state from dummy context") - } - pub fn dollar(&self) -> Option<&ObjValue> { self.0.dollar.as_ref() } @@ -112,7 +104,6 @@ ctx.bindings.clone().extend(new_bindings) }; Self(Cc::new(ContextInternals { - state: ctx.state.clone(), dollar, sup, this, @@ -128,34 +119,22 @@ } pub struct ContextBuilder { - state: Option, bindings: FxHashMap>, extend: Option, } impl ContextBuilder { - /// # Panics - /// Panics aren't directly caused by this function, but if state from resulting context is used - pub fn dangerous_empty_state() -> Self { - Self { - state: None, - bindings: FxHashMap::new(), - extend: None, - } + pub fn new() -> Self { + Self::with_capacity(0) } - pub fn new(state: State) -> Self { - Self::with_capacity(state, 0) - } - pub fn with_capacity(state: State, capacity: usize) -> Self { + pub fn with_capacity(capacity: usize) -> Self { Self { - state: Some(state), bindings: FxHashMap::with_capacity(capacity), extend: None, } } pub fn extend(parent: Context) -> Self { Self { - state: parent.0.state.clone(), bindings: FxHashMap::new(), extend: Some(parent), } @@ -173,7 +152,6 @@ parent.extend(self.bindings, None, None, None) } else { Context(Cc::new(ContextInternals { - state: self.state, bindings: LayeredHashMap::new(self.bindings), dollar: None, sup: None, --- a/crates/jrsonnet-evaluator/src/function/arglike.rs +++ b/crates/jrsonnet-evaluator/src/function/arglike.rs @@ -4,7 +4,7 @@ use jrsonnet_interner::IStr; use jrsonnet_parser::{ArgsDesc, LocExpr, SourceFifo, SourcePath}; -use crate::{evaluate, typed::Typed, Context, Result, Thunk, Val}; +use crate::{evaluate, typed::Typed, with_state, Context, Result, Thunk, Val}; /// Marker for arguments, which can be evaluated with context set to None pub trait OptionalContext {} @@ -47,28 +47,59 @@ ImportStr(String), InlineCode(String), } -impl ArgLike for TlaArg { - fn evaluate_arg(&self, ctx: Context, _tailstrict: bool) -> Result> { +impl TlaArg { + pub fn evaluate_tailstrict(&self) -> Result { match self { + Self::String(s) => Ok(Val::string(s.clone())), + Self::Val(val) => Ok(val.clone()), + Self::Lazy(lazy) => Ok(lazy.evaluate()?), + Self::Import(p) => with_state(|s| { + let resolved = s.resolve_from_default(&p.as_str())?; + s.import_resolved(resolved) + }), + Self::ImportStr(p) => with_state(|s| { + let resolved = s.resolve_from_default(&p.as_str())?; + s.import_resolved_str(resolved).map(Val::string) + }), + Self::InlineCode(p) => with_state(|s| { + let resolved = + SourcePath::new(SourceFifo("".to_owned(), p.as_bytes().into())); + s.import_resolved(resolved) + }), + } + } + pub fn evaluate(&self) -> Result> { + match self { Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))), Self::Val(val) => Ok(Thunk::evaluated(val.clone())), Self::Lazy(lazy) => Ok(lazy.clone()), - Self::Import(p) => { - let resolved = ctx.state().resolve_from_default(&p.as_str())?; - Ok(Thunk!(move || ctx.state().import_resolved(resolved))) - } - Self::ImportStr(p) => { - let resolved = ctx.state().resolve_from_default(&p.as_str())?; - Ok(Thunk!(move || ctx - .state() + Self::Import(p) => with_state(|s| { + let resolved = s.resolve_from_default(&p.as_str())?; + Ok(Thunk!(move || s.import_resolved(resolved))) + }), + Self::ImportStr(p) => with_state(|s| { + let resolved = s.resolve_from_default(&p.as_str())?; + Ok(Thunk!(move || s .import_resolved_str(resolved) .map(Val::string))) - } - Self::InlineCode(p) => { + }), + Self::InlineCode(p) => with_state(|s| { let resolved = SourcePath::new(SourceFifo("".to_owned(), p.as_bytes().into())); - Ok(Thunk!(move || ctx.state().import_resolved(resolved))) - } + Ok(Thunk!(move || s.import_resolved(resolved))) + }), + } + } +} + +// TODO: Is this implementation really required, as there is no Context to use? +// Maybe something a bit stricter is possible to add, especially with precompiled calls? +impl ArgLike for TlaArg { + fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result> { + if tailstrict { + self.evaluate_tailstrict().map(Thunk::evaluated) + } else { + self.evaluate() } } } --- a/crates/jrsonnet-evaluator/src/function/mod.rs +++ b/crates/jrsonnet-evaluator/src/function/mod.rs @@ -207,7 +207,7 @@ tailstrict: bool, ) -> Result { self.evaluate( - ContextBuilder::dangerous_empty_state().build(), + ContextBuilder::new().build(), CallLocation::native(), args, tailstrict, --- a/crates/jrsonnet-evaluator/src/tla.rs +++ b/crates/jrsonnet-evaluator/src/tla.rs @@ -1,21 +1,24 @@ use jrsonnet_interner::IStr; use jrsonnet_parser::Source; +use rustc_hash::FxHashMap; use crate::{ - function::{ArgsLike, CallLocation}, - in_description_frame, Result, State, Val, + function::{CallLocation, TlaArg}, + in_description_frame, with_state, Result, Val, }; -pub fn apply_tla(s: State, args: &A, val: Val) -> Result { +pub fn apply_tla(args: &FxHashMap, val: Val) -> Result { Ok(if let Val::Func(func) = val { in_description_frame( || "during TLA call".to_owned(), || { func.evaluate( - s.create_default_context(Source::new_virtual( - "".into(), - IStr::empty(), - )), + with_state(|s| { + s.create_default_context(Source::new_virtual( + "".into(), + IStr::empty(), + )) + }), CallLocation::native(), args, false, --- a/crates/jrsonnet-stdlib/src/lib.rs +++ b/crates/jrsonnet-stdlib/src/lib.rs @@ -335,11 +335,6 @@ pub path_resolver: PathResolver, } -fn extvar_source(name: &str, code: impl Into) -> Source { - let source_name = format!(""); - Source::new_virtual(source_name.into(), code.into()) -} - #[derive(Trace, Clone)] pub struct ContextInitializer { /// std without applied thisFile overlay --- a/crates/jrsonnet-stdlib/src/misc.rs +++ b/crates/jrsonnet-stdlib/src/misc.rs @@ -3,15 +3,15 @@ use jrsonnet_evaluator::{ bail, error::{ErrorKind::*, Result}, - function::{builtin, ArgLike, CallLocation, FuncVal}, + function::{builtin, CallLocation, FuncVal}, manifest::JsonFormat, typed::{Either2, Either4}, val::{equals, ArrValue}, - Context, Either, IStr, ObjValue, ObjValueBuilder, ResultExt, Thunk, Val, + Either, IStr, ObjValue, ObjValueBuilder, ResultExt, Thunk, Val, }; use jrsonnet_gcmodule::Cc; -use crate::{extvar_source, Settings}; +use crate::Settings; #[builtin] pub fn builtin_length(x: Either![IStr, ArrValue, ObjValue, FuncVal]) -> usize { @@ -50,16 +50,14 @@ #[builtin(fields( settings: Cc>, ))] -pub fn builtin_ext_var(this: &builtin_ext_var, ctx: Context, x: IStr) -> Result { - let ctx = ctx.state().create_default_context(extvar_source(&x, "")); +pub fn builtin_ext_var(this: &builtin_ext_var, x: IStr) -> Result { this.settings .borrow() .ext_vars .get(&x) .cloned() .ok_or_else(|| UndefinedExternalVariable(x))? - .evaluate_arg(ctx, true)? - .evaluate() + .evaluate_tailstrict() } #[builtin(fields( --- a/tests/tests/builtin.rs +++ b/tests/tests/builtin.rs @@ -19,7 +19,7 @@ fn basic_function() -> Result<()> { let a: a = a {}; let v = u32::from_untyped(a.call( - ContextBuilder::dangerous_empty_state().build(), + ContextBuilder::new().build(), CallLocation::native(), &(), )?)?; -- gitstuff