Crate derive_visitor
source · [−]Expand description
This crate derives visitor pattern for arbitrary data structures. This pattern is particularly useful when dealing with complex nested data structures, abstract trees and hierarchies of all kinds.
The main building blocks of this crate are two derivable traits:
Visitor
andVisitorMut
implementations walk through data structures and accumulate some information;Drive
andDriveMut
implementations are data structures that know how to drive a visitor through themselves.
Please refer to these traits’ documentation for more details.
Example
Immutable visitor that counts items in a tree
use derive_visitor::{Visitor, Drive};
#[derive(Drive)]
struct Directory {
#[drive(skip)]
name: String,
items: Vec<DirectoryItem>,
}
#[derive(Drive)]
enum DirectoryItem {
File(File),
Directory(Directory),
}
#[derive(Drive)]
struct File {
#[drive(skip)]
name: String,
}
#[derive(Visitor, Default)]
#[visitor(File(enter), Directory(enter))]
struct Counter {
files: u32,
directories: u32
}
impl Counter {
fn enter_file(&mut self, _file: &File) {
self.files += 1;
}
fn enter_directory(&mut self, _directory: &Directory) {
self.directories += 1;
}
}
let mut counter = Counter::default();
let example_directory = Directory {
name: "root".into(),
items: vec![
DirectoryItem::Directory(
Directory {
name: "home".into(),
items: vec![
DirectoryItem::File(File { name: "README.md".into() }),
DirectoryItem::File(File { name: "Star Wars.mov".into() })
]
}
),
DirectoryItem::Directory(
Directory { name: "downloads".into(), items: vec![] }
)
],
};
example_directory.drive(&mut counter);
assert_eq!(counter.files, 2);
assert_eq!(counter.directories, 3);
Mutable visitor that alters a tree
use derive_visitor::{VisitorMut, DriveMut};
#[derive(DriveMut)]
struct Tree {
#[drive(skip)]
name: String,
children: Vec<Tree>
}
#[derive(VisitorMut, Default)]
#[visitor(Tree(enter))]
struct Renamer {
from: &'static str,
to: &'static str,
}
impl Renamer {
fn enter_tree(&mut self, tree: &mut Tree) {
tree.name = tree.name.replace(self.from, self.to);
}
}
let mut my_tree = Tree{
name: "old parent".to_string(),
children: vec![
Tree {
name: "old child".to_string(),
children: vec![]
}
]
};
my_tree.drive_mut(&mut Renamer{from: "old", to: "new"});
assert_eq!(my_tree.name, "new parent");
assert_eq!(my_tree.children[0].name, "new child");
Features
std-types-drive
- implement Drive for primitive types and String type from std. It is recommended to either skip these types in yourDrive
implementation, or to wrap them with newtypes, so this feature is disabled by default. However it might be useful when driving through autogenerated structs.
Structs
Type returned by visitor_fn.
Enums
Defines whether an item is being entered or exited by a visitor.
Traits
Drive a VisitorMut
over this datastructure.
An interface for visiting arbitrary data structures.
An interface for visiting data structures and mutating them during the visit.
Functions
Similar to visitor_fn, but the closure will only be called on Event::Enter.
Similar to visitor_fn_mut
, but the closure will only be called on Event::Enter.
Create a visitor that only visits items of some specific type from a function or a closure.
Create a visitor that only visits items and mutates them with the given function