pub(super) struct ImportLeaf {
pub(super) segments: Box<[Box<str>]>,
pub(super) alias: Option<Box<str>>,
pub(super) glob: bool,
}
pub(super) fn use_tree_leaves(tree: &syn::UseTree) -> Box<[ImportLeaf]> {
let mut leaves = Vec::new();
let mut prefix: Vec<Box<str>> = Vec::new();
let mut pending = vec![Step::Enter(tree)];
while let Some(step) = pending.pop() {
match step {
Step::Enter(node) => enter(node, &mut prefix, &mut pending, &mut leaves),
Step::Restore(depth) => prefix.truncate(depth),
}
}
leaves.into_boxed_slice()
}
enum Step<'a> {
Enter(&'a syn::UseTree),
Restore(usize),
}
fn enter<'a>(
tree: &'a syn::UseTree,
prefix: &mut Vec<Box<str>>,
pending: &mut Vec<Step<'a>>,
leaves: &mut Vec<ImportLeaf>,
) {
match tree {
syn::UseTree::Path(syn::UsePath { ident, tree, .. }) => {
pending.push(Step::Restore(prefix.len()));
prefix.push(ident.to_string().into_boxed_str());
pending.push(Step::Enter(tree));
}
syn::UseTree::Name(syn::UseName { ident }) => leaves.push(leaf(prefix, ident, None)),
syn::UseTree::Rename(syn::UseRename { ident, rename, .. }) => {
let alias = rename.to_string().into_boxed_str();
leaves.push(leaf(prefix, ident, Some(alias)));
}
syn::UseTree::Glob(_) => leaves.push(ImportLeaf {
segments: prefix.to_vec().into_boxed_slice(),
alias: None,
glob: true,
}),
syn::UseTree::Group(syn::UseGroup { items, .. }) => {
pending.extend(items.iter().rev().map(Step::Enter));
}
}
}
fn leaf(prefix: &[Box<str>], ident: &syn::Ident, alias: Option<Box<str>>) -> ImportLeaf {
let segments: Box<[Box<str>]> = prefix
.iter()
.cloned()
.chain(std::iter::once(ident.to_string().into_boxed_str()))
.collect();
ImportLeaf {
segments,
alias,
glob: false,
}
}