#![feature(offset_of_enum)]
use nearest::{Flat, Near, NearList, Region, list, near};
#[derive(Flat, Debug)]
struct Child {
name: NearList<u8>,
node: Near<FsNode>,
}
#[derive(Flat, Debug)]
#[repr(C, u8)]
#[expect(dead_code, reason = "variants constructed via emitters")]
enum FsNode {
File { size: u32 },
Dir { children: NearList<Child> },
}
fn name_of(list: &NearList<u8>) -> String {
list.iter().map(|&b| b as char).collect()
}
fn print_tree(node: &FsNode, prefix: &str, name: &str) {
match node {
FsNode::File { size } => println!("{prefix}{name} ({size} bytes)"),
FsNode::Dir { children } => {
println!("{prefix}{name}/");
for (i, child) in children.iter().enumerate() {
let is_last = i == children.len() - 1;
let connector = if is_last { "└── " } else { "├── " };
let next_prefix = format!("{}{}", prefix, if is_last { " " } else { "│ " });
print_tree(&child.node, &next_prefix, &format!("{}{}", connector, name_of(&child.name)));
}
}
}
}
fn main() {
let src = Region::new(FsNode::make_dir(list([
Child::make(list(b"main.rs".as_slice()), near(FsNode::make_file(1200))),
Child::make(list(b"lib.rs".as_slice()), near(FsNode::make_file(800))),
])));
let docs = Region::new(FsNode::make_dir(list([Child::make(
list(b"readme.md".as_slice()),
near(FsNode::make_file(2400)),
)])));
let mut region = Region::new(FsNode::make_dir(list([
Child::make(list(b"src".as_slice()), near(&*src)),
Child::make(list(b"docs".as_slice()), near(&*docs)),
])));
println!("=== initial tree ===");
print_tree(®ion, "", "root");
region.session(|s| {
let src_children = s.nav(s.root(), |n| match n {
FsNode::Dir { children } => match &*children[0].node {
FsNode::Dir { children } => children,
FsNode::File { .. } => panic!("expected Dir"),
},
FsNode::File { .. } => panic!("expected Dir"),
});
s.extend_list(
src_children,
[Child::make(list(b"test.rs".as_slice()), near(FsNode::make_file(500)))],
);
});
println!("\n=== after adding test.rs ===");
print_tree(®ion, "", "root");
let build = Region::new(FsNode::make_dir(list([
Child::make(list(b"output.bin".as_slice()), near(FsNode::make_file(4096))),
Child::make(list(b"deps.lock".as_slice()), near(FsNode::make_file(128))),
])));
region.session(|s| {
let grafted = s.graft(&build);
let root_children = s.nav(s.root(), |n| match n {
FsNode::Dir { children } => children,
FsNode::File { .. } => panic!("expected Dir"),
});
s.extend_list(root_children, [Child::make(list(b"build".as_slice()), near(grafted))]);
});
println!("\n=== after grafting build/ ===");
print_tree(®ion, "", "root");
match &*region {
FsNode::Dir { children } => {
assert_eq!(children.len(), 3);
assert_eq!(name_of(&children[2].name), "build");
}
FsNode::File { .. } => panic!("expected Dir"),
}
let before = region.byte_len();
region.trim();
println!("\ntrim: {} -> {} bytes", before, region.byte_len());
}