windows-bindgen 0.52.0

Windows metadata compiler
Documentation
use super::*;

#[derive(Default, Clone)]
pub struct Cfg {
    pub types: BTreeMap<&'static str, BTreeSet<TypeDef>>,
    pub core_types: BTreeSet<Type>,
    pub arches: BTreeSet<&'static str>,
    pub implement: bool,
}

impl Cfg {
    pub fn add_feature(&mut self, feature: &'static str) {
        self.types.entry(feature).or_default();
    }
    pub fn union(&self, other: &Self) -> Self {
        let mut union = Self::default();
        self.types.keys().for_each(|feature| {
            union.types.entry(feature).or_default();
        });
        other.types.keys().for_each(|feature| {
            union.types.entry(feature).or_default();
        });
        self.arches.iter().for_each(|arch| {
            union.arches.insert(arch);
        });
        other.arches.iter().for_each(|arch| {
            union.arches.insert(arch);
        });
        union
    }
}

pub fn field_cfg(row: Field) -> Cfg {
    let mut cfg = Cfg::default();
    field_cfg_combine(row, None, &mut cfg);
    cfg
}
fn field_cfg_combine(row: Field, enclosing: Option<TypeDef>, cfg: &mut Cfg) {
    type_cfg_combine(&row.ty(enclosing), cfg)
}

pub fn type_def_cfg(row: TypeDef, generics: &[Type]) -> Cfg {
    let mut cfg = Cfg::default();
    type_def_cfg_combine(row, generics, &mut cfg);
    cfg_add_attributes(&mut cfg, row);
    cfg
}
pub fn type_def_cfg_impl(def: TypeDef, generics: &[Type]) -> Cfg {
    let mut cfg = Cfg { implement: true, ..Default::default() };

    fn combine(def: TypeDef, generics: &[Type], cfg: &mut Cfg) {
        type_def_cfg_combine(def, generics, cfg);

        for method in def.methods() {
            signature_cfg_combine(&method.signature(generics), cfg);
        }
    }

    combine(def, generics, &mut cfg);

    for interface in type_interfaces(&Type::TypeDef(def, generics.to_vec())) {
        if let Type::TypeDef(def, generics) = interface.ty {
            combine(def, &generics, &mut cfg);
        }
    }

    cfg_add_attributes(&mut cfg, def);
    cfg
}
pub fn type_def_cfg_combine(row: TypeDef, generics: &[Type], cfg: &mut Cfg) {
    let type_name = row.type_name();

    for generic in generics {
        type_cfg_combine(generic, cfg);
    }

    if cfg.types.entry(type_name.namespace).or_default().insert(row) {
        match row.kind() {
            TypeKind::Class => {
                if let Some(default_interface) = type_def_default_interface(row) {
                    type_cfg_combine(&default_interface, cfg);
                }
            }
            TypeKind::Interface => {
                if !row.flags().contains(TypeAttributes::WindowsRuntime) {
                    for def in type_def_vtables(row) {
                        if let Type::TypeDef(def, _) = def {
                            cfg.add_feature(def.namespace());
                        }
                    }
                }
            }
            TypeKind::Struct => {
                row.fields().for_each(|field| field_cfg_combine(field, Some(row), cfg));
                if !type_name.namespace.is_empty() {
                    for def in row.reader().get_type_def(type_name.namespace, type_name.name) {
                        if def != row {
                            type_def_cfg_combine(def, &[], cfg);
                        }
                    }
                }
            }
            TypeKind::Delegate => signature_cfg_combine(&type_def_invoke_method(row).signature(generics), cfg),
            _ => {}
        }
    }
}

pub fn signature_cfg(method: MethodDef) -> Cfg {
    let mut cfg = Cfg::default();
    signature_cfg_combine(&method.signature(&[]), &mut cfg);
    cfg_add_attributes(&mut cfg, method);
    cfg
}
fn signature_cfg_combine(signature: &MethodDefSig, cfg: &mut Cfg) {
    type_cfg_combine(&signature.return_type, cfg);
    signature.params.iter().for_each(|param| type_cfg_combine(param, cfg));
}

fn cfg_add_attributes<R: AsRow + Into<HasAttribute>>(cfg: &mut Cfg, row: R) {
    for attribute in row.attributes() {
        match attribute.name() {
            "SupportedArchitectureAttribute" => {
                if let Some((_, Value::EnumDef(_, value))) = attribute.args().first() {
                    if let Value::I32(value) = **value {
                        if value & 1 == 1 {
                            cfg.arches.insert("x86");
                        }
                        if value & 2 == 2 {
                            cfg.arches.insert("x86_64");
                        }
                        if value & 4 == 4 {
                            cfg.arches.insert("aarch64");
                        }
                    }
                }
            }
            "DeprecatedAttribute" => {
                cfg.add_feature("deprecated");
            }
            _ => {}
        }
    }
}

pub fn type_cfg(ty: &Type) -> Cfg {
    let mut cfg = Cfg::default();
    type_cfg_combine(ty, &mut cfg);
    cfg
}

fn type_cfg_combine(ty: &Type, cfg: &mut Cfg) {
    match ty {
        Type::TypeDef(row, generics) => type_def_cfg_combine(*row, generics, cfg),
        Type::Win32Array(ty, _) => type_cfg_combine(ty, cfg),
        Type::ConstPtr(ty, _) => type_cfg_combine(ty, cfg),
        Type::MutPtr(ty, _) => type_cfg_combine(ty, cfg),
        Type::WinrtArray(ty) => type_cfg_combine(ty, cfg),
        Type::WinrtArrayRef(ty) => type_cfg_combine(ty, cfg),
        ty => _ = cfg.core_types.insert(ty.clone()),
    }
}