use serde_json::Value;
use super::ledger::{self, FLOOR};
use super::{ADVERTISED, QUEUED, REFUSAL, ROUTED};
pub(crate) const REPLIES: [(&str, &[&str]); 4] = [
("reply/advertised", &ADVERTISED),
("reply/invocations", &QUEUED),
("reply/routed", &ROUTED),
("reply/refusal", &[REFUSAL]),
];
pub(crate) fn editions() -> Vec<u32> {
(FLOOR..=FLOOR.max(ledger::edition())).collect()
}
pub(crate) fn project(frame: &Value, signature: &[(&'static str, u32)], edition: u32) -> Value {
let mut projected = frame.clone();
for &(entry, since) in signature {
if since > edition {
drop_at(&mut projected, &segments(ledger::path_of(entry)));
}
}
projected
}
pub(crate) fn reword(frame: &Value, path: &str, word: &str) -> Option<Value> {
let mut reworded = frame.clone();
set_at(&mut reworded, &segments(path), word).then_some(reworded)
}
fn segments(path: &str) -> Vec<&str> {
path.split('/').filter(|step| !step.is_empty()).collect()
}
fn drop_at(v: &mut Value, steps: &[&str]) {
let Some((head, rest)) = steps.split_first() else {
return;
};
if *head == "[]" {
if let Value::Array(rows) = v {
for row in rows {
drop_at(row, rest);
}
}
return;
}
let Value::Object(o) = v else {
return;
};
if rest.is_empty() {
o.remove(*head);
return;
}
if let Some(next) = o.get_mut(*head) {
drop_at(next, rest);
}
}
fn set_at(v: &mut Value, steps: &[&str], word: &str) -> bool {
let Some((head, rest)) = steps.split_first() else {
return false;
};
if *head == "[]" {
let Value::Array(rows) = v else {
return false;
};
let mut set = false;
for row in rows {
set |= set_at(row, rest, word);
}
return set;
}
let Value::Object(o) = v else {
return false;
};
if rest.is_empty() {
return match o.get_mut(*head) {
Some(slot) if slot.is_string() => {
*slot = Value::String(word.to_owned());
true
}
_ => false,
};
}
o.get_mut(*head)
.is_some_and(|next| set_at(next, rest, word))
}
mod tests;