Mutating tree like structures

Hi! Something like this has probably been answered before, but I'm having trouble figuring out what to search for.

I'm trying to write an editor for SmartGit's repository-grouping.yml files. Their contents look something like this:

structure:
- name: code
  children:
  - name: github
    children:
    - name: imager
      children:
      - {name: imager, git: true, path: ~/code/github.com/imager-io/imager, path.absolute: /home/user/code/github.com/imager-io/imager}
  - name: gitlab
    children: []
recentlyUsed: [~/code/github.com/imager-io/imager]
ignored: []

Using serde and the serde_yaml I've got the file parsing into structs that look like:

#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct RepoGroupingFile<'a> {
    structure: Vec<StructureNode<'a>>,

    #[serde(rename = "recentlyUsed")]
    recently_used: Vec<String>,
    ignored: Vec<String>,
}

#[serde(untagged)]
#[derive(Serialize, Deserialize, PartialEq, Debug)]
enum StructureNode<'a> {
    Group(Group<'a>),
    Repo(Repo<'a>),
}

#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Group<'a> {
    name: Cow<'a, str>,
    children: Vec<StructureNode<'a>>,
    expanded: bool,
}

#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct Repo<'a> {
    name: Cow<'a, str>,
    git: bool,
    path: Cow<'a, str>,

    #[serde(rename = "path.absolute")]
    path_absolute: Cow<'a, str>,
}

I'd like to be able to pass a path to a git repo, and create any Group and Repo notes (as necessary). In another language I'd loop through each level, creating additional nodes as necessary.

Eg (pseudocode - my current attempt is a broken mess):

/// structure is the structure vector from the file
/// hierarchy is the path split by separator eg: ['home,'user','test']
ensure_nodes(structure: Vec<StructureNode<'a>>, hierarchy: &mut VecDeque<String>) {
    current_children = &structure

    while let Some(current) = hierarchy.pop_front() {
       if current_children contains node.name == current:
           current_childern = node.children
           continue

      // create the node
      new_node = StructureNode::Group(Group{})
      current_children.push(new_node)
      // grab the children vector from the element we just pushed onto the vec
      current_children = &current_children.last().children
    }
}

However, this approach runs afoul of the borrow checker, mostly around multiple mutable borrows of current_children.

I was reading other approaches to mutable trees where nodes contain a vector of indicies of their children and you index into a vector containing the acual nodes. However, I'd rather not have to translate from the file representation to this editable representation and back again. I also considered rebuilding the entire structure every time (so everything is owned), but that didn't immediately seem like an easier solution.

Any advice would be greatly appreciated!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.