kbvm 0.1.5

An implementation of the XKB specification
Documentation
use crate::xkb::{
    kccgst::ast::{
        CompatmapDecl, Component, ConfigItemType, Decl, Decls, DirectOrIncluded, GeometryDecl,
        Included, Item, ItemType, KeycodeDecl, LoadedInclude, SymbolsDecl, TypesDecl,
    },
    span::Spanned,
};

pub(crate) fn embed(item: &mut Item) {
    match &mut item.ty {
        ItemType::Composite(e) => {
            for item in &mut e.config_items {
                embed_config_item_type(&mut item.val.item.specific);
            }
        }
        ItemType::Config(e) => {
            embed_config_item_type(e);
        }
    }
}

trait Embeddable: Sized {
    fn embed(decls: &mut DirectOrIncluded<Self>);

    fn unwrap_decls(i: ConfigItemType) -> Box<[Spanned<Decl<Self>>]>;
}

macro_rules! s {
    ($($decl:ident, $var:ident;)*) => {
        fn embed_config_item_type(item: &mut ConfigItemType) {
            match item {
                $(
                    ConfigItemType::$var(e) => {
                        for doc in &mut e.decls.decls {
                            <$decl>::embed(&mut doc.val.ty);
                        }
                    },
                )*
            }
        }

        $(
            impl Embeddable for $decl {
                fn embed(decl: &mut DirectOrIncluded<Self>) {
                    if let DirectOrIncluded::Direct($decl::Include(i)) = decl {
                        if let Some(loaded) = i.loaded.take() {
                            let mut components = vec!();
                            embed_config_item_type2(&mut components, loaded);
                            *decl = DirectOrIncluded::Included(Included {
                                components: components.into_boxed_slice(),
                            });
                        }
                    }
                }

                fn unwrap_decls(i: ConfigItemType) -> Box<[Spanned<Decl<Self>>]> {
                    match i {
                        ConfigItemType::$var(s) => s.decls.decls,
                        _ => Box::new([]),
                    }
                }
            }
        )*
    };
}

s! {
    KeycodeDecl, Keycodes;
    TypesDecl, Types;
    CompatmapDecl, Compat;
    SymbolsDecl, Symbols;
    GeometryDecl, Geometry;
}

fn embed_config_item_type2<T: Embeddable>(dst: &mut Vec<Component<T>>, src: Box<[LoadedInclude]>) {
    for el in src {
        let mut decls = match el.item.val.ty {
            ItemType::Composite(_) => Box::new([]) as _,
            ItemType::Config(c) => T::unwrap_decls(c),
        };
        for decl in &mut decls {
            T::embed(&mut decl.val.ty);
        }
        dst.push(Component {
            mm: el.mm,
            decls: Decls { decls },
            group: el.group,
        });
    }
}