axbuild 0.4.17

An OS build lib toolkit used by arceos
Documentation
use super::*;

#[derive(Default)]
pub(super) struct CaseTreeNode {
    children: BTreeMap<String, CaseTreeNode>,
    labels: BTreeSet<String>,
}

pub(super) fn insert_case_tree_path(node: &mut CaseTreeNode, path: &str) {
    insert_case_tree_path_with_label(node, path, None);
}

pub(super) fn insert_case_tree_path_with_label(
    node: &mut CaseTreeNode,
    path: &str,
    label: Option<String>,
) {
    let mut current = node;
    for part in path.split('/').filter(|part| !part.is_empty()) {
        current = current.children.entry(part.to_string()).or_default();
    }
    if let Some(label) = label {
        current.labels.insert(label);
    }
}

pub(super) fn render_case_tree_node(node: &CaseTreeNode, prefix: &str, lines: &mut Vec<String>) {
    let total = node.children.len();
    for (index, (name, child)) in node.children.iter().enumerate() {
        let is_last = index + 1 == total;
        let branch = if is_last { "└── " } else { "├── " };
        let label = if child.labels.is_empty() {
            String::new()
        } else {
            format!(
                " [{}]",
                child
                    .labels
                    .iter()
                    .map(String::as_str)
                    .collect::<Vec<_>>()
                    .join(", ")
            )
        };
        lines.push(format!("{prefix}{branch}{name}{label}"));

        let child_prefix = if is_last { "    " } else { "" };
        render_case_tree_node(child, &format!("{prefix}{child_prefix}"), lines);
    }
}

pub(crate) fn render_case_tree<I, S>(group: &str, cases: I) -> String
where
    I: IntoIterator<Item = S>,
    S: AsRef<str>,
{
    let mut root = CaseTreeNode::default();
    for case in cases {
        insert_case_tree_path(&mut root, case.as_ref());
    }

    let mut lines = vec![group.to_string()];
    render_case_tree_node(&root, "", &mut lines);
    lines.join("\n")
}

pub(crate) fn render_qemu_case_forest<I, G, C>(suite: &str, groups: I) -> String
where
    I: IntoIterator<Item = (G, C)>,
    G: AsRef<str>,
    C: IntoIterator<Item = ListedQemuCase>,
{
    let mut root = CaseTreeNode::default();
    for (group, cases) in groups {
        let group_node = root.children.entry(group.as_ref().to_string()).or_default();
        for case in cases {
            let label = if case.archs.is_empty() {
                None
            } else {
                Some(case.archs.join(", "))
            };
            insert_case_tree_path_with_label(group_node, &case.name, label);
        }
    }

    let mut lines = vec![suite.to_string()];
    render_case_tree_node(&root, "", &mut lines);
    lines.join("\n")
}

pub(crate) fn render_labeled_case_forest<I, G, C, N, L>(suite: &str, groups: I) -> String
where
    I: IntoIterator<Item = (G, C)>,
    G: AsRef<str>,
    C: IntoIterator<Item = (N, L)>,
    N: AsRef<str>,
    L: AsRef<str>,
{
    let mut root = CaseTreeNode::default();
    for (group, cases) in groups {
        let group_node = root.children.entry(group.as_ref().to_string()).or_default();
        for (case, label) in cases {
            insert_case_tree_path_with_label(
                group_node,
                case.as_ref(),
                Some(label.as_ref().to_string()),
            );
        }
    }

    let mut lines = vec![suite.to_string()];
    render_case_tree_node(&root, "", &mut lines);
    lines.join("\n")
}