kiutils_kicad 0.3.0

Typed KiCad document model and codecs for seamless, lossless edit round-trips
Documentation
use kiutils_sexpr::{Atom, Node};

pub(crate) fn head_of(node: &Node) -> Option<&str> {
    let Node::List { items, .. } = node else {
        return None;
    };
    let Some(Node::Atom {
        atom: Atom::Symbol(head),
        ..
    }) = items.first()
    else {
        return None;
    };
    Some(head.as_str())
}

pub(crate) fn atom_as_string(node: &Node) -> Option<String> {
    match node {
        Node::Atom {
            atom: Atom::Symbol(v),
            ..
        } => Some(v.clone()),
        Node::Atom {
            atom: Atom::Quoted(v),
            ..
        } => Some(v.clone()),
        _ => None,
    }
}

pub(crate) fn atom_as_i32(node: &Node) -> Option<i32> {
    atom_as_string(node).and_then(|s| s.parse::<i32>().ok())
}

pub(crate) fn second_atom_string(node: &Node) -> Option<String> {
    let Node::List { items, .. } = node else {
        return None;
    };
    items.get(1).and_then(atom_as_string)
}

pub(crate) fn second_atom_i32(node: &Node) -> Option<i32> {
    second_atom_string(node).and_then(|s| s.parse::<i32>().ok())
}

pub(crate) fn atom_as_f64(node: &Node) -> Option<f64> {
    atom_as_string(node).and_then(|s| s.parse::<f64>().ok())
}

pub(crate) fn second_atom_f64(node: &Node) -> Option<f64> {
    second_atom_string(node).and_then(|s| s.parse::<f64>().ok())
}

pub(crate) fn second_atom_bool(node: &Node) -> Option<bool> {
    match second_atom_string(node).as_deref() {
        Some("yes") => Some(true),
        Some("no") => Some(false),
        _ => None,
    }
}

pub(crate) fn list_child_head_count(node: &Node, head: &str) -> usize {
    let Node::List { items, .. } = node else {
        return 0;
    };
    items
        .iter()
        .filter(|child| matches!(head_of(child), Some(h) if h == head))
        .count()
}