use qubit_budget::ResourceQuantity;
use qubit_budget::json::JsonValueTransaction;
use serde_json::Value;
use super::JsonTreeControl;
use super::JsonTreeMutVisitor;
use super::JsonTreeMutateError;
use super::JsonTreeReader;
use super::internal::MutFrame;
pub struct JsonTreeMutator<'input_transaction, 'input_budget, 'output_transaction, 'output_budget, R, Q>
where
Q: ResourceQuantity,
{
input: &'input_transaction mut JsonValueTransaction<'input_budget, R, Q>,
output: &'output_transaction mut JsonValueTransaction<'output_budget, R, Q>,
}
impl<'input_transaction, 'input_budget, 'output_transaction, 'output_budget, R, Q>
JsonTreeMutator<'input_transaction, 'input_budget, 'output_transaction, 'output_budget, R, Q>
where
R: Clone,
Q: ResourceQuantity,
{
#[inline(always)]
#[must_use]
pub fn new(
input: &'input_transaction mut JsonValueTransaction<'input_budget, R, Q>,
output: &'output_transaction mut JsonValueTransaction<'output_budget, R, Q>,
) -> Self {
Self { input, output }
}
pub fn process<V>(&mut self, root: &mut Value, visitor: &mut V) -> Result<(), JsonTreeMutateError<R, Q, V::Error>>
where
V: JsonTreeMutVisitor,
{
JsonTreeReader::new(&mut *self.input)
.account(root)
.map_err(JsonTreeMutateError::InputBudget)?;
Self::mutate(root, visitor).map_err(JsonTreeMutateError::Visitor)?;
JsonTreeReader::new(&mut *self.output)
.account(root)
.map_err(JsonTreeMutateError::OutputBudget)
}
fn mutate<V>(root: &mut Value, visitor: &mut V) -> Result<(), V::Error>
where
V: JsonTreeMutVisitor,
{
let mut stack = vec![MutFrame::root(root)];
while !stack.is_empty() {
let index = stack.len() - 1;
if !stack[index].entered {
let frame = &mut stack[index];
let context = frame.location.context(frame.depth);
let value = unsafe { frame.value.as_mut() };
let control = visitor.visit(value, context)?;
frame.entered = true;
if control != JsonTreeControl::Descend {
frame.finished = true;
}
continue;
}
if let Some(child) = stack[index].next_child() {
stack.push(child);
continue;
}
let _ = stack.pop().expect("mutable frame exists");
}
Ok(())
}
}