refactor(value): migrate Value::Object to Object storage abstraction (#736)

Builds on #57. Swap Value::Object's payload from Rc<BTreeMap<Value, Value>>
to Rc<Object> and migrate all call sites to the Object API.

as_object / as_object_mut keep their names but return &Object / &mut Object.
The mutable accessor handles Rc::make_mut internally, so callers no longer
do it themselves. Object grows into_value() and From<Object> for Value.
Value's serializer now delegates to Object::serialize, dropping a duplicate
non-string-key stringification path.

RVM IterationState::Object is rewritten around ObjectCursor: O(log n)
steps over a shared Rc<Object>, no eager pair snapshot. Snapshot
independence is preserved by Rc copy-on-write; setup_next_iteration
advances the cursor inline and advance() becomes a no-op for this variant.
A new iteration_state_object_is_snapshot_independent_of_source test
covers CoW against a mutated alias.

Value::Set still wraps Rc<BTreeSet<Value>>; the matching Set abstraction
and its swap ship in follow-up PRs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Anand Krishnamoorthi
2026-06-05 18:04:37 -05:00
committed by GitHub
parent bd90453dd3
commit ed6ae465b0
30 changed files with 439 additions and 372 deletions
@@ -11,8 +11,9 @@ use crate::ast::{Expr, ExprRef};
use crate::lexer::Span;
use crate::rvm::instructions::{ArrayCreateParams, ObjectCreateParams, SetCreateParams};
use crate::rvm::Instruction;
use crate::value::Object;
use crate::{Rc, Value};
use alloc::collections::{BTreeMap, BTreeSet};
use alloc::collections::BTreeSet;
use alloc::vec::Vec;
/// Try to evaluate an expression as a compile-time constant.
@@ -43,7 +44,7 @@ pub(in crate::languages::rego::compiler) fn try_eval_const(expr: &Expr) -> Optio
Expr::Object { fields, .. } => fields
.iter()
.map(|(_, k, v)| Some((try_eval_const(k.as_ref())?, try_eval_const(v.as_ref())?)))
.collect::<Option<BTreeMap<_, _>>>()
.collect::<Option<Object>>()
.map(|m| Value::Object(Rc::new(m))),
_ => None,
}
@@ -117,7 +118,7 @@ impl<'a> Compiler<'a> {
fields: &[(crate::lexer::Span, ExprRef, ExprRef)],
span: &Span,
) -> Result<Register> {
let all_const: Option<BTreeMap<_, _>> = fields
let all_const: Option<Object> = fields
.iter()
.map(|(_, k, v)| Some((try_eval_const(k.as_ref())?, try_eval_const(v.as_ref())?)))
.collect();
@@ -166,7 +167,7 @@ impl<'a> Compiler<'a> {
let mut template_keys = literal_keys.clone();
template_keys.sort();
let mut template_obj = BTreeMap::new();
let mut template_obj = Object::new();
for key in &template_keys {
template_obj.insert(key.clone(), Value::Undefined);
}