Skip to content

Commit

Permalink
Simplify metadata filtering (#2684)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr authored Oct 18, 2023
1 parent 462f941 commit 22de1c9
Show file tree
Hide file tree
Showing 32 changed files with 264 additions and 280 deletions.
11 changes: 5 additions & 6 deletions crates/libs/bindgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,14 @@ where
let output = canonicalize(output)?;

let input = read_input(&input)?;
let reader = metadata::Reader::new(input);
let filter = metadata::Filter::new(&include, &exclude);
let reader = metadata::Reader::filter(input, &include, &exclude);

winmd::verify(reader, &filter)?;
winmd::verify(reader)?;

match extension(&output) {
"rdl" => rdl::from_reader(reader, &filter, config, &output)?,
"winmd" => winmd::from_reader(reader, &filter, config, &output)?,
"rs" => rust::from_reader(reader, &filter, config, &output)?,
"rdl" => rdl::from_reader(reader, config, &output)?,
"winmd" => winmd::from_reader(reader, config, &output)?,
"rs" => rust::from_reader(reader, config, &output)?,
_ => return Err(Error::new("output extension must be one of winmd/rdl/rs")),
}

Expand Down
135 changes: 68 additions & 67 deletions crates/libs/bindgen/src/metadata.rs

Large diffs are not rendered by default.

19 changes: 9 additions & 10 deletions crates/libs/bindgen/src/rdl/from_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ use crate::tokens::{quote, to_ident, TokenStream};
use crate::{rdl, Error, Result, Tree};
use metadata::*;

pub fn from_reader(reader: &metadata::Reader, filter: &metadata::Filter, mut config: std::collections::BTreeMap<&str, &str>, output: &str) -> Result<()> {
pub fn from_reader(reader: &metadata::Reader, mut config: std::collections::BTreeMap<&str, &str>, output: &str) -> Result<()> {
let dialect = match config.remove("type") {
Some("winrt") => Dialect::WinRT,
Some("win32") => Dialect::Win32,
_ => return Err(Error::new("configuration value `type` must be `win32` or `winrt`")),
};

let mut writer = Writer::new(reader, filter, output, dialect);
let mut writer = Writer::new(reader, output, dialect);

// TODO: be sure to use the same "split" key for winmd splitting.
// May also want to support split=N similar to the way MIDLRT supports winmd splitting
Expand All @@ -29,7 +29,7 @@ pub fn from_reader(reader: &metadata::Reader, filter: &metadata::Filter, mut con
}

fn gen_split(writer: &Writer) -> Result<()> {
let tree = Tree::new(writer.reader, writer.filter);
let tree = Tree::new(writer.reader);
let directory = crate::directory(writer.output);

// TODO: parallelize
Expand All @@ -46,7 +46,7 @@ fn gen_split(writer: &Writer) -> Result<()> {
}

fn gen_file(writer: &Writer) -> Result<()> {
let tree = Tree::new(writer.reader, writer.filter);
let tree = Tree::new(writer.reader);
let tokens = writer.tree(&tree);
writer.write_to_file(writer.output, tokens)
}
Expand All @@ -59,20 +59,19 @@ enum Dialect {

struct Writer<'a> {
reader: &'a metadata::Reader,
filter: &'a metadata::Filter<'a>,
namespace: &'a str,
dialect: Dialect,
split: bool,
output: &'a str,
}

impl<'a> Writer<'a> {
fn new(reader: &'a metadata::Reader, filter: &'a metadata::Filter, output: &'a str, dialect: Dialect) -> Self {
Self { reader, filter, namespace: "", output, dialect, split: false }
fn new(reader: &'a metadata::Reader, output: &'a str, dialect: Dialect) -> Self {
Self { reader, namespace: "", output, dialect, split: false }
}

fn with_namespace(&self, namespace: &'a str) -> Self {
Self { reader: self.reader, filter: self.filter, namespace, dialect: self.dialect, output: self.output, split: self.split }
Self { reader: self.reader, namespace, dialect: self.dialect, output: self.output, split: self.split }
}

fn write_to_file(&self, output: &str, tokens: TokenStream) -> Result<()> {
Expand Down Expand Up @@ -135,7 +134,7 @@ impl<'a> Writer<'a> {
let mut types = vec![];

if !tree.namespace.is_empty() {
for item in self.reader.namespace_items(tree.namespace, self.filter).filter(|item| match item {
for item in self.reader.namespace_items(tree.namespace).filter(|item| match item {
metadata::Item::Type(def) => {
let winrt = def.flags().contains(metadata::TypeAttributes::WindowsRuntime);
match self.dialect {
Expand Down Expand Up @@ -246,7 +245,7 @@ impl<'a> Writer<'a> {
let name = to_ident(method.name());

// TODO: use reader.method_def_signature instead
let signature = metadata::method_def_signature(self.reader, def.namespace(), method, generics);
let signature = metadata::method_def_signature(def.namespace(), method, generics);

let return_type = self.return_type(&signature.return_type);

Expand Down
76 changes: 38 additions & 38 deletions crates/libs/bindgen/src/rust/cfg.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use super::*;

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

impl<'a> Cfg<'a> {
pub fn add_feature(&mut self, feature: &'a str) {
impl Cfg {
pub fn add_feature(&mut self, feature: &'static str) {
self.types.entry(feature).or_default();
}
pub fn union(&self, other: &Self) -> Self {
Expand All @@ -30,63 +30,63 @@ impl<'a> Cfg<'a> {
}
}

pub fn field_cfg(reader: &Reader, row: Field) -> Cfg {
pub fn field_cfg(row: Field) -> Cfg {
let mut cfg = Cfg::default();
field_cfg_combine(reader, row, None, &mut cfg);
field_cfg_combine(row, None, &mut cfg);
cfg
}
fn field_cfg_combine<'a>(reader: &'a Reader, row: Field, enclosing: Option<TypeDef>, cfg: &mut Cfg<'a>) {
type_cfg_combine(reader, &row.ty(enclosing), 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<'a>(reader: &'a Reader, row: TypeDef, generics: &[Type]) -> Cfg<'a> {
pub fn type_def_cfg(row: TypeDef, generics: &[Type]) -> Cfg {
let mut cfg = Cfg::default();
type_def_cfg_combine(reader, row, generics, &mut cfg);
type_def_cfg_combine(row, generics, &mut cfg);
cfg_add_attributes(&mut cfg, row);
cfg
}
pub fn type_def_cfg_impl<'a>(reader: &'a Reader, def: TypeDef, generics: &[Type]) -> Cfg<'a> {
pub fn type_def_cfg_impl(def: TypeDef, generics: &[Type]) -> Cfg {
let mut cfg = Cfg { implement: true, ..Default::default() };

fn combine<'a>(reader: &'a Reader, def: TypeDef, generics: &[Type], cfg: &mut Cfg<'a>) {
type_def_cfg_combine(reader, def, generics, cfg);
fn combine(def: TypeDef, generics: &[Type], cfg: &mut Cfg) {
type_def_cfg_combine(def, generics, cfg);

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

combine(reader, def, generics, &mut cfg);
combine(def, generics, &mut cfg);

for def in type_def_vtables(def) {
if let Type::TypeDef(def, generics) = def {
combine(reader, def, &generics, &mut cfg);
combine(def, &generics, &mut cfg);
}
}

if def.flags().contains(TypeAttributes::WindowsRuntime) {
for interface in type_def_interfaces(def, generics) {
if let Type::TypeDef(def, generics) = interface {
combine(reader, def, &generics, &mut cfg);
combine(def, &generics, &mut cfg);
}
}
}

cfg_add_attributes(&mut cfg, def);
cfg
}
pub fn type_def_cfg_combine<'a>(reader: &'a Reader, row: TypeDef, generics: &[Type], cfg: &mut Cfg<'a>) {
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(reader, generic, cfg);
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(reader, &default_interface, cfg);
type_cfg_combine(&default_interface, cfg);
}
}
TypeKind::Interface => {
Expand All @@ -99,30 +99,30 @@ pub fn type_def_cfg_combine<'a>(reader: &'a Reader, row: TypeDef, generics: &[Ty
}
}
TypeKind::Struct => {
row.fields().for_each(|field| field_cfg_combine(reader, field, Some(row), cfg));
row.fields().for_each(|field| field_cfg_combine(field, Some(row), cfg));
if !type_name.namespace.is_empty() {
for def in reader.get_type_def(type_name.namespace, type_name.name) {
for def in row.reader().get_type_def(type_name.namespace, type_name.name) {
if def != row {
type_def_cfg_combine(reader, def, &[], cfg);
type_def_cfg_combine(def, &[], cfg);
}
}
}
}
TypeKind::Delegate => signature_cfg_combine(reader, &type_def_invoke_method(row).signature(generics), cfg),
TypeKind::Delegate => signature_cfg_combine(&type_def_invoke_method(row).signature(generics), cfg),
_ => {}
}
}
}

pub fn signature_cfg(reader: &Reader, method: MethodDef) -> Cfg {
pub fn signature_cfg(method: MethodDef) -> Cfg {
let mut cfg = Cfg::default();
signature_cfg_combine(reader, &method.signature(&[]), &mut cfg);
signature_cfg_combine(&method.signature(&[]), &mut cfg);
cfg_add_attributes(&mut cfg, method);
cfg
}
fn signature_cfg_combine<'a>(reader: &'a Reader, signature: &MethodDefSig, cfg: &mut Cfg<'a>) {
type_cfg_combine(reader, &signature.return_type, cfg);
signature.params.iter().for_each(|param| type_cfg_combine(reader, param, 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) {
Expand Down Expand Up @@ -151,19 +151,19 @@ fn cfg_add_attributes<R: AsRow + Into<HasAttribute>>(cfg: &mut Cfg, row: R) {
}
}

pub fn type_cfg<'a>(reader: &'a Reader, ty: &Type) -> Cfg<'a> {
pub fn type_cfg(ty: &Type) -> Cfg {
let mut cfg = Cfg::default();
type_cfg_combine(reader, ty, &mut cfg);
type_cfg_combine(ty, &mut cfg);
cfg
}
fn type_cfg_combine<'a>(reader: &'a Reader, ty: &Type, cfg: &mut Cfg<'a>) {
fn type_cfg_combine(ty: &Type, cfg: &mut Cfg) {
match ty {
Type::TypeDef(row, generics) => type_def_cfg_combine(reader, *row, generics, cfg),
Type::Win32Array(ty, _) => type_cfg_combine(reader, ty, cfg),
Type::ConstPtr(ty, _) => type_cfg_combine(reader, ty, cfg),
Type::MutPtr(ty, _) => type_cfg_combine(reader, ty, cfg),
Type::WinrtArray(ty) => type_cfg_combine(reader, ty, cfg),
Type::WinrtArrayRef(ty) => type_cfg_combine(reader, ty, cfg),
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()),
}
}
12 changes: 6 additions & 6 deletions crates/libs/bindgen/src/rust/classes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ fn gen_class(writer: &Writer, def: TypeDef) -> TokenStream {
}

let name = to_ident(def.name());
let interfaces = type_interfaces(writer.reader, &Type::TypeDef(def, Vec::new()));
let interfaces = type_interfaces(&Type::TypeDef(def, Vec::new()));
let mut methods = quote! {};
let mut method_names = MethodNames::new();

let cfg = type_def_cfg(writer.reader, def, &[]);
let cfg = type_def_cfg(def, &[]);
let doc = writer.cfg_doc(&cfg);
let features = writer.cfg_features(&cfg);

Expand All @@ -44,7 +44,7 @@ fn gen_class(writer: &Writer, def: TypeDef) -> TokenStream {
if let Type::TypeDef(def, generics) = &interface.ty {
if def.methods().next().is_some() {
let interface_type = writer.type_name(&interface.ty);
let features = writer.cfg_features(&type_def_cfg(writer.reader, *def, generics));
let features = writer.cfg_features(&type_def_cfg(*def, generics));

return Some(quote! {
#[doc(hidden)]
Expand Down Expand Up @@ -138,17 +138,17 @@ fn gen_conversions(writer: &Writer, def: TypeDef, name: &TokenStream, interfaces
}

let into = writer.type_name(&interface.ty);
let features = writer.cfg_features(&cfg.union(&type_cfg(writer.reader, &interface.ty)));
let features = writer.cfg_features(&cfg.union(&type_cfg(&interface.ty)));

tokens.combine(&quote! {
#features
impl ::windows_core::CanTryInto<#into> for #name {}
});
}

for def in type_def_bases(writer.reader, def) {
for def in type_def_bases(def) {
let into = writer.type_def_name(def, &[]);
let features = writer.cfg_features(&cfg.union(&type_def_cfg(writer.reader, def, &[])));
let features = writer.cfg_features(&cfg.union(&type_def_cfg(def, &[])));

tokens.combine(&quote! {
#features
Expand Down
4 changes: 2 additions & 2 deletions crates/libs/bindgen/src/rust/com_methods.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use super::*;

pub fn writer(writer: &Writer, def: TypeDef, kind: InterfaceKind, method: MethodDef, method_names: &mut MethodNames, virtual_names: &mut MethodNames, base_count: usize) -> TokenStream {
let signature = method_def_signature(writer.reader, def.namespace(), method, &[]);
let signature = method_def_signature(def.namespace(), method, &[]);

let name = method_names.add(method);
let vname = virtual_names.add(method);
let generics = writer.constraint_generics(&signature.params);
let where_clause = writer.where_clause(&signature.params);
let mut cfg = signature_cfg(writer.reader, method);
let mut cfg = signature_cfg(method);
cfg.add_feature(def.namespace());
let doc = writer.cfg_method_doc(&cfg);
let features = writer.cfg_features(&cfg);
Expand Down
2 changes: 1 addition & 1 deletion crates/libs/bindgen/src/rust/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use super::*;
pub fn writer(writer: &Writer, def: Field) -> TokenStream {
let name = to_ident(def.name());
let ty = def.ty(None).to_const_type();
let cfg = field_cfg(writer.reader, def);
let cfg = field_cfg(def);
let doc = writer.cfg_doc(&cfg);
let features = writer.cfg_features(&cfg);

Expand Down
8 changes: 4 additions & 4 deletions crates/libs/bindgen/src/rust/delegates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ fn gen_callback(writer: &Writer, def: TypeDef) -> TokenStream {
let name = to_ident(def.name());
let method = type_def_invoke_method(def);

let signature = method_def_signature(writer.reader, def.namespace(), method, &[]);
let signature = method_def_signature(def.namespace(), method, &[]);

let return_type = writer.return_sig(&signature);
let cfg = type_def_cfg(writer.reader, def, &[]);
let cfg = type_def_cfg(def, &[]);
let doc = writer.cfg_doc(&cfg);
let features = writer.cfg_features(&cfg);

Expand Down Expand Up @@ -57,10 +57,10 @@ fn gen_win_delegate(writer: &Writer, def: TypeDef) -> TokenStream {
let ident = writer.type_def_name(def, generics);
let method = type_def_invoke_method(def);

let signature = method_def_signature(writer.reader, def.namespace(), method, generics);
let signature = method_def_signature(def.namespace(), method, generics);

let fn_constraint = gen_fn_constraint(writer, def, &signature);
let cfg = type_def_cfg(writer.reader, def, generics);
let cfg = type_def_cfg(def, generics);
let doc = writer.cfg_doc(&cfg);
let features = writer.cfg_features(&cfg);

Expand Down
4 changes: 2 additions & 2 deletions crates/libs/bindgen/src/rust/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub fn writer(writer: &Writer, def: TypeDef) -> TokenStream {
// TODO: unscoped enums should be removed from metadata
let is_scoped = def.flags().contains(TypeAttributes::WindowsRuntime) || def.has_attribute("ScopedEnumAttribute");

let cfg = type_def_cfg(writer.reader, def, &[]);
let cfg = type_def_cfg(def, &[]);
let doc = writer.cfg_doc(&cfg);
let features = writer.cfg_features(&cfg);

Expand Down Expand Up @@ -160,7 +160,7 @@ pub fn writer(writer: &Writer, def: TypeDef) -> TokenStream {
}

if def.flags().contains(TypeAttributes::WindowsRuntime) {
let signature = Literal::byte_string(type_def_signature(writer.reader, def, &[]).as_bytes());
let signature = Literal::byte_string(type_def_signature(def, &[]).as_bytes());

tokens.combine(&quote! {
#features
Expand Down
Loading

0 comments on commit 22de1c9

Please sign in to comment.