Skip to content

Commit

Permalink
Advanced metadata filtering (#2385)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr authored Mar 15, 2023
1 parent 649ace3 commit 3507dcd
Show file tree
Hide file tree
Showing 16 changed files with 209 additions and 33 deletions.
12 changes: 9 additions & 3 deletions crates/libs/bindgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ pub fn namespace(gen: &Gen, tree: &Tree) -> String {
let mut functions = BTreeMap::<&str, TokenStream>::new();
let mut types = BTreeMap::<TypeKind, BTreeMap<&str, TokenStream>>::new();

for def in gen.reader.namespace_types(tree.namespace) {
for def in gen
.reader
.namespace_types(tree.namespace, &Default::default())
{
let type_name = gen.reader.type_def_type_name(def);
if REMAP_TYPES.iter().any(|(x, _)| x == &type_name) {
continue;
Expand Down Expand Up @@ -145,7 +148,10 @@ pub fn namespace(gen: &Gen, tree: &Tree) -> String {
pub fn namespace_impl(gen: &Gen, tree: &Tree) -> String {
let mut types = BTreeMap::<&str, TokenStream>::new();

for def in gen.reader.namespace_types(tree.namespace) {
for def in gen
.reader
.namespace_types(tree.namespace, &Default::default())
{
let type_name = gen.reader.type_def_type_name(def);
if CORE_TYPES.iter().any(|(x, _)| x == &type_name) {
continue;
Expand All @@ -172,7 +178,7 @@ pub fn namespace_impl(gen: &Gen, tree: &Tree) -> String {

pub fn component(namespace: &str, files: &[File]) -> String {
let reader = &Reader::new(files);
let tree = reader.tree(namespace, &[]).expect("Namespace not found");
let tree = reader.tree(namespace, &Default::default());
let mut gen = Gen::new(reader);
gen.namespace = tree.namespace;
gen.component = true;
Expand Down
2 changes: 1 addition & 1 deletion crates/libs/implement/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ pub fn implement(attributes: proc_macro::TokenStream, original_type: proc_macro:
let remaining = self.count.release();
if remaining == 0 {
unsafe {
let _ = ::std::boxed::Box::from_raw(self as *const Self as *mut Self);
_ = ::std::boxed::Box::from_raw(self as *const Self as *mut Self);
}
}
remaining
Expand Down
6 changes: 3 additions & 3 deletions crates/libs/interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,10 +372,10 @@ impl Parse for Interface {
}

let visibility = input.parse::<syn::Visibility>()?;
let _ = input.parse::<syn::Token![unsafe]>()?;
let _ = input.parse::<syn::Token![trait]>()?;
_ = input.parse::<syn::Token![unsafe]>()?;
_ = input.parse::<syn::Token![trait]>()?;
let name = input.parse::<syn::Ident>()?;
let _ = input.parse::<syn::Token![:]>();
_ = input.parse::<syn::Token![:]>();
let parent = input.parse::<syn::Path>().ok();
let content;
syn::braced!(content in input);
Expand Down
157 changes: 157 additions & 0 deletions crates/libs/metadata/src/reader/filter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
use super::*;

#[derive(Default)]
pub struct Filter<'a>(Vec<(&'a str, bool)>);

impl<'a> Filter<'a> {
pub fn new(include: &[&'a str], exclude: &[&'a str]) -> Self {
let mut rules = vec![];

for include in include {
rules.push((*include, true));
}

for exclude in exclude {
rules.push((*exclude, false));
}

rules.sort_unstable_by(|left, right| {
let left = (left.0.len(), !left.1);
let right = (right.0.len(), !right.1);
left.cmp(&right).reverse()
});

Self(rules)
}

pub fn includes_namespace(&self, namespace: &str) -> bool {
if self.is_empty() {
return true;
}

for rule in &self.0 {
if rule.1 {
// include
if rule.0.starts_with(namespace) {
return true;
}
if namespace.starts_with(rule.0) {
return true;
}
} else {
// exclude
if namespace.starts_with(rule.0) {
return false;
}
}
}

false
}

pub fn includes_type(&self, reader: &Reader, ty: TypeDef) -> bool {
self.includes_type_name(reader.type_def_type_name(ty))
}

fn includes_type_name(&self, type_name: TypeName) -> bool {
if self.is_empty() {
return true;
}

for rule in &self.0 {
if match_type_name(rule.0, type_name.namespace, type_name.name) {
return rule.1;
}
}

false
}

fn is_empty(&self) -> bool {
self.0.is_empty()
}
}

fn match_type_name(rule: &str, namespace: &str, name: &str) -> bool {
if rule.len() <= namespace.len() {
return namespace.starts_with(rule);
}

if !rule.starts_with(namespace) {
return false;
}

if rule.as_bytes()[namespace.len()] != b'.' {
return false;
}

name.starts_with(&rule[namespace.len() + 1..])
}

#[cfg(test)]
mod tests {
use super::*;

fn includes_type_name(filter: &Filter, full_name: &str) -> bool {
filter.includes_type_name(TypeName::parse(full_name))
}

#[test]
fn test_namespace() {
let include = ["N1.N2"];
let exclude = ["N1.N2.N3"];
let f = Filter::new(&include, &exclude);

assert!(f.includes_namespace("N1"));
assert!(f.includes_namespace("N1.N2"));
assert!(f.includes_namespace("N1.N2.N4"));

assert!(!f.includes_namespace("N1.N2.N3"));
assert!(!f.includes_namespace("N1.N2.N3.N4"));
}

#[test]
fn test_simple() {
let include = ["N1", "N3", "N3.N4.N5"];
let exclude = ["N2", "N3.N4"];
let f = Filter::new(&include, &exclude);

assert!(!f.is_empty());

assert!(!includes_type_name(&f, "NN.T"));

assert!(includes_type_name(&f, "N1.T"));
assert!(includes_type_name(&f, "N3.T"));

assert!(!includes_type_name(&f, "N2.T"));
assert!(!includes_type_name(&f, "N3.N4.T"));

assert!(includes_type_name(&f, "N3.N4.N5.T"));
}

#[test]
fn filter_excludes_same_length() {
let include = ["N.N1", "N.N2"];
let exclude = ["N.N3", "N.N4"];
let f = Filter::new(&include, &exclude);

assert!(!f.is_empty());

assert!(includes_type_name(&f, "N.N1.T"));
assert!(includes_type_name(&f, "N.N2.T"));

assert!(!includes_type_name(&f, "N.N3.T"));
assert!(!includes_type_name(&f, "N.N4.T"));
}

#[test]
fn filter_exclude_include_precedence() {
let include = ["N.T"];
let exclude = ["N.T"];
let f = Filter::new(&include, &exclude);

assert!(!f.is_empty());

assert!(!includes_type_name(&f, "N.T"));
}
}
19 changes: 14 additions & 5 deletions crates/libs/metadata/src/reader/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod blob;
mod codes;
mod file;
mod filter;
mod guid;
mod row;
mod tree;
Expand All @@ -11,6 +12,7 @@ pub use super::*;
pub use blob::*;
pub use codes::*;
pub use file::*;
pub use filter::*;
pub use guid::*;
pub use r#type::*;
pub use row::*;
Expand Down Expand Up @@ -195,6 +197,9 @@ impl<'a> Reader<'a> {
for row in 0..file.tables[TABLE_TYPEDEF].len {
let key = Row::new(row, TABLE_TYPEDEF, file_index);
let namespace = file.str(key.row as _, key.table as _, 2);
if namespace.is_empty() {
continue;
}
let name = trim_tick(file.str(key.row as _, key.table as _, 1));
types.entry(namespace).or_default().entry(name).or_default().push(TypeDef(key));
}
Expand All @@ -208,22 +213,26 @@ impl<'a> Reader<'a> {
}
Self { files, types, nested }
}
pub fn tree(&'a self, root: &'a str, exclude: &[&str]) -> Option<Tree> {
pub fn tree(&'a self, root: &'a str, filter: &Filter) -> Tree {
let mut tree = Tree::from_namespace("");
for ns in self.types.keys() {
if !exclude.iter().any(|x| ns.starts_with(x)) {
if filter.includes_namespace(ns) {
tree.insert_namespace(ns, 0);
}
}
tree.seek(root)
if root.is_empty() {
tree
} else {
tree.seek(root).expect("Namespace not found")
}
}

//
// Hash functions for fast type lookup
//

pub fn namespace_types(&self, namespace: &str) -> impl Iterator<Item = TypeDef> + '_ {
self.types.get(namespace).map(|types| types.values().flatten().copied()).into_iter().flatten()
pub fn namespace_types(&'a self, namespace: &str, filter: &'a Filter) -> impl Iterator<Item = TypeDef> + '_ {
self.types.get(namespace).map(move |types| types.values().flatten().copied().filter(move |ty| filter.includes_type(self, *ty))).into_iter().flatten()
}
pub fn nested_types(&self, type_def: TypeDef) -> impl Iterator<Item = TypeDef> + '_ {
self.nested.get(&type_def).map(|map| map.values().copied()).into_iter().flatten()
Expand Down
2 changes: 1 addition & 1 deletion crates/samples/windows/spellchecker/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ fn main() -> Result<()> {
// Get the next suggestion breaking if the call to `Next` failed
let mut suggestion = [PWSTR::null()];
unsafe {
let _ = suggestions.Next(&mut suggestion, None);
_ = suggestions.Next(&mut suggestion, None);
}
if suggestion[0].is_null() {
break;
Expand Down
2 changes: 1 addition & 1 deletion crates/tests/implement/tests/data_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ fn test() -> Result<()> {
assert!(!(*i).EnumDAdvise);

d.DUnadvise(0)?;
let _ = d.EnumDAdvise();
_ = d.EnumDAdvise();

assert!((*i).DUnadvise);
assert!((*i).EnumDAdvise);
Expand Down
2 changes: 1 addition & 1 deletion crates/tests/interface/tests/non_com_existing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ fn test() -> Result<()> {

// Pass the callback to another API (ignore the result)...
let mut source = None;
let _ = audio.CreateSourceVoice(&mut source, std::ptr::null(), 0, 0.0, &*callback, None, None);
_ = audio.CreateSourceVoice(&mut source, std::ptr::null(), 0, 0.0, &*callback, None, None);

Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion crates/tests/matrix3x2/tests/matrix3x2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ use windows::Foundation::Numerics::Matrix3x2;

#[test]
fn test() {
let _ = Matrix3x2::rotation(0.0, 1.0, 2.0);
_ = Matrix3x2::rotation(0.0, 1.0, 2.0);
}
2 changes: 1 addition & 1 deletion crates/tests/not_dll/tests/win.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ use windows::Win32::Graphics::Printing::*;
#[test]
fn test() {
unsafe {
let _ = GetSpoolFileHandle(None);
_ = GetSpoolFileHandle(None);
}
}
2 changes: 1 addition & 1 deletion crates/tests/win32/tests/win32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fn rect() {

#[test]
fn dxgi_mode_desc() {
let _ = DXGI_MODE_DESC {
_ = DXGI_MODE_DESC {
Width: 1,
Height: 2,
RefreshRate: DXGI_RATIONAL { Numerator: 3, Denominator: 5 },
Expand Down
2 changes: 1 addition & 1 deletion crates/tools/gnu/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn build_platform(platform: &str, dlltool: &str, ar: &str) {

let libraries = lib::libraries();
let output = std::path::PathBuf::from(format!("crates/targets/{platform}/lib"));
let _ = std::fs::remove_dir_all(&output);
_ = std::fs::remove_dir_all(&output);
std::fs::create_dir_all(&output).unwrap();

for (library, functions) in &libraries {
Expand Down
2 changes: 1 addition & 1 deletion crates/tools/lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub fn libraries() -> BTreeMap<String, BTreeMap<String, CallingConvention>> {
let files = metadata::reader::File::with_default(&[]).unwrap();
let reader = &metadata::reader::Reader::new(&files);
let mut libraries = BTreeMap::<String, BTreeMap<String, CallingConvention>>::new();
let root = reader.tree("Windows", &[]).expect("`Windows` namespace not found");
let root = reader.tree("Windows", &Default::default());

for tree in root.flatten() {
if let Some(apis) = reader.get(metadata::reader::TypeName::new(tree.namespace, "Apis")).next() {
Expand Down
2 changes: 1 addition & 1 deletion crates/tools/msvc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn main() {

let libraries = lib::libraries();
let output = std::path::PathBuf::from("crates/targets/baseline");
let _ = std::fs::remove_dir_all(&output);
_ = std::fs::remove_dir_all(&output);
std::fs::create_dir_all(&output).unwrap();

for (library, functions) in &libraries {
Expand Down
Loading

0 comments on commit 3507dcd

Please sign in to comment.