Maintain parent pointers from primitive values too

After resolving a reference to a primitive value, we want to set
its parent pointer so that `Tree::resolve` can navigate upward and
update the cached resolved status of each node.
This commit is contained in:
Antonio Scandurra 2021-09-16 11:15:48 +02:00
parent df4b5890fd
commit 9402eb3f3e

View file

@ -30,10 +30,21 @@ enum Node {
resolved: bool,
parent: Option<Weak<RefCell<Node>>>,
},
String(String),
Number(serde_json::Number),
Bool(bool),
Null,
String {
value: String,
parent: Option<Weak<RefCell<Node>>>,
},
Number {
value: serde_json::Number,
parent: Option<Weak<RefCell<Node>>>,
},
Bool {
value: bool,
parent: Option<Weak<RefCell<Node>>>,
},
Null {
parent: Option<Weak<RefCell<Node>>>,
},
}
#[derive(Clone)]
@ -53,12 +64,21 @@ impl Tree {
parent: None,
}))
} else {
Ok(Self::new(Node::String(value)))
Ok(Self::new(Node::String {
value,
parent: None,
}))
}
}
Value::Number(value) => Ok(Self::new(Node::Number(value))),
Value::Bool(value) => Ok(Self::new(Node::Bool(value))),
Value::Null => Ok(Self::new(Node::Null)),
Value::Number(value) => Ok(Self::new(Node::Number {
value,
parent: None,
})),
Value::Bool(value) => Ok(Self::new(Node::Bool {
value,
parent: None,
})),
Value::Null => Ok(Self::new(Node::Null { parent: None })),
Value::Object(object) => {
let tree = Self::new(Node::Object {
base: Default::default(),
@ -75,7 +95,10 @@ impl Tree {
if let Value::String(value) = value {
base = value.strip_prefix("$").map(str::to_string);
resolved = false;
Self::new(Node::String(value))
Self::new(Node::String {
value,
parent: None,
})
} else {
unreachable!()
}
@ -133,10 +156,10 @@ impl Tree {
fn to_json(&self) -> Result<Value> {
match &*self.0.borrow() {
Node::Reference { .. } => Err(anyhow!("unresolved tree")),
Node::String(value) => Ok(Value::String(value.clone())),
Node::Number(value) => Ok(Value::Number(value.clone())),
Node::Bool(value) => Ok(Value::Bool(*value)),
Node::Null => Ok(Value::Null),
Node::String { value, .. } => Ok(Value::String(value.clone())),
Node::Number { value, .. } => Ok(Value::Number(value.clone())),
Node::Bool { value, .. } => Ok(Value::Bool(*value)),
Node::Null { .. } => Ok(Value::Null),
Node::Object { children, .. } => {
let mut json_children = serde_json::Map::new();
for (key, value) in children {
@ -158,8 +181,11 @@ impl Tree {
match &*self.0.borrow() {
Node::Reference { parent, .. }
| Node::Object { parent, .. }
| Node::Array { parent, .. } => parent.as_ref().and_then(|p| p.upgrade()).map(Tree),
_ => None,
| Node::Array { parent, .. }
| Node::String { parent, .. }
| Node::Number { parent, .. }
| Node::Bool { parent, .. }
| Node::Null { parent } => parent.as_ref().and_then(|p| p.upgrade()).map(Tree),
}
}
@ -182,10 +208,10 @@ impl Tree {
}
Node::Reference { .. } => return Ok(None),
Node::Array { .. }
| Node::String(_)
| Node::Number(_)
| Node::Bool(_)
| Node::Null => {
| Node::String { .. }
| Node::Number { .. }
| Node::Bool { .. }
| Node::Null { .. } => {
return Err(anyhow!(
"key \"{}\" in path \"{}\" is not an object",
component,
@ -202,7 +228,9 @@ impl Tree {
match &*self.0.borrow() {
Node::Reference { .. } => false,
Node::Object { resolved, .. } | Node::Array { resolved, .. } => *resolved,
Node::String(_) | Node::Number(_) | Node::Bool(_) | Node::Null => true,
Node::String { .. } | Node::Number { .. } | Node::Bool { .. } | Node::Null { .. } => {
true
}
}
}
@ -247,14 +275,13 @@ impl Tree {
}
fn resolve_subtree(&self, root: &Tree, unresolved: &mut Vec<Tree>) -> Result<bool> {
let mut made_progress = false;
let borrow = self.0.borrow();
match &*borrow {
let node = self.0.borrow();
match &*node {
Node::Reference { path, parent } => {
if let Some(subtree) = root.get(&path)? {
if subtree.is_resolved() {
let parent = parent.clone();
drop(borrow);
drop(node);
let mut new_node = subtree.0.borrow().clone();
new_node.set_parent(parent);
*self.0.borrow_mut() = new_node;
@ -277,6 +304,7 @@ impl Tree {
if *resolved {
Ok(false)
} else {
let mut made_progress = false;
let mut children_resolved = true;
for child in children.values() {
made_progress |= child.resolve_subtree(root, unresolved)?;
@ -291,16 +319,15 @@ impl Tree {
if let Some(base) = root.get(base)? {
if base.is_resolved() {
resolved_base = Some(base);
} else {
made_progress |= base.resolve_subtree(root, unresolved)?;
}
}
}
drop(borrow);
drop(node);
if let Some(base) = resolved_base.as_ref() {
self.extend_from(&base);
made_progress = true;
}
if let Node::Object { resolved, .. } = &mut *self.0.borrow_mut() {
@ -325,6 +352,7 @@ impl Tree {
if *resolved {
Ok(false)
} else {
let mut made_progress = false;
let mut children_resolved = true;
for child in children.iter() {
made_progress |= child.resolve_subtree(root, unresolved)?;
@ -332,7 +360,7 @@ impl Tree {
}
if children_resolved {
drop(borrow);
drop(node);
if let Node::Array { resolved, .. } = &mut *self.0.borrow_mut() {
*resolved = true;
@ -342,8 +370,8 @@ impl Tree {
Ok(made_progress)
}
}
Node::String(_) | Node::Number(_) | Node::Bool(_) | Node::Null => {
return Ok(false);
Node::String { .. } | Node::Number { .. } | Node::Bool { .. } | Node::Null { .. } => {
Ok(false)
}
}
}
@ -382,8 +410,11 @@ impl Node {
match self {
Node::Reference { parent, .. }
| Node::Object { parent, .. }
| Node::Array { parent, .. } => *parent = new_parent,
_ => {}
| Node::Array { parent, .. }
| Node::String { parent, .. }
| Node::Number { parent, .. }
| Node::Bool { parent, .. }
| Node::Null { parent } => *parent = new_parent,
}
}
}