From 403a8e59bf6aea7a493e22c688397590f9e9365e Mon Sep 17 00:00:00 2001 From: Kenny Kerr Date: Thu, 9 Jan 2025 09:21:41 -0600 Subject: [PATCH] Revert "Simplify internal `windows-bindgen` caching (#3427)" This reverts commit ffb90786c00e03d8684e2bf46695b90fb6b4a7c2. --- crates/libs/bindgen/src/config.rs | 38 ---------------- crates/libs/bindgen/src/derive.rs | 10 ++--- crates/libs/bindgen/src/derive_writer.rs | 4 +- crates/libs/bindgen/src/filter.rs | 10 ++--- crates/libs/bindgen/src/lib.rs | 41 ++++++++++++----- crates/libs/bindgen/src/libraries.rs | 20 ++++++--- crates/libs/bindgen/src/references.rs | 6 +-- crates/libs/bindgen/src/tables/attribute.rs | 2 +- crates/libs/bindgen/src/tables/method_def.rs | 3 +- crates/libs/bindgen/src/tables/type_def.rs | 2 +- crates/libs/bindgen/src/type_map.rs | 9 ++-- crates/libs/bindgen/src/type_tree.rs | 4 +- crates/libs/bindgen/src/types/class.rs | 16 +++---- crates/libs/bindgen/src/types/cpp_const.rs | 6 +-- crates/libs/bindgen/src/types/cpp_delegate.rs | 2 +- crates/libs/bindgen/src/types/cpp_enum.rs | 11 ++--- crates/libs/bindgen/src/types/cpp_fn.rs | 19 ++++---- .../libs/bindgen/src/types/cpp_interface.rs | 28 ++++++------ crates/libs/bindgen/src/types/cpp_struct.rs | 17 +++---- crates/libs/bindgen/src/types/delegate.rs | 2 +- crates/libs/bindgen/src/types/enum.rs | 8 ++-- crates/libs/bindgen/src/types/interface.rs | 34 +++++++------- crates/libs/bindgen/src/types/mod.rs | 45 +++++++++++++------ crates/libs/bindgen/src/types/struct.rs | 6 +-- crates/libs/bindgen/src/winmd/blob.rs | 4 ++ crates/libs/bindgen/src/winmd/codes.rs | 8 ++++ crates/libs/bindgen/src/winmd/file.rs | 7 +++ crates/libs/bindgen/src/winmd/reader.rs | 20 ++------- crates/libs/bindgen/src/winmd/row.rs | 5 +++ crates/libs/bindgen/src/writer/cpp_handle.rs | 4 +- crates/libs/bindgen/src/writer/format.rs | 8 ++-- crates/libs/bindgen/src/writer/mod.rs | 15 ++++--- crates/libs/bindgen/src/writer/names.rs | 12 ++--- 33 files changed, 221 insertions(+), 205 deletions(-) delete mode 100644 crates/libs/bindgen/src/config.rs diff --git a/crates/libs/bindgen/src/config.rs b/crates/libs/bindgen/src/config.rs deleted file mode 100644 index b910095954..0000000000 --- a/crates/libs/bindgen/src/config.rs +++ /dev/null @@ -1,38 +0,0 @@ -use super::*; - -use std::sync::atomic::{AtomicPtr, Ordering}; - -static CONFIG: AtomicPtr = AtomicPtr::new(std::ptr::null_mut()); - -pub fn config() -> &'static Config { - let ptr = CONFIG.load(Ordering::Relaxed); - - if ptr.is_null() { - panic!(); - } else { - unsafe { &*ptr } - } -} - -pub struct Config { - pub types: TypeMap, - pub references: References, - pub output: String, - pub flat: bool, - pub no_allow: bool, - pub no_comment: bool, - pub no_core: bool, - pub no_toml: bool, - pub package: bool, - pub rustfmt: String, - pub sys: bool, - pub implement: bool, - pub derive: Derive, -} - -impl Config { - pub fn init(value: Self) { - let config = Box::leak(Box::new(value)); - CONFIG.store(config, Ordering::Relaxed); - } -} diff --git a/crates/libs/bindgen/src/derive.rs b/crates/libs/bindgen/src/derive.rs index 220c1fb937..6c94712e53 100644 --- a/crates/libs/bindgen/src/derive.rs +++ b/crates/libs/bindgen/src/derive.rs @@ -3,7 +3,7 @@ use super::*; pub struct Derive(HashMap>); impl Derive { - pub fn new(types: &TypeMap, derive: &[&str]) -> Self { + pub fn new(reader: &Reader, types: &TypeMap, derive: &[&str]) -> Self { let mut map = HashMap::new(); for derive in derive { @@ -11,7 +11,7 @@ impl Derive { panic!("`--derive` must be `=Comma,Separated,List"); }; - let tn = get_type_name(name); + let tn = get_type_name(reader, name); if !types.contains_key(&tn) { panic!("type not included: `{name}`"); @@ -33,15 +33,15 @@ impl Derive { } } -fn get_type_name(path: &str) -> TypeName { +fn get_type_name(reader: &Reader, path: &str) -> TypeName { if let Some((namespace, name)) = path.rsplit_once('.') { - if let Some((namespace, types)) = reader().get_key_value(namespace) { + if let Some((namespace, types)) = reader.get_key_value(namespace) { if let Some((name, _)) = types.get_key_value(name) { return TypeName(namespace, name); } } } else { - for (namespace, types) in reader().iter() { + for (namespace, types) in reader.iter() { if let Some((name, _)) = types.get_key_value(path) { return TypeName(namespace, name); } diff --git a/crates/libs/bindgen/src/derive_writer.rs b/crates/libs/bindgen/src/derive_writer.rs index bc15f6884d..63118f7b05 100644 --- a/crates/libs/bindgen/src/derive_writer.rs +++ b/crates/libs/bindgen/src/derive_writer.rs @@ -3,9 +3,9 @@ use super::*; pub struct DeriveWriter(BTreeSet); impl DeriveWriter { - pub fn new(type_name: TypeName) -> Self { + pub fn new(writer: &Writer, type_name: TypeName) -> Self { let mut derive = BTreeSet::new(); - derive.extend(config().derive.get(type_name)); + derive.extend(writer.config.derive.get(type_name)); Self(derive) } diff --git a/crates/libs/bindgen/src/filter.rs b/crates/libs/bindgen/src/filter.rs index 6472076408..6666e4d863 100644 --- a/crates/libs/bindgen/src/filter.rs +++ b/crates/libs/bindgen/src/filter.rs @@ -4,15 +4,15 @@ use super::*; pub struct Filter(Vec<(String, bool)>); impl Filter { - pub fn new(include: &[&str], exclude: &[&str]) -> Self { + pub fn new(reader: &Reader, include: &[&str], exclude: &[&str]) -> Self { let mut rules = vec![]; for filter in include { - push_filter(&mut rules, filter, true); + push_filter(reader, &mut rules, filter, true); } for filter in exclude { - push_filter(&mut rules, filter, false) + push_filter(reader, &mut rules, filter, false) } debug_assert!(!rules.is_empty()); @@ -68,9 +68,7 @@ impl Filter { } } -fn push_filter(rules: &mut Vec<(String, bool)>, filter: &str, include: bool) { - let reader = reader(); - +fn push_filter(reader: &Reader, rules: &mut Vec<(String, bool)>, filter: &str, include: bool) { if reader.contains_key(filter) { rules.push((filter.to_string(), include)); return; diff --git a/crates/libs/bindgen/src/lib.rs b/crates/libs/bindgen/src/lib.rs index ffeb934477..fd2d363d39 100644 --- a/crates/libs/bindgen/src/lib.rs +++ b/crates/libs/bindgen/src/lib.rs @@ -6,7 +6,6 @@ clippy::needless_doctest_main )] -mod config; mod derive; mod derive_writer; mod filter; @@ -25,7 +24,6 @@ mod value; mod winmd; mod writer; -use config::*; use derive::*; use derive_writer::*; use filter::*; @@ -49,6 +47,22 @@ use writer::*; mod method_names; use method_names::*; +struct Config { + pub types: TypeMap, + pub references: References, + pub output: String, + pub flat: bool, + pub no_allow: bool, + pub no_comment: bool, + pub no_core: bool, + pub no_toml: bool, + pub package: bool, + pub rustfmt: String, + pub sys: bool, + pub implement: bool, + pub derive: Derive, +} + /// The Windows code generator. #[track_caller] pub fn bindgen(args: I) @@ -145,13 +159,13 @@ where panic!("at least one `--filter` required"); } - Reader::init(expand_input(&input)); - let filter = Filter::new(&include, &exclude); - let references = References::new(references); - let types = TypeMap::filter(&filter, &references); - let derive = Derive::new(&types, &derive); + let reader = Reader::new(expand_input(&input)); + let filter = Filter::new(reader, &include, &exclude); + let references = References::new(reader, references); + let types = TypeMap::filter(reader, &filter, &references); + let derive = Derive::new(reader, &types, &derive); - Config::init(Config { + let config = Box::leak(Box::new(Config { types, flat, references, @@ -165,11 +179,16 @@ where output, sys, implement, - }); + })); - let writer = Writer { namespace: "" }; + let tree = TypeTree::new(&config.types); + + let writer = Writer { + config, + namespace: "", + }; - writer.write(TypeTree::new()) + writer.write(tree) } enum ArgKind { diff --git a/crates/libs/bindgen/src/libraries.rs b/crates/libs/bindgen/src/libraries.rs index a4041427e3..eaece2a530 100644 --- a/crates/libs/bindgen/src/libraries.rs +++ b/crates/libs/bindgen/src/libraries.rs @@ -9,10 +9,18 @@ pub enum CallingConvention { // Returns the libraries and their function and stack sizes used by the gnu and msvc tools to build the umbrella libs. #[doc(hidden)] pub fn libraries() -> BTreeMap> { - Reader::init(expand_input(&["default"])); - let mut result = BTreeMap::>::new(); + let mut libraries = BTreeMap::new(); - for types in reader().values() { + let reader = Reader::new(expand_input(&["default"])); + combine_libraries(reader, &mut libraries); + libraries +} + +fn combine_libraries( + reader: &Reader, + libraries: &mut BTreeMap>, +) { + for types in reader.values() { for ty in types.values() { let Some(ty) = cpp_fn(ty) else { continue; @@ -32,12 +40,12 @@ pub fn libraries() -> BTreeMap> { 0 }; - result + libraries .entry(library) .or_default() .insert(name, CallingConvention::Stdcall(params)); } else if flags.contains(PInvokeAttributes::CallConvCdecl) { - result + libraries .entry(library) .or_default() .insert(name, CallingConvention::Cdecl); @@ -46,8 +54,6 @@ pub fn libraries() -> BTreeMap> { } } } - - result } fn cpp_fn(types: &[Type]) -> Option { diff --git a/crates/libs/bindgen/src/references.rs b/crates/libs/bindgen/src/references.rs index fa869e22bb..7454a2dc97 100644 --- a/crates/libs/bindgen/src/references.rs +++ b/crates/libs/bindgen/src/references.rs @@ -68,13 +68,13 @@ pub struct Reference { pub struct References(Vec); impl References { - pub fn new(stage: Vec) -> Self { + pub fn new(reader: &'static Reader, stage: Vec) -> Self { Self( stage .into_iter() .map(|stage| { - let filter = Filter::new(&[&stage.path], &[]); - let types = TypeMap::filter(&filter, &References::default()); + let filter = Filter::new(reader, &[&stage.path], &[]); + let types = TypeMap::filter(reader, &filter, &References::default()); Reference { name: stage.name, diff --git a/crates/libs/bindgen/src/tables/attribute.rs b/crates/libs/bindgen/src/tables/attribute.rs index 48320bab3f..0b5d2e8679 100644 --- a/crates/libs/bindgen/src/tables/attribute.rs +++ b/crates/libs/bindgen/src/tables/attribute.rs @@ -29,7 +29,7 @@ impl Attribute { let ret_type = sig.read_usize(); std::debug_assert_eq!(ret_type, 1); let mut args = Vec::with_capacity(fixed_arg_count); - let reader = reader(); + let reader = self.reader(); for _ in 0..fixed_arg_count { let arg = match Type::from_blob(&mut sig, None, &[]) { diff --git a/crates/libs/bindgen/src/tables/method_def.rs b/crates/libs/bindgen/src/tables/method_def.rs index 3c5f30cb9a..6098bf253e 100644 --- a/crates/libs/bindgen/src/tables/method_def.rs +++ b/crates/libs/bindgen/src/tables/method_def.rs @@ -36,7 +36,6 @@ impl MethodDef { let _param_count = blob.read_usize(); let mut return_type = Type::from_blob(&mut blob, None, generics); let mut return_param = None; - let reader = reader(); let mut params = vec![]; @@ -62,7 +61,7 @@ impl MethodDef { if !param_is_output { if let Some(attribute) = param.find_attribute("AssociatedEnumAttribute") { if let Some((_, Value::Str(name))) = attribute.args().first() { - let overload = reader.unwrap_full_name(namespace, name); + let overload = param.reader().unwrap_full_name(namespace, name); ty = Type::PrimitiveOrEnum(Box::new(ty), Box::new(overload)); } diff --git a/crates/libs/bindgen/src/tables/type_def.rs b/crates/libs/bindgen/src/tables/type_def.rs index c1b34dc64c..f5bb1b59f3 100644 --- a/crates/libs/bindgen/src/tables/type_def.rs +++ b/crates/libs/bindgen/src/tables/type_def.rs @@ -81,7 +81,7 @@ impl TypeDef { if let Some(attribute) = self.find_attribute("RAIIFreeAttribute") { if let Some((_, Value::Str(name))) = attribute.args().first() { if let Some(Type::CppFn(ty)) = - reader().with_full_name(self.namespace(), name).next() + self.reader().with_full_name(self.namespace(), name).next() { return Some(ty); } diff --git a/crates/libs/bindgen/src/type_map.rs b/crates/libs/bindgen/src/type_map.rs index 87279d4c92..17fe42ae9c 100644 --- a/crates/libs/bindgen/src/type_map.rs +++ b/crates/libs/bindgen/src/type_map.rs @@ -17,9 +17,8 @@ impl TypeMap { } #[track_caller] - pub fn filter(filter: &Filter, references: &References) -> Self { + pub fn filter(reader: &'static Reader, filter: &Filter, references: &References) -> Self { let mut dependencies = Self::new(); - let reader = reader(); for namespace in reader.keys() { if filter.includes_namespace(namespace) { @@ -82,7 +81,7 @@ impl TypeMap { ) } - pub fn included(&self) -> bool { + pub fn included(&self, config: &Config) -> bool { self.0.iter().all(|(tn, _)| { // An empty namespace covers core types like `HRESULT`. This way we don't exclude methods // that depend on core types that aren't explicitly included in the filter. @@ -90,11 +89,11 @@ impl TypeMap { return true; } - if config().types.contains_key(tn) { + if config.types.contains_key(tn) { return true; } - if config().references.contains(*tn).is_some() { + if config.references.contains(*tn).is_some() { return true; } diff --git a/crates/libs/bindgen/src/type_tree.rs b/crates/libs/bindgen/src/type_tree.rs index 18b552cf6d..4d7b6f2812 100644 --- a/crates/libs/bindgen/src/type_tree.rs +++ b/crates/libs/bindgen/src/type_tree.rs @@ -9,10 +9,10 @@ pub struct TypeTree { } impl TypeTree { - pub fn new() -> Self { + pub fn new(dependencies: &TypeMap) -> Self { let mut tree = Self::with_namespace(""); - for (tn, types) in config().types.iter() { + for (tn, types) in dependencies.iter() { let tree = tree.insert_namespace(tn.namespace()); types.iter().for_each(|ty| { tree.types.insert(ty.clone()); diff --git a/crates/libs/bindgen/src/types/class.rs b/crates/libs/bindgen/src/types/class.rs index 94a03fbb0c..f5df2aa36c 100644 --- a/crates/libs/bindgen/src/types/class.rs +++ b/crates/libs/bindgen/src/types/class.rs @@ -17,7 +17,7 @@ impl Class { let name = to_ident(type_name.name()); let mut dependencies = TypeMap::new(); - if config().package { + if writer.config.package { self.dependencies(&mut dependencies); } @@ -38,7 +38,7 @@ impl Class { let mut virtual_names = MethodNames::new(); for method in interface - .get_methods() + .get_methods(writer) .iter() .filter_map(|method| match &method { MethodOrName::Method(method) => Some(method), @@ -47,7 +47,7 @@ impl Class { { let mut difference = TypeMap::new(); - if config().package { + if writer.config.package { difference = method.dependencies.difference(&dependencies); } @@ -253,7 +253,7 @@ impl Class { fn bases(&self) -> Vec { let mut bases = Vec::new(); let mut def = self.def; - let reader = reader(); + let reader = def.reader(); loop { let extends = def.extends().unwrap(); @@ -309,8 +309,6 @@ impl Class { walk(base.def, &[], true, &mut set); } - let reader = reader(); - for attribute in self.def.attributes() { let kind = match attribute.name() { "StaticAttribute" | "ActivatableAttribute" => InterfaceKind::Static, @@ -320,8 +318,10 @@ impl Class { for (_, arg) in attribute.args() { if let Value::TypeName(tn) = arg { - let Type::Interface(mut interface) = - reader.unwrap_full_name(tn.namespace(), tn.name()) + let Type::Interface(mut interface) = self + .def + .reader() + .unwrap_full_name(tn.namespace(), tn.name()) else { panic!("type not found: {tn}"); }; diff --git a/crates/libs/bindgen/src/types/cpp_const.rs b/crates/libs/bindgen/src/types/cpp_const.rs index 4ad6de2f0f..39782aa1f3 100644 --- a/crates/libs/bindgen/src/types/cpp_const.rs +++ b/crates/libs/bindgen/src/types/cpp_const.rs @@ -38,7 +38,7 @@ impl CppConst { let mut dependencies = TypeMap::new(); - if config().package { + if writer.config.package { self.dependencies(&mut dependencies); } @@ -52,7 +52,7 @@ impl CppConst { let crate_name = writer.write_core(); let value = constant.value().write(); - // TODO: if config().no_core then write these literals out as byte strings? + // TODO: if writer.config.no_core then write these literals out as byte strings? if is_ansi_encoding(self.field) { quote! { #cfg @@ -94,7 +94,7 @@ impl CppConst { value = quote! { #value as _ }; } - if config().sys || field_ty == Type::Bool { + if writer.config.sys || field_ty == Type::Bool { quote! { #cfg pub const #name: #ty = #value; diff --git a/crates/libs/bindgen/src/types/cpp_delegate.rs b/crates/libs/bindgen/src/types/cpp_delegate.rs index f89e2f68c4..c2f4cd6a89 100644 --- a/crates/libs/bindgen/src/types/cpp_delegate.rs +++ b/crates/libs/bindgen/src/types/cpp_delegate.rs @@ -49,7 +49,7 @@ impl CppDelegate { let mut dependencies = TypeMap::new(); - if config().package { + if writer.config.package { self.dependencies(&mut dependencies); } diff --git a/crates/libs/bindgen/src/types/cpp_enum.rs b/crates/libs/bindgen/src/types/cpp_enum.rs index 25c35ebbfc..91e95e88b6 100644 --- a/crates/libs/bindgen/src/types/cpp_enum.rs +++ b/crates/libs/bindgen/src/types/cpp_enum.rs @@ -30,17 +30,17 @@ impl CppEnum { let tn = self.def.type_name(); let is_scoped = self.def.has_attribute("ScopedEnumAttribute"); - if !is_scoped && config().sys { + if !is_scoped && writer.config.sys { return writer.write_cpp_handle(self.def); } let name = to_ident(tn.name()); let underlying_type = self.def.underlying_type().write_name(writer); - let mut derive = DeriveWriter::new(tn); + let mut derive = DeriveWriter::new(writer, tn); derive.extend(["Copy", "Clone"]); - if !config().sys { + if !writer.config.sys { derive.extend(["Default", "Debug", "PartialEq", "Eq"]); } @@ -67,7 +67,7 @@ impl CppEnum { quote! {} }; - let flags = if config().sys || !self.def.has_attribute("FlagsAttribute") { + let flags = if writer.config.sys || !self.def.has_attribute("FlagsAttribute") { quote! {} } else { quote! { @@ -127,7 +127,8 @@ impl CppEnum { pub fn dependencies(&self, dependencies: &mut TypeMap) { if let Some(attribute) = self.def.find_attribute("AlsoUsableForAttribute") { if let Some((_, Value::Str(type_name))) = attribute.args().first() { - reader() + self.def + .reader() .unwrap_full_name(self.def.namespace(), type_name) .dependencies(dependencies); } diff --git a/crates/libs/bindgen/src/types/cpp_fn.rs b/crates/libs/bindgen/src/types/cpp_fn.rs index a4d7ceeb8c..412b6423e2 100644 --- a/crates/libs/bindgen/src/types/cpp_fn.rs +++ b/crates/libs/bindgen/src/types/cpp_fn.rs @@ -62,12 +62,12 @@ impl CppFn { let return_sig = writer.write_return_sig(self.method, &signature, underlying_types); - let vararg = if config().sys && signature.call_flags.contains(MethodCallAttributes::VARARG) - { - quote! { , ... } - } else { - quote! {} - }; + let vararg = + if writer.config.sys && signature.call_flags.contains(MethodCallAttributes::VARARG) { + quote! { , ... } + } else { + quote! {} + }; link_fmt(quote! { windows_targets::link!(#library #abi #symbol fn #name(#(#params),* #vararg) #return_sig); @@ -79,14 +79,14 @@ impl CppFn { let signature = self.method.signature(self.namespace, &[]); let mut dependencies = TypeMap::new(); - if config().package { + if writer.config.package { self.dependencies(&mut dependencies); } let link = self.write_link(writer, false); let cfg = writer.write_cfg(self.method, self.namespace, &dependencies, false); let window_long = self.write_window_long(); - if config().sys { + if writer.config.sys { return quote! { #cfg #link @@ -278,7 +278,8 @@ impl CppFn { }; if let Some(dependency) = dependency { - reader() + self.method + .reader() .unwrap_full_name(self.namespace, dependency) .dependencies(dependencies); } diff --git a/crates/libs/bindgen/src/types/cpp_interface.rs b/crates/libs/bindgen/src/types/cpp_interface.rs index 1d2672d718..8a4427df04 100644 --- a/crates/libs/bindgen/src/types/cpp_interface.rs +++ b/crates/libs/bindgen/src/types/cpp_interface.rs @@ -28,14 +28,14 @@ impl CppInterface { self.def.type_name() } - pub fn get_methods(&self) -> Vec { + pub fn get_methods(&self, writer: &Writer) -> Vec { let namespace = self.def.namespace(); self.def .methods() .map(|def| { let method = CppMethod::new(def, namespace); - if method.dependencies.included() { + if method.dependencies.included(writer.config) { CppMethodOrName::Method(method) } else { CppMethodOrName::Name(method.def.name()) @@ -45,14 +45,14 @@ impl CppInterface { } pub fn write(&self, writer: &Writer) -> TokenStream { - let methods = self.get_methods(); + let methods = self.get_methods(writer); let base_interfaces = self.base_interfaces(); let has_unknown_base = matches!(base_interfaces.first(), Some(Type::IUnknown)); let mut dependencies = TypeMap::new(); - if config().package { + if writer.config.package { self.dependencies(&mut dependencies); } @@ -82,7 +82,7 @@ impl CppInterface { CppMethodOrName::Method(method) => { let mut difference = TypeMap::new(); - if config().package { + if writer.config.package { difference = method.dependencies.difference(&dependencies); } @@ -122,10 +122,10 @@ impl CppInterface { } }; - if config().sys { + if writer.config.sys { let mut result = quote! {}; - if !config().package { + if !writer.config.package { if has_unknown_base { if let Some(guid) = self.def.guid_attribute() { let name: TokenStream = format!("IID_{}", self.def.name()).into(); @@ -193,7 +193,7 @@ impl CppInterface { }) { let mut difference = TypeMap::new(); - if config().package { + if writer.config.package { difference = method.dependencies.difference(&dependencies); } @@ -220,19 +220,19 @@ impl CppInterface { let impl_name: TokenStream = format!("{}_Impl", self.def.name()).into(); - if config().package { - fn collect(interface: &CppInterface, dependencies: &mut TypeMap) { - for method in interface.get_methods().iter() { + if writer.config.package { + fn collect(interface: &CppInterface, dependencies: &mut TypeMap, writer: &Writer) { + for method in interface.get_methods(writer).iter() { if let CppMethodOrName::Method(method) = method { dependencies.combine(&method.dependencies); } } } - collect(self, &mut dependencies); + collect(self, &mut dependencies, writer); base_interfaces.iter().for_each(|interface| { if let Type::CppInterface(ty) = interface { - collect(ty, &mut dependencies); + collect(ty, &mut dependencies, writer); } }); } @@ -404,7 +404,7 @@ impl CppInterface { } pub fn write_name(&self, writer: &Writer) -> TokenStream { - if config().sys { + if writer.config.sys { quote! { *mut core::ffi::c_void } } else { self.type_name().write(writer, &[]) diff --git a/crates/libs/bindgen/src/types/cpp_struct.rs b/crates/libs/bindgen/src/types/cpp_struct.rs index fbaa061463..12bb5e1cf5 100644 --- a/crates/libs/bindgen/src/types/cpp_struct.rs +++ b/crates/libs/bindgen/src/types/cpp_struct.rs @@ -59,7 +59,7 @@ impl CppStruct { let mut dependencies = TypeMap::new(); - if config().package { + if writer.config.package { self.dependencies(&mut dependencies); } @@ -87,10 +87,10 @@ impl CppStruct { let fields = fields.iter().map(|(name, ty)| { let name = to_ident(name); - let ty = if !config().sys && is_union && !ty.is_copyable() { + let ty = if !writer.config.sys && is_union && !ty.is_copyable() { let ty = ty.write_default(writer); quote! { core::mem::ManuallyDrop<#ty> } - } else if !config().sys && ty.is_dropped() { + } else if !writer.config.sys && ty.is_dropped() { if let Type::ArrayFixed(ty, len) = ty { let ty = ty.write_default(writer); let len = Literal::usize_unsuffixed(*len); @@ -119,10 +119,10 @@ impl CppStruct { } }; - let mut derive = DeriveWriter::new(self.type_name()); + let mut derive = DeriveWriter::new(writer, self.type_name()); let mut manual_clone = None; - if config().sys || is_copyable { + if writer.config.sys || is_copyable { derive.extend(["Clone", "Copy"]); } else if !matches!( TypeName(self.def.namespace(), self.def.name()), @@ -142,11 +142,11 @@ impl CppStruct { } } - if !config().sys && !has_explicit_layout && !has_packing { + if !writer.config.sys && !has_explicit_layout && !has_packing { derive.extend(["Debug", "PartialEq"]); } - let default = if config().sys { + let default = if writer.config.sys { quote! {} } else { quote! { @@ -228,7 +228,8 @@ impl CppStruct { if let Some(attribute) = self.def.find_attribute("AlsoUsableForAttribute") { if let Some((_, Value::Str(type_name))) = attribute.args().first() { - reader() + self.def + .reader() .unwrap_full_name(self.def.namespace(), type_name) .dependencies(dependencies); } diff --git a/crates/libs/bindgen/src/types/delegate.rs b/crates/libs/bindgen/src/types/delegate.rs index 8639c4d470..ebf6c3929a 100644 --- a/crates/libs/bindgen/src/types/delegate.rs +++ b/crates/libs/bindgen/src/types/delegate.rs @@ -25,7 +25,7 @@ impl Delegate { let mut dependencies = TypeMap::new(); - if config().package { + if writer.config.package { self.dependencies(&mut dependencies); } diff --git a/crates/libs/bindgen/src/types/enum.rs b/crates/libs/bindgen/src/types/enum.rs index ab02dc9af5..423931d163 100644 --- a/crates/libs/bindgen/src/types/enum.rs +++ b/crates/libs/bindgen/src/types/enum.rs @@ -18,10 +18,10 @@ impl Enum { let name = to_ident(self.def.name()); let underlying_type = self.def.underlying_type(); - let mut derive = DeriveWriter::new(self.type_name()); + let mut derive = DeriveWriter::new(writer, self.type_name()); derive.extend(["Copy", "Clone"]); - if !config().sys { + if !writer.config.sys { derive.extend(["Default", "Debug", "PartialEq", "Eq"]); } @@ -38,7 +38,7 @@ impl Enum { } }); - let flags = if config().sys || underlying_type != Type::U32 { + let flags = if writer.config.sys || underlying_type != Type::U32 { quote! {} } else { quote! { @@ -81,7 +81,7 @@ impl Enum { let underlying_type = underlying_type.write_name(writer); - let win_traits = if config().sys { + let win_traits = if writer.config.sys { quote! {} } else { let signature = Literal::byte_string(&self.runtime_signature()); diff --git a/crates/libs/bindgen/src/types/interface.rs b/crates/libs/bindgen/src/types/interface.rs index 133c2e624d..c5243cdea5 100644 --- a/crates/libs/bindgen/src/types/interface.rs +++ b/crates/libs/bindgen/src/types/interface.rs @@ -53,12 +53,12 @@ impl Interface { self.def.type_name() } - pub fn get_methods(&self) -> Vec { + pub fn get_methods(&self, writer: &Writer) -> Vec { self.def .methods() .map(|def| { let method = Method::new(def, &self.generics); - if method.dependencies.included() { + if method.dependencies.included(writer.config) { MethodOrName::Method(method) } else { MethodOrName::Name(method.def.name()) @@ -69,7 +69,7 @@ impl Interface { pub fn write(&self, writer: &Writer) -> TokenStream { let type_name = self.def.type_name(); - let methods = self.get_methods(); + let methods = self.get_methods(writer); let mut required_interfaces = self.required_interfaces(); required_interfaces.sort(); @@ -84,7 +84,7 @@ impl Interface { let mut dependencies = TypeMap::new(); - if config().package { + if writer.config.package { self.dependencies(&mut dependencies); } @@ -98,7 +98,7 @@ impl Interface { MethodOrName::Method(method) => { let mut difference = TypeMap::new(); - if config().package { + if writer.config.package { difference = method.dependencies.difference(&dependencies); } @@ -139,10 +139,10 @@ impl Interface { } }; - if config().sys { + if writer.config.sys { let mut result = quote! {}; - if !config().package { + if !writer.config.package { if let Some(guid) = self.def.guid_attribute() { let name: TokenStream = format!("IID_{}", self.def.name()).into(); result.combine(writer.write_cpp_const_guid(name, &guid)); @@ -232,7 +232,7 @@ impl Interface { }) { let mut difference = TypeMap::new(); - if config().package { + if writer.config.package { difference = method.dependencies.difference(&dependencies); } @@ -257,7 +257,7 @@ impl Interface { for method in interface - .get_methods() + .get_methods(writer) .iter() .filter_map(|method| match &method { MethodOrName::Method(method) => Some(method), @@ -266,7 +266,7 @@ impl Interface { { let mut difference = TypeMap::new(); - if config().package { + if writer.config.package { difference = method.dependencies.difference(&dependencies); } @@ -340,7 +340,7 @@ impl Interface { } } - if config().implement || !is_exclusive { + if writer.config.implement || !is_exclusive { let impl_name: TokenStream = format!("{}_Impl", self.def.name()).into(); let generics: Vec<_> = self @@ -351,19 +351,19 @@ impl Interface { let runtime_name = format!("{type_name}"); - if config().package { - fn collect(interface: &Interface, dependencies: &mut TypeMap) { - for method in interface.get_methods().iter() { + if writer.config.package { + fn collect(interface: &Interface, dependencies: &mut TypeMap, writer: &Writer) { + for method in interface.get_methods(writer).iter() { if let MethodOrName::Method(method) = method { dependencies.combine(&method.dependencies); } } } - collect(self, &mut dependencies); + collect(self, &mut dependencies, writer); required_interfaces .iter() - .for_each(|interface| collect(interface, &mut dependencies)); + .for_each(|interface| collect(interface, &mut dependencies, writer)); } let cfg = writer.write_cfg(self.def, self.def.namespace(), &dependencies, false); @@ -509,7 +509,7 @@ impl Interface { } pub fn write_name(&self, writer: &Writer) -> TokenStream { - if config().sys { + if writer.config.sys { quote! { *mut core::ffi::c_void } } else { self.type_name().write(writer, &self.generics) diff --git a/crates/libs/bindgen/src/types/mod.rs b/crates/libs/bindgen/src/types/mod.rs index 3928604e8c..c52f8951a1 100644 --- a/crates/libs/bindgen/src/types/mod.rs +++ b/crates/libs/bindgen/src/types/mod.rs @@ -224,7 +224,8 @@ impl Type { } } - reader().unwrap_full_name(code_name.namespace(), code_name.name()) + code.reader() + .unwrap_full_name(code_name.namespace(), code_name.name()) } #[track_caller] @@ -297,7 +298,9 @@ impl Type { let code = blob.decode::(); let code_name = code.type_name(); - let mut ty = reader().unwrap_full_name(code_name.namespace(), code_name.name()); + let mut ty = blob + .reader() + .unwrap_full_name(code_name.namespace(), code_name.name()); let mut item_generics = vec![]; @@ -380,7 +383,7 @@ impl Type { quote! { #name BSTR } } Self::IUnknown => { - if config().sys { + if writer.config.sys { quote! { *mut core::ffi::c_void } } else { let name = writer.write_core(); @@ -400,7 +403,7 @@ impl Type { quote! { #name HSTRING } } Self::Object => { - if config().sys { + if writer.config.sys { quote! { *mut core::ffi::c_void } } else { let name = writer.write_core(); @@ -454,7 +457,7 @@ impl Type { Self::ArrayRef(ty) => ty.write_name(writer), Self::ConstRef(ty) => ty.write_name(writer), Self::PrimitiveOrEnum(primitive, ty) => { - if config().sys { + if writer.config.sys { primitive.write_name(writer) } else { ty.write_name(writer) @@ -472,7 +475,7 @@ impl Type { if matches!(self, Self::Param(_)) { quote! { <#tokens as windows_core::Type<#tokens>>::Default } - } else if self.is_interface() && !config().sys { + } else if self.is_interface() && !writer.config.sys { quote! { Option<#tokens> } } else { tokens @@ -493,7 +496,7 @@ impl Type { } pub fn write_abi(&self, writer: &Writer) -> TokenStream { - if config().sys { + if writer.config.sys { return self.write_default(writer); } @@ -570,11 +573,17 @@ impl Type { pub fn split_generic(&self) -> (Type, Vec) { match self { Self::Interface(ty) if !ty.generics.is_empty() => { - let base = reader().unwrap_full_name(ty.def.namespace(), ty.def.name()); + let base = ty + .def + .reader() + .unwrap_full_name(ty.def.namespace(), ty.def.name()); (base, ty.generics.clone()) } Self::Delegate(ty) if !ty.generics.is_empty() => { - let base = reader().unwrap_full_name(ty.def.namespace(), ty.def.name()); + let base = ty + .def + .reader() + .unwrap_full_name(ty.def.namespace(), ty.def.name()); (base, ty.generics.clone()) } _ => (self.clone(), vec![]), @@ -621,8 +630,16 @@ impl Type { } if let Some(multi) = match &ty { - Self::CppStruct(ty) => Some(reader().with_full_name(ty.def.namespace(), ty.def.name())), - Self::CppFn(ty) => Some(reader().with_full_name(ty.namespace, ty.method.name())), + Self::CppStruct(ty) => Some( + ty.def + .reader() + .with_full_name(ty.def.namespace(), ty.def.name()), + ), + Self::CppFn(ty) => Some( + ty.method + .reader() + .with_full_name(ty.namespace, ty.method.name()), + ), _ => None, } { multi.for_each(|multi| { @@ -837,8 +854,8 @@ impl Type { } impl Type { - fn write_no_deps(&self) -> TokenStream { - if !config().no_core { + fn write_no_deps(&self, writer: &Writer) -> TokenStream { + if !writer.config.no_core { return quote! {}; } @@ -906,7 +923,7 @@ impl Type { Self::Class(ty) => ty.write(writer), Self::CppInterface(ty) => ty.write(writer), - _ => self.write_no_deps(), + _ => self.write_no_deps(writer), } } diff --git a/crates/libs/bindgen/src/types/struct.rs b/crates/libs/bindgen/src/types/struct.rs index 735c9663e4..157ab87e08 100644 --- a/crates/libs/bindgen/src/types/struct.rs +++ b/crates/libs/bindgen/src/types/struct.rs @@ -25,14 +25,14 @@ impl Struct { let is_copyable = fields.iter().all(|(_, ty)| ty.is_copyable()); - let mut derive = DeriveWriter::new(self.type_name()); + let mut derive = DeriveWriter::new(writer, self.type_name()); derive.extend(["Clone"]); if is_copyable { derive.extend(["Copy"]); } - if !config().sys { + if !writer.config.sys { derive.extend(["Default", "Debug", "PartialEq"]); } @@ -42,7 +42,7 @@ impl Struct { quote! { pub #name: #ty, } }); - let win_traits = if config().sys { + let win_traits = if writer.config.sys { quote! {} } else { let type_kind = if is_copyable { diff --git a/crates/libs/bindgen/src/winmd/blob.rs b/crates/libs/bindgen/src/winmd/blob.rs index 7c82b493f0..53181950c5 100644 --- a/crates/libs/bindgen/src/winmd/blob.rs +++ b/crates/libs/bindgen/src/winmd/blob.rs @@ -18,6 +18,10 @@ impl Blob { Self { file, slice } } + pub fn reader(&self) -> &'static Reader { + self.file.reader() + } + fn peek(&self) -> (usize, usize) { if self[0] & 0x80 == 0 { (self[0] as usize, 1) diff --git a/crates/libs/bindgen/src/winmd/codes.rs b/crates/libs/bindgen/src/winmd/codes.rs index b755ceda5a..77d650487a 100644 --- a/crates/libs/bindgen/src/winmd/codes.rs +++ b/crates/libs/bindgen/src/winmd/codes.rs @@ -83,4 +83,12 @@ impl TypeDefOrRef { rest => panic!("{rest:?}"), } } + + pub fn reader(&self) -> &'static Reader { + match self { + Self::TypeDef(row) => row.reader(), + Self::TypeRef(row) => row.reader(), + Self::TypeSpec(row) => row.reader(), + } + } } diff --git a/crates/libs/bindgen/src/winmd/file.rs b/crates/libs/bindgen/src/winmd/file.rs index 63a670d5a8..7c707c83fb 100644 --- a/crates/libs/bindgen/src/winmd/file.rs +++ b/crates/libs/bindgen/src/winmd/file.rs @@ -1,6 +1,7 @@ use super::*; pub struct File { + pub(crate) reader: *const Reader, bytes: Vec, strings: usize, blobs: usize, @@ -45,6 +46,7 @@ impl File { pub fn new(bytes: Vec) -> Option { let mut result = File { bytes, + reader: std::ptr::null(), strings: 0, blobs: 0, tables: Default::default(), @@ -653,6 +655,11 @@ impl File { pub(crate) fn table(&'static self) -> RowIterator { RowIterator::new(self, 0..self.tables[R::TABLE].len) } + + pub(crate) fn reader(&self) -> &'static Reader { + // Safety: At this point the File is already pointing to a valid Reader. + unsafe { &*self.reader } + } } fn section_from_rva(sections: &[IMAGE_SECTION_HEADER], rva: u32) -> Option<&IMAGE_SECTION_HEADER> { diff --git a/crates/libs/bindgen/src/winmd/reader.rs b/crates/libs/bindgen/src/winmd/reader.rs index 060253f832..7a0facb9d1 100644 --- a/crates/libs/bindgen/src/winmd/reader.rs +++ b/crates/libs/bindgen/src/winmd/reader.rs @@ -1,17 +1,4 @@ use super::*; -use std::sync::atomic::{AtomicPtr, Ordering}; - -static READER: AtomicPtr = AtomicPtr::new(std::ptr::null_mut()); - -pub fn reader() -> &'static Reader { - let ptr = READER.load(Ordering::Relaxed); - - if ptr.is_null() { - panic!(); - } else { - unsafe { &*ptr } - } -} fn insert(types: &mut HashMap<&'static str, Vec>, name: &'static str, ty: Type) { types.entry(name).or_default().push(ty); @@ -28,10 +15,11 @@ impl std::ops::Deref for Reader { } impl Reader { - pub fn init(files: Vec) { + pub fn new(files: Vec) -> &'static Self { let reader = Box::leak(Box::new(Self(HashMap::new()))); - for file in files { + for mut file in files { + file.reader = reader; let file = Box::leak(Box::new(file)); let mut nested = HashMap::>::new(); @@ -179,7 +167,7 @@ impl Reader { } } - READER.store(reader, Ordering::Relaxed); + reader } #[track_caller] diff --git a/crates/libs/bindgen/src/winmd/row.rs b/crates/libs/bindgen/src/winmd/row.rs index afa72233a1..d965c1e2bb 100644 --- a/crates/libs/bindgen/src/winmd/row.rs +++ b/crates/libs/bindgen/src/winmd/row.rs @@ -21,6 +21,11 @@ pub trait AsRow: Copy { self.to_row().file } + fn reader(&self) -> &'static Reader { + // Safety: At this point the File is already pointing to a valid Reader. + unsafe { &*self.file().reader } + } + fn index(&self) -> usize { self.to_row().index } diff --git a/crates/libs/bindgen/src/writer/cpp_handle.rs b/crates/libs/bindgen/src/writer/cpp_handle.rs index 509eaccbcb..722f0b7495 100644 --- a/crates/libs/bindgen/src/writer/cpp_handle.rs +++ b/crates/libs/bindgen/src/writer/cpp_handle.rs @@ -7,7 +7,7 @@ impl Writer { let ty = def.underlying_type(); let ty_name = ty.write_name(self); - if config().sys { + if self.config.sys { quote! { pub type #name = #ty_name; } @@ -111,7 +111,7 @@ impl Writer { if let Some(attribute) = def.find_attribute("AlsoUsableForAttribute") { if let Some((_, Value::Str(type_name))) = attribute.args().first() { - let ty = reader().unwrap_full_name(def.namespace(), type_name); + let ty = def.reader().unwrap_full_name(def.namespace(), type_name); let ty = ty.write_name(self); diff --git a/crates/libs/bindgen/src/writer/format.rs b/crates/libs/bindgen/src/writer/format.rs index 402411845a..65bfa5a14e 100644 --- a/crates/libs/bindgen/src/writer/format.rs +++ b/crates/libs/bindgen/src/writer/format.rs @@ -3,7 +3,7 @@ use std::io::Write; impl Writer { pub fn format(&self, tokens: &str) -> String { - let preamble = if config().no_comment { + let preamble = if self.config.no_comment { String::new() } else { let version = std::env!("CARGO_PKG_VERSION"); @@ -16,7 +16,7 @@ impl Writer { ) }; - let allow = if config().no_allow { + let allow = if self.config.no_allow { "" } else { "#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]\n\n" @@ -28,9 +28,9 @@ impl Writer { cmd.stdout(std::process::Stdio::piped()); cmd.stderr(std::process::Stdio::null()); - if !config().rustfmt.is_empty() { + if !self.config.rustfmt.is_empty() { cmd.arg("--config"); - cmd.arg(&config().rustfmt); + cmd.arg(&self.config.rustfmt); } let Ok(mut child) = cmd.spawn() else { diff --git a/crates/libs/bindgen/src/writer/mod.rs b/crates/libs/bindgen/src/writer/mod.rs index e146df308c..cb0de64b03 100644 --- a/crates/libs/bindgen/src/writer/mod.rs +++ b/crates/libs/bindgen/src/writer/mod.rs @@ -9,6 +9,7 @@ use rayon::prelude::*; #[derive(Clone)] pub struct Writer { + pub config: &'static Config, pub namespace: &'static str, } @@ -21,7 +22,7 @@ impl Writer { #[track_caller] pub fn write(&self, tree: TypeTree) { - if config().package { + if self.config.package { self.write_package(&tree); } else { self.write_file(tree); @@ -30,13 +31,13 @@ impl Writer { #[track_caller] fn write_file(&self, tree: TypeTree) { - let tokens = if config().flat { + let tokens = if self.config.flat { self.write_flat(tree) } else { self.write_modules(&tree) }; - write_to_file(&config().output, self.format(&tokens.into_string())); + write_to_file(&self.config.output, self.format(&tokens.into_string())); } fn write_flat(&self, tree: TypeTree) -> TokenStream { @@ -67,7 +68,7 @@ impl Writer { fn write_package(&self, tree: &TypeTree) { for name in tree.nested.keys() { - _ = std::fs::remove_dir_all(format!("{}/src/{name}", &config().output)); + _ = std::fs::remove_dir_all(format!("{}/src/{name}", &self.config.output)); } let trees = tree.flatten_trees(); @@ -75,7 +76,7 @@ impl Writer { trees.par_iter().for_each(|tree| { let directory = format!( "{}/src/{}", - &config().output, + &self.config.output, tree.namespace.replace('.', "/") ); @@ -101,11 +102,11 @@ impl Writer { write_to_file(&output, self.format(&tokens.into_string())); }); - if config().no_toml { + if self.config.no_toml { return; } - let toml_path = format!("{}/Cargo.toml", &config().output); + let toml_path = format!("{}/Cargo.toml", &self.config.output); let mut toml = String::new(); for line in read_file_lines(&toml_path) { diff --git a/crates/libs/bindgen/src/writer/names.rs b/crates/libs/bindgen/src/writer/names.rs index 271cd71191..e222b547ff 100644 --- a/crates/libs/bindgen/src/writer/names.rs +++ b/crates/libs/bindgen/src/writer/names.rs @@ -2,10 +2,10 @@ use super::*; impl Writer { pub fn write_core(&self) -> TokenStream { - if config().sys { - if config().package || !config().no_core { + if self.config.sys { + if self.config.package || !self.config.no_core { quote! { windows_sys::core:: } - } else if config().flat { + } else if self.config.flat { quote! {} } else { let mut tokens = TokenStream::new(); @@ -56,10 +56,10 @@ impl Writer { } if let Some(reference) = { - if config().types.contains_key(&type_name) { + if self.config.types.contains_key(&type_name) { None } else { - config().references.contains(type_name) + self.config.references.contains(type_name) } } { tokens.push_str(&reference.name); @@ -82,7 +82,7 @@ impl Writer { tokens } else { - if config().flat || type_name.namespace() == self.namespace { + if self.config.flat || type_name.namespace() == self.namespace { return tokens; }