Reputation: 25
I'm making an asset library that's supposed to hold a tree of nodes. A node can be either an Asset
or a Directory
:
struct Node {
name: String,
data: Content,
}
enum Content {
Directory(Vec<Node>),
Asset(Rc<dyn Asset>, usize),
}
I have a create_dir_all
method that's supposed to take a path and create all directories. The way I want to do that is to iterate over the components of the path, search for the corresponding node, and if it is found, move on to the next, if I get a NotFound
error, create the node and then move on.
My first idea was to do this:
let mut current_node = &mut self.root;
for component in path.components() {
let name = component.as_os_str().to_str().unwrap();
current_node = current_node.get_child(name).or_else(|error| match error {
ErrorKind::NotFound => {
current_node.create_child(Node::directory(String::from(name)))
}
error => Err(error),
})?;
}
I believe I understand why that doesn't work: the closure has to borrow current_node
mutably at the time it's created, so the create_child
call is a second mutable borrow.
However, I can't seem to find any way around that. Here's another attempt:
let mut current_node = &mut self.root;
for component in path.components() {
let name = component.as_os_str().to_str().unwrap();
current_node = match current_node.get_child(name) {
Ok(child) => Ok(child),
Err(error) => match error {
ErrorKind::NotFound => {
current_node.create_child(Node::directory(String::from(name)))
}
error => Err(error),
},
}?;
}
Here's my understanding of this one:
The lifetime of current_node
inside the inner match is the same one that's assigned on the get_child
call, so the create_child
call will be a second mutable borrow.
While researching this, I found that the lifetime of the result will be tied to the lifetime of current_node
. If that's the case, is it impossible to match the error and generate a fallback value? That seems like a very simple thing to do but I cannot figure out what I'm missing.
Upvotes: 0
Views: 215
Reputation: 25
I had posted this to the Rust forums as well and got a helpful response there: the borrow checker "does not recognize a borrow being continued on one arm of a match but terminated on another."
I went with the suggestion from that response and will look into writing some unsafe code here in the future. It looks like this:
let mut current_node = &mut self.root;
for component in path.components() {
let name = component.as_os_str().to_str().unwrap();
if let Err(error) = current_node.get_child(name) {
match error {
ErrorKind::NotFound => {
current_node.create_child(Node::directory(String::from(name)))
}
error => Err(error),
}?;
}
current_node = current_node.get_child(name)?;
}
Upvotes: 1