Skip to content

Commit

Permalink
Add fn map(…) and fn map_ref(..) methods to Tree<T>
Browse files Browse the repository at this point in the history
  • Loading branch information
regexident authored Nov 30, 2024
1 parent 95aaf8b commit 78c6bd8
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 1 deletion.
56 changes: 56 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,32 @@ impl<T> Node<T> {
value,
}
}

pub fn map<F, U>(self, mut transform: F) -> Node<U>
where
F: FnMut(T) -> U,
{
Node {
parent: self.parent,
prev_sibling: self.prev_sibling,
next_sibling: self.next_sibling,
children: self.children,
value: transform(self.value),
}
}

pub fn map_ref<F, U>(&self, mut transform: F) -> Node<U>
where
F: FnMut(&T) -> U,
{
Node {
parent: self.parent,
prev_sibling: self.prev_sibling,
next_sibling: self.next_sibling,
children: self.children,
value: transform(&self.value),
}
}
}

/// Node reference.
Expand Down Expand Up @@ -232,6 +258,36 @@ impl<T> Tree<T> {
self.vec.extend(other_tree.vec);
unsafe { self.get_unchecked_mut(other_tree_root_id) }
}

/// Maps a `Tree<T>` to `Tree<U>` by applying a function to all node values,
/// copying over the tree's structure and node ids untouched, consuming `self`.
pub fn map<F, U>(self, mut transform: F) -> Tree<U>
where
F: FnMut(T) -> U,
{
Tree {
vec: self
.vec
.into_iter()
.map(|node| node.map(&mut transform))
.collect(),
}
}

/// Maps a `&Tree<T>` to `Tree<U>` by applying a function to all node values,
/// copying over the tree's structure and node ids untouched.
pub fn map_ref<F, U>(&self, mut transform: F) -> Tree<U>
where
F: FnMut(&T) -> U,
{
Tree {
vec: self
.vec
.iter()
.map(|node| node.map_ref(&mut transform))
.collect(),
}
}
}

impl<'a, T: 'a> NodeRef<'a, T> {
Expand Down
2 changes: 1 addition & 1 deletion src/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl<'a, T> From<NodeRef<'a, T>> for SerNode<'a, T> {
}
}

impl<'a, T: Serialize> Serialize for SerNode<'a, T> {
impl<T: Serialize> Serialize for SerNode<'_, T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
Expand Down
52 changes: 52 additions & 0 deletions tests/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,58 @@ fn insert_id_before() {
assert_eq!(3, tree.root().children().count());
}

#[test]
fn test_map_values() {
let str_tree = tree! {
"root" => {
"a" => {
"child 1",
},
"b" => {
"child 2",
},
}
};

let identity_mapped_tree = str_tree.clone().map(|value| value);

// If we pass the identity function to `.map_values()`,
// then we expect the tree to effectively remain untouched:
assert_eq!(str_tree, identity_mapped_tree);

let string_tree = str_tree.clone().map(|value| value.to_owned());

// A `&str` will produce the same output for `.to_string()` as its equivalent `String`,
// so the output of `.to_string()` should match for corresponding trees as well:
assert_eq!(str_tree.to_string(), string_tree.to_string());
}

#[test]
fn test_map_value_refs() {
let str_tree = tree! {
"root" => {
"a" => {
"child 1",
},
"b" => {
"child 2",
},
}
};

let identity_mapped_tree = str_tree.map_ref(|&value| value);

// If we pass the identity function to `.map_values()`,
// then we expect the tree to effectively remain untouched:
assert_eq!(str_tree, identity_mapped_tree);

let string_tree = str_tree.map_ref(|&value| value.to_owned());

// A `&str` will produce the same output for `.to_string()` as its equivalent `String`,
// so the output of `.to_string()` should match for corresponding trees as well:
assert_eq!(str_tree.to_string(), string_tree.to_string());
}

#[test]
fn test_display() {
let tree = tree! {
Expand Down

0 comments on commit 78c6bd8

Please sign in to comment.