use crate::document::{Document, HOME_TITLE, Link};
use std::collections::VecDeque;
pub fn populate_depths(document: &mut Document) {
for node in document.text_nodes.values_mut() {
node.depth = None;
}
let mut pending_titles = VecDeque::<String>::new();
if let Some(home) = document.text_nodes.get_mut(HOME_TITLE) {
home.depth = Some(0);
pending_titles.push_back(HOME_TITLE.to_owned());
}
while let Some(title) = pending_titles.pop_front() {
let depth = document.text_nodes[&title]
.depth
.expect("queued nodes should have a depth");
let text_links = document.text_nodes[&title]
.links
.iter()
.filter_map(|link| match link {
Link::Text(text_link) => Some(text_link.clone()),
Link::File(_) | Link::Directory(_) => None,
})
.collect::<Vec<_>>();
for text_link in text_links {
if let Some(target) = document.text_nodes.get_mut(&text_link)
&& target.depth.is_none()
{
target.depth = Some(depth + 1);
pending_titles.push_back(text_link);
}
}
}
}
#[cfg(test)]
mod tests {
use super::populate_depths;
use crate::parser::parse;
#[test]
fn transitive_text_links() {
let mut document = parse("# Home\nSee [Middle].\n# Middle\nSee [End].\n# End").unwrap();
populate_depths(&mut document);
assert_eq!(document.text_nodes["Home"].depth, Some(0));
assert_eq!(document.text_nodes["Middle"].depth, Some(1));
assert_eq!(document.text_nodes["End"].depth, Some(2));
}
#[test]
fn minimum_depth() {
let mut document = parse(concat!(
"# Home\nSee [Left] and [Target].\n",
"# Left\nSee [Middle].\n",
"# Middle\nSee [Target].\n",
"# Target",
))
.unwrap();
populate_depths(&mut document);
assert_eq!(document.text_nodes["Left"].depth, Some(1));
assert_eq!(document.text_nodes["Middle"].depth, Some(2));
assert_eq!(document.text_nodes["Target"].depth, Some(1));
}
}