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
+2 -3
View File
@@ -4,7 +4,6 @@
use crate::rvm::instructions::{GuardMode, Instruction, LiteralOrRegister};
use crate::rvm::program::Program;
use crate::value::Value;
use alloc::collections::BTreeSet;
use alloc::vec::Vec;
use core::mem;
@@ -670,7 +669,7 @@ impl RegoVM {
}
}
SetNew { dest } => {
let empty_set = Value::Set(crate::Rc::new(BTreeSet::new()));
let empty_set = Value::new_set();
self.set_register(dest, empty_set)?;
Ok(InstructionOutcome::Continue)
}
@@ -707,7 +706,7 @@ impl RegoVM {
if any_undefined {
self.set_register(params.dest, Value::Undefined)?;
} else {
let mut set = BTreeSet::new();
let mut set = alloc::collections::BTreeSet::new();
for &reg in params.element_registers() {
set.insert(self.get_register(reg)?.clone());
}