I am writing a Rust parser toy, and I want to transform some nodes, there are three possible for this transform remove, keep, ToTopLevel
, remove and keep is ok, but when I encounter ToTopLevel
, I need to clone a node to push it into a temporary Vec
, since it will delete node I wonder if there is any way I can get ownership and just give it to the temporary Vec
.
use std::borrow::Cow;
#[derive(PartialEq, Clone)]
struct ASTNode<'a> {
value: Cow<'a, str>,
nodes: Vec<ASTNode<'a>>
}
struct Visitor<'a> {
new_node: Vec<ASTNode<'a>>
}
enum Action {
Remove,
Keep,
ToTopLevel,
}
impl<'a> Visitor<'a> {
fn some_compute_to_determinate_action(&mut self, root: &mut ASTNode<'a>) -> Action {
return Action::ToTopLevel;
}
fn visit(&mut self, root :&mut ASTNode<'a>) -> Action {
let mut children_actions: Vec<Action> = Vec::new();
for node in &mut root.nodes {
children_actions.push(self.visit(node));
}
let mut index: usize = 0;
root.nodes.retain(|node| {
index+=1;
match children_actions[index-1] {
Action::Remove => false,
Action::Keep => true,
Action::ToTopLevel => {
// since it would delete node, is there are any way
// i can take ownership and push it to new_node vec ?
// like : self.new_node.push(*node);
self.new_node.push(node.clone());
return false;
}
}
});
return self.some_compute_to_determinate_action(root);
}
fn push_node_to_top_level_after_visit(&mut self,root: &mut ASTNode<'a>) {
root.nodes.append(&mut self.new_node);
}
}
fn main() {
let mut root = ASTNode {
value: Cow::Borrowed("root_value"),
nodes: Vec::new()/* assume there are a a lot of nested children */
};
let mut visitor = Visitor {
new_node: Vec::new()
};
visitor.visit(&mut root);
visitor.push_node_to_top_level_after_visit(&mut root);
}
There is no iterator or method which hands off the item itself (it'd need something like T -> Option<T>
as a callback, not sure why there isn't such a variant for drain
and retain
though, seems useful).
However since it's possible to create an ASTNode
cheaply:
ASTNode {
value: Cow::Borrowed(""),
nodes: Vec::new()
}
what you can do is use Vec::retain_mut
and std::mem::replace
to take the "actual" ASTNode out replacing it with a dummy which you then don't keep:
root.nodes.retain_mut(|node| {
index+=1;
match children_actions[index-1] {
Action::Remove => false,
Action::Keep => true,
Action::ToTopLevel => {
self.new_node.push(std::mem::replace(node, ASTNode {
value: Cow::Borrowed(""),
nodes: Vec::new(),
}));
false
}
}
});
or if you derive(Default)
on ASTNode
, just std::mem::take
root.nodes.retain_mut(|node| {
index+=1;
match children_actions[index-1] {
Action::Remove => false,
Action::Keep => true,
Action::ToTopLevel => {
self.new_node.push(std::mem::take(node));
false
}
}
});