summaryrefslogtreecommitdiffstats
path: root/vendor/windows-bindgen/src/rdl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /vendor/windows-bindgen/src/rdl
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/windows-bindgen/src/rdl')
-rw-r--r--vendor/windows-bindgen/src/rdl/fmt.rs454
-rw-r--r--vendor/windows-bindgen/src/rdl/from_reader.rs435
-rw-r--r--vendor/windows-bindgen/src/rdl/mod.rs338
-rw-r--r--vendor/windows-bindgen/src/rdl/to_winmd.rs335
4 files changed, 1562 insertions, 0 deletions
diff --git a/vendor/windows-bindgen/src/rdl/fmt.rs b/vendor/windows-bindgen/src/rdl/fmt.rs
new file mode 100644
index 000000000..8b2df36aa
--- /dev/null
+++ b/vendor/windows-bindgen/src/rdl/fmt.rs
@@ -0,0 +1,454 @@
+use super::*;
+
+// TODO: should we use rustfmt in the short term (with pre/post)
+
+#[derive(Default)]
+pub struct Writer {
+ out: String,
+ indent: usize,
+ newline: bool,
+}
+
+impl Writer {
+ pub fn new(file: &rdl::File) -> Self {
+ let mut writer = Self::default();
+ writer.rdl_file(file);
+ writer
+ }
+
+ pub fn into_string(mut self) -> String {
+ self.out.push('\n');
+ self.out
+ }
+
+ fn word(&mut self, value: &str) {
+ if self.newline {
+ self.newline = false;
+ self.out.push('\n');
+ for _ in 0..self.indent {
+ self.out.push_str(" ");
+ }
+ }
+
+ self.out.push_str(value);
+ }
+
+ fn newline(&mut self) {
+ self.newline = true;
+ }
+
+ fn rdl_file(&mut self, file: &rdl::File) {
+ if file.winrt {
+ self.word("#![winrt]\n");
+ } else {
+ self.word("#![win32]\n");
+ }
+
+ self.newline();
+
+ for reference in &file.references {
+ self.item_use(reference);
+ }
+
+ for module in &file.modules {
+ self.rdl_module(module);
+ }
+ }
+
+ fn rdl_module(&mut self, module: &rdl::Module) {
+ self.word("mod ");
+ self.word(module.name());
+ self.word(" {");
+ self.newline();
+ self.indent += 1;
+
+ for member in &module.members {
+ self.rdl_module_member(member);
+ self.newline();
+ }
+
+ self.indent -= 1;
+ self.newline();
+ self.word("}");
+ self.newline();
+ }
+
+ fn rdl_module_member(&mut self, member: &rdl::ModuleMember) {
+ match member {
+ rdl::ModuleMember::Module(member) => self.rdl_module(member),
+ rdl::ModuleMember::Interface(member) => self.rdl_interface(member),
+ rdl::ModuleMember::Struct(member) => self.rdl_struct(member),
+ rdl::ModuleMember::Enum(member) => self.rdl_enum(member),
+ rdl::ModuleMember::Class(member) => self.rdl_class(member),
+ rdl::ModuleMember::Constant(member) => self.rdl_constant(member),
+ rdl::ModuleMember::Function(member) => self.rdl_function(member),
+ }
+ }
+
+ fn rdl_class(&mut self, member: &rdl::Class) {
+ self.attrs(&member.attributes);
+ self.word("class ");
+ self.word(&member.name);
+
+ if !member.extends.is_empty() || member.base.is_some() {
+ self.word(" : ");
+
+ if let Some(path) = &member.base {
+ self.word("class ");
+ self.type_path(path);
+
+ if !member.extends.is_empty() {
+ self.word(", ");
+ }
+ }
+
+ let mut first = true;
+ for path in &member.extends {
+ if first {
+ first = false;
+ } else {
+ self.word(", ");
+ }
+ self.type_path(path);
+ }
+ }
+
+ self.word(";");
+ self.newline();
+ }
+
+ fn rdl_interface(&mut self, member: &rdl::Interface) {
+ self.attrs(&member.attributes);
+ self.word("interface ");
+ self.word(&member.name);
+
+ if !member.generics.is_empty() {
+ self.word("<");
+
+ let mut first = true;
+ for generic in &member.generics {
+ if first {
+ first = false;
+ } else {
+ self.word(", ");
+ }
+ self.word(generic);
+ }
+
+ self.word(">");
+ }
+
+ if !member.extends.is_empty() {
+ self.word(" : ");
+
+ let mut first = true;
+ for path in &member.extends {
+ if first {
+ first = false;
+ } else {
+ self.word(", ");
+ }
+ self.type_path(path);
+ }
+ }
+
+ self.word(" {");
+ self.newline();
+ self.indent += 1;
+
+ for method in &member.methods {
+ self.trait_item_fn(method);
+ self.word(";");
+ self.newline();
+ }
+
+ self.indent -= 1;
+ self.newline();
+ self.word("}");
+ }
+
+ fn rdl_constant(&mut self, member: &rdl::Constant) {
+ self.item_const(&member.item);
+ }
+
+ fn rdl_function(&mut self, member: &rdl::Function) {
+ self.trait_item_fn(&member.item);
+ self.word(";");
+ self.newline();
+ }
+
+ fn item_const(&mut self, item: &syn::ItemConst) {
+ self.word("const ");
+ self.ident(&item.ident);
+ self.word(": ");
+ self.ty(&item.ty);
+ self.word(" = ");
+ self.expr(&item.expr);
+ self.word(";");
+ self.newline();
+ }
+
+ fn attrs(&mut self, attrs: &[syn::Attribute]) {
+ for attr in attrs {
+ self.attr(attr);
+ }
+ }
+
+ fn attr(&mut self, attr: &syn::Attribute) {
+ self.word("#[");
+ self.meta(&attr.meta);
+ self.word("]");
+ self.newline();
+ }
+
+ fn meta(&mut self, meta: &syn::Meta) {
+ match meta {
+ syn::Meta::Path(path) => self.path(path),
+ syn::Meta::List(list) => self.meta_list(list),
+ syn::Meta::NameValue(meta) => self.meta_name_value(meta),
+ }
+ }
+
+ fn meta_list(&mut self, meta_list: &syn::MetaList) {
+ self.path(&meta_list.path);
+ self.word("(");
+ self.word(&meta_list.tokens.to_string());
+ self.word(")");
+ }
+
+ fn meta_name_value(&mut self, meta: &syn::MetaNameValue) {
+ self.path(&meta.path);
+ self.word(" = ");
+ self.expr(&meta.value);
+ }
+
+ fn rdl_struct(&mut self, member: &rdl::Struct) {
+ self.attrs(&member.attributes);
+
+ self.word("struct ");
+ self.word(&member.name);
+ self.word(" {");
+ self.newline();
+ self.indent += 1;
+
+ for field in &member.fields {
+ self.word(&field.name);
+ self.word(": ");
+ self.ty(&field.ty);
+ self.word(",");
+ self.newline();
+ }
+
+ self.indent -= 1;
+ self.newline();
+ self.word("}");
+ }
+
+ fn rdl_enum(&mut self, member: &rdl::Enum) {
+ self.attrs(&member.item.attrs);
+
+ self.word("enum ");
+ self.ident(&member.item.ident);
+ self.word(" {");
+ self.newline();
+ self.indent += 1;
+
+ for variant in &member.item.variants {
+ self.ident(&variant.ident);
+ if let Some((_, expr)) = &variant.discriminant {
+ self.word(" = ");
+ self.expr(expr);
+ }
+ self.word(",");
+ self.newline();
+ }
+
+ self.indent -= 1;
+ self.newline();
+ self.word("}");
+ }
+
+ fn trait_item_fn(&mut self, method: &syn::TraitItemFn) {
+ self.attrs(&method.attrs);
+ self.signature(&method.sig);
+ }
+
+ fn signature(&mut self, signature: &syn::Signature) {
+ self.word("fn ");
+ self.ident(&signature.ident);
+ self.word("(");
+
+ let mut first = true;
+ for input in &signature.inputs {
+ if first {
+ first = false;
+ } else {
+ self.word(", ");
+ }
+ self.fn_arg(input);
+ }
+
+ self.word(")");
+
+ if let syn::ReturnType::Type(_, ty) = &signature.output {
+ self.word(" -> ");
+ self.ty(ty);
+ }
+ }
+
+ fn fn_arg(&mut self, fn_arg: &syn::FnArg) {
+ if let syn::FnArg::Typed(pat_type) = fn_arg {
+ self.pat_type(pat_type);
+ }
+ }
+
+ fn pat_type(&mut self, pat_type: &syn::PatType) {
+ self.pat(&pat_type.pat);
+ self.word(": ");
+ self.ty(&pat_type.ty);
+ }
+
+ fn pat(&mut self, pat: &syn::Pat) {
+ match pat {
+ syn::Pat::Ident(pat_ident) => self.pat_ident(pat_ident),
+ rest => unimplemented!("{rest:?}"),
+ }
+ }
+
+ fn pat_ident(&mut self, pat_ident: &syn::PatIdent) {
+ self.ident(&pat_ident.ident);
+ }
+
+ fn ty(&mut self, ty: &syn::Type) {
+ match ty {
+ syn::Type::Path(ty) => self.type_path(ty),
+ syn::Type::Ptr(ptr) => self.type_ptr(ptr),
+ syn::Type::Array(array) => self.type_array(array),
+ rest => unimplemented!("{rest:?}"),
+ }
+ }
+
+ fn type_array(&mut self, array: &syn::TypeArray) {
+ self.word("[");
+ self.ty(&array.elem);
+ self.word("; ");
+ self.expr(&array.len);
+ self.word("]");
+ }
+
+ fn expr(&mut self, expr: &syn::Expr) {
+ match expr {
+ syn::Expr::Lit(lit) => self.expr_lit(lit),
+ syn::Expr::Unary(unary) => self.expr_unary(unary),
+ rest => unimplemented!("{rest:?}"),
+ }
+ }
+
+ fn expr_unary(&mut self, unary: &syn::ExprUnary) {
+ self.word("-");
+ self.expr(&unary.expr);
+ }
+
+ fn expr_lit(&mut self, expr: &syn::ExprLit) {
+ self.lit(&expr.lit);
+ }
+
+ fn lit(&mut self, lit: &syn::Lit) {
+ match lit {
+ syn::Lit::Int(lit) => self.lit_int(lit),
+ syn::Lit::Str(lit) => self.lit_str(lit),
+ _ => _ = dbg!(lit),
+ }
+ }
+
+ fn lit_str(&mut self, lit: &syn::LitStr) {
+ self.word("\"");
+ self.word(&lit.value());
+ self.word("\"");
+ }
+
+ fn lit_int(&mut self, lit: &syn::LitInt) {
+ self.word(&lit.token().to_string());
+ }
+
+ fn type_ptr(&mut self, ptr: &syn::TypePtr) {
+ if ptr.mutability.is_some() {
+ self.word("*mut ");
+ } else {
+ self.word("*const ");
+ }
+ self.ty(&ptr.elem);
+ }
+
+ fn type_path(&mut self, ty: &syn::TypePath) {
+ self.path(&ty.path);
+ }
+
+ fn path(&mut self, path: &syn::Path) {
+ let mut first = true;
+ for segment in &path.segments {
+ if first {
+ first = false;
+ } else {
+ self.word("::");
+ }
+ self.path_segment(segment);
+ }
+ }
+
+ pub fn path_segment(&mut self, segment: &syn::PathSegment) {
+ self.ident(&segment.ident);
+
+ if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
+ self.word("<");
+
+ let mut first = true;
+ for arg in &args.args {
+ if first {
+ first = false;
+ } else {
+ self.word(", ");
+ }
+ self.generic_argument(arg);
+ }
+
+ self.word(">");
+ }
+ }
+
+ fn generic_argument(&mut self, arg: &syn::GenericArgument) {
+ match arg {
+ syn::GenericArgument::Type(ty) => self.ty(ty),
+ rest => unimplemented!("{rest:?}"),
+ }
+ }
+
+ fn item_use(&mut self, item: &syn::ItemUse) {
+ self.word("use ");
+ self.use_tree(&item.tree);
+ self.word(";");
+ self.newline();
+ }
+
+ fn use_tree(&mut self, use_tree: &syn::UseTree) {
+ match use_tree {
+ syn::UseTree::Path(use_path) => self.use_path(use_path),
+ syn::UseTree::Name(use_name) => self.use_name(use_name),
+ _ => {}
+ }
+ }
+
+ fn use_path(&mut self, use_path: &syn::UsePath) {
+ self.ident(&use_path.ident);
+ self.word("::");
+ self.use_tree(&use_path.tree);
+ }
+
+ fn use_name(&mut self, use_name: &syn::UseName) {
+ self.ident(&use_name.ident);
+ }
+
+ pub fn ident(&mut self, ident: &syn::Ident) {
+ self.word(&ident.to_string());
+ }
+}
diff --git a/vendor/windows-bindgen/src/rdl/from_reader.rs b/vendor/windows-bindgen/src/rdl/from_reader.rs
new file mode 100644
index 000000000..136430a9a
--- /dev/null
+++ b/vendor/windows-bindgen/src/rdl/from_reader.rs
@@ -0,0 +1,435 @@
+use super::*;
+use crate::tokens::{quote, to_ident, TokenStream};
+use crate::{rdl, Error, Result, Tree};
+use metadata::RowReader;
+
+pub fn from_reader(reader: &metadata::Reader, filter: &metadata::Filter, 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);
+
+ // 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
+ // at different nesting levels.
+ writer.split = config.remove("split").is_some();
+
+ if let Some((key, _)) = config.first_key_value() {
+ return Err(Error::new(&format!("invalid configuration value `{key}`")));
+ }
+
+ if writer.split {
+ gen_split(&writer)
+ } else {
+ gen_file(&writer)
+ }
+}
+
+fn gen_split(writer: &Writer) -> Result<()> {
+ let tree = Tree::new(writer.reader, writer.filter);
+ let directory = crate::directory(writer.output);
+
+ // TODO: parallelize
+ for tree in tree.flatten() {
+ let tokens = writer.tree(tree);
+
+ if !tokens.is_empty() {
+ let output = format!("{directory}/{}.rdl", tree.namespace);
+ writer.write_to_file(&output, tokens)?;
+ }
+ }
+
+ Ok(())
+}
+
+fn gen_file(writer: &Writer) -> Result<()> {
+ let tree = Tree::new(writer.reader, writer.filter);
+ let tokens = writer.tree(&tree);
+ writer.write_to_file(writer.output, tokens)
+}
+
+#[derive(Debug, Copy, Clone, PartialEq)]
+enum Dialect {
+ Win32,
+ WinRT,
+}
+
+struct Writer<'a> {
+ reader: &'a metadata::Reader<'a>,
+ 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 with_namespace(&self, namespace: &'a str) -> Self {
+ Self { reader: self.reader, filter: self.filter, namespace, dialect: self.dialect, output: self.output, split: self.split }
+ }
+
+ fn write_to_file(&self, output: &str, tokens: TokenStream) -> Result<()> {
+ let dialect = match self.dialect {
+ Dialect::Win32 => quote! { #![win32] },
+ Dialect::WinRT => quote! { #![winrt] },
+ };
+
+ let tokens = quote! {
+ #dialect
+ #tokens
+ };
+
+ let file = rdl::File::parse_str(&tokens.into_string())?;
+ crate::write_to_file(output, file.fmt())
+ //crate::write_to_file(output, tokens.into_string())
+ }
+
+ fn tree(&self, tree: &'a Tree) -> TokenStream {
+ let items = self.items(tree);
+
+ if self.split {
+ let mut tokens = items;
+
+ if !tokens.is_empty() {
+ for name in tree.namespace.rsplit('.').map(to_ident) {
+ tokens = quote! {
+ mod #name {
+ #tokens
+ }
+ };
+ }
+ }
+
+ tokens
+ } else {
+ let name = to_ident(tree.namespace.rsplit_once('.').map_or(tree.namespace, |(_, name)| name));
+
+ let modules = tree.nested.values().map(|tree| self.with_namespace(tree.namespace).tree(tree));
+
+ if tree.namespace.is_empty() {
+ quote! {
+ #(#modules)*
+ #items
+ }
+ } else {
+ quote! {
+ mod #name {
+ #(#modules)*
+ #items
+ }
+ }
+ }
+ }
+ }
+
+ fn items(&self, tree: &'a Tree) -> TokenStream {
+ let mut functions = vec![];
+ let mut constants = vec![];
+ let mut types = vec![];
+
+ if !tree.namespace.is_empty() {
+ for item in self.reader.namespace_items(tree.namespace, self.filter).filter(|item| match item {
+ metadata::Item::Type(def) => {
+ let winrt = self.reader.type_def_flags(*def).contains(metadata::TypeAttributes::WindowsRuntime);
+ match self.dialect {
+ Dialect::Win32 => !winrt,
+ Dialect::WinRT => winrt,
+ }
+ }
+ metadata::Item::Fn(_, _) | metadata::Item::Const(_) => self.dialect == Dialect::Win32,
+ }) {
+ match item {
+ metadata::Item::Type(def) => types.push(self.type_def(def)),
+ metadata::Item::Const(field) => constants.push(self.constant(field)),
+ metadata::Item::Fn(method, namespace) => functions.push(self.function(method, &namespace)),
+ }
+ }
+ }
+
+ quote! {
+ #(#functions)*
+ #(#constants)*
+ #(#types)*
+ }
+ }
+
+ fn function(&self, def: metadata::MethodDef, _namespace: &str) -> TokenStream {
+ let name = to_ident(self.reader.method_def_name(def));
+ quote! { fn #name(); }
+ }
+
+ fn constant(&self, def: metadata::Field) -> TokenStream {
+ let name = to_ident(self.reader.field_name(def));
+ quote! { const #name: i32 = 0; }
+ }
+
+ fn type_def(&self, def: metadata::TypeDef) -> TokenStream {
+ if let Some(extends) = self.reader.type_def_extends(def) {
+ if extends.namespace == "System" {
+ if extends.name == "Enum" {
+ self.enum_def(def)
+ } else if extends.name == "ValueType" {
+ self.struct_def(def)
+ } else if extends.name == "MulticastDelegate" {
+ self.delegate_def(def)
+ } else {
+ self.class_def(def)
+ }
+ } else {
+ self.class_def(def)
+ }
+ } else {
+ self.interface_def(def)
+ }
+ }
+
+ fn enum_def(&self, def: metadata::TypeDef) -> TokenStream {
+ let name = to_ident(self.reader.type_def_name(def));
+
+ quote! {
+ struct #name {
+
+ }
+ }
+ }
+
+ fn struct_def(&self, def: metadata::TypeDef) -> TokenStream {
+ let name = to_ident(self.reader.type_def_name(def));
+
+ let fields = self.reader.type_def_fields(def).map(|field| {
+ let name = to_ident(self.reader.field_name(field));
+ let ty = self.ty(&self.reader.field_type(field, Some(def)));
+ quote! {
+ #name: #ty
+ }
+ });
+
+ quote! {
+ struct #name {
+ #(#fields),*
+ }
+ }
+ }
+
+ fn delegate_def(&self, def: metadata::TypeDef) -> TokenStream {
+ let name = to_ident(self.reader.type_def_name(def));
+
+ quote! {
+ struct #name {
+
+ }
+ }
+ }
+
+ fn class_def(&self, def: metadata::TypeDef) -> TokenStream {
+ let name = to_ident(self.reader.type_def_name(def));
+ let implements = self.implements(def, &[]);
+
+ quote! {
+ class #name #implements;
+ }
+ }
+
+ fn interface_def(&self, def: metadata::TypeDef) -> TokenStream {
+ let name = to_ident(self.reader.type_def_name(def));
+ let generics = &metadata::type_def_generics(self.reader, def);
+ let implements = self.implements(def, generics);
+
+ let methods = self.reader.type_def_methods(def).map(|method| {
+ let name = to_ident(self.reader.method_def_name(method));
+
+ // TODO: use reader.method_def_signature instead
+ let signature = metadata::method_def_signature(self.reader, self.reader.type_def_namespace(def), method, generics);
+
+ let return_type = self.return_type(&signature.return_type);
+
+ let params = signature.params.iter().map(|param| {
+ let name = to_ident(self.reader.param_name(param.def));
+ let ty = self.ty(&param.ty);
+ quote! { #name: #ty }
+ });
+
+ quote! {
+ fn #name(#(#params),*) #return_type;
+ }
+ });
+
+ let generics = self.generics(generics);
+
+ quote! {
+ interface #name #generics #implements {
+ #(#methods)*
+ }
+ }
+ }
+
+ fn generics(&self, generics: &[metadata::Type]) -> TokenStream {
+ if generics.is_empty() {
+ quote! {}
+ } else {
+ let generics = generics.iter().map(|generic| self.ty(generic));
+
+ quote! { <#(#generics),*>}
+ }
+ }
+
+ fn implements(&self, def: metadata::TypeDef, generics: &[metadata::Type]) -> TokenStream {
+ let mut types = Vec::<TokenStream>::new();
+
+ // TODO: if a winrt composable class then start with base
+ // TODO: then list default interface first
+ // Then everything else
+
+ for imp in self.reader.type_def_interface_impls(def) {
+ let ty = self.reader.interface_impl_type(imp, generics);
+ if self.reader.has_attribute(imp, "DefaultAttribute") {
+ types.insert(0, self.ty(&ty));
+ } else {
+ types.push(self.ty(&ty));
+ }
+ }
+
+ if let Some(type_name) = self.reader.type_def_extends(def) {
+ if type_name != metadata::TypeName::Object {
+ let namespace = self.namespace(type_name.namespace);
+ let name = to_ident(type_name.name);
+ // TODO: ideally the "class" contextual keyword wouldn't be needed here
+ // but currently there's no way to tell the base class apart from a required interface.
+ types.insert(0, quote! { class #namespace #name });
+ }
+ }
+
+ if types.is_empty() {
+ quote! {}
+ } else {
+ quote! { : #(#types),* }
+ }
+ }
+
+ fn return_type(&self, ty: &metadata::Type) -> TokenStream {
+ match ty {
+ metadata::Type::Void => quote! {},
+ _ => {
+ let ty = self.ty(ty);
+ quote! { -> #ty }
+ }
+ }
+ }
+
+ fn ty(&self, ty: &metadata::Type) -> TokenStream {
+ match ty {
+ metadata::Type::Void => quote! { ::core::ffi::c_void },
+ metadata::Type::Bool => quote! { bool },
+ metadata::Type::Char => quote! { u16 },
+ metadata::Type::I8 => quote! { i8 },
+ metadata::Type::U8 => quote! { u8 },
+ metadata::Type::I16 => quote! { i16 },
+ metadata::Type::U16 => quote! { u16 },
+ metadata::Type::I32 => quote! { i32 },
+ metadata::Type::U32 => quote! { u32 },
+ metadata::Type::I64 => quote! { i64 },
+ metadata::Type::U64 => quote! { u64 },
+ metadata::Type::F32 => quote! { f32 },
+ metadata::Type::F64 => quote! { f64 },
+ metadata::Type::ISize => quote! { isize },
+ metadata::Type::USize => quote! { usize },
+
+ // TODO: dialect-specific keywords for "well-known types" that don't map to metadata in all cases.
+ metadata::Type::String => quote! { HSTRING },
+ metadata::Type::HRESULT => quote! { HRESULT },
+ metadata::Type::GUID => quote! { GUID },
+ metadata::Type::IInspectable => quote! { IInspectable },
+ metadata::Type::IUnknown => quote! { IUnknown },
+
+ metadata::Type::TypeDef(def, generics) => {
+ let namespace = self.namespace(self.reader.type_def_namespace(*def));
+ let name = to_ident(self.reader.type_def_name(*def));
+ if generics.is_empty() {
+ quote! { #namespace #name }
+ } else {
+ let generics = generics.iter().map(|ty| self.ty(ty));
+ quote! { #namespace #name<#(#generics,)*> }
+ }
+ }
+
+ metadata::Type::TypeRef(code) => {
+ let type_name = self.reader.type_def_or_ref(*code);
+ let namespace = self.namespace(type_name.namespace);
+ let name = to_ident(type_name.name);
+ quote! { #namespace #name }
+ }
+
+ metadata::Type::GenericParam(generic) => self.reader.generic_param_name(*generic).into(),
+ metadata::Type::WinrtArray(ty) => self.ty(ty),
+ metadata::Type::WinrtArrayRef(ty) => self.ty(ty),
+ metadata::Type::ConstRef(ty) => self.ty(ty),
+ metadata::Type::MutPtr(ty, _pointers) => self.ty(ty),
+ metadata::Type::ConstPtr(ty, _pointers) => self.ty(ty),
+ metadata::Type::Win32Array(ty, _len) => self.ty(ty),
+ // TODO: these types should just be regular metadata type defs
+ metadata::Type::PSTR => quote! { PSTR },
+ metadata::Type::PWSTR => quote! { PWSTR },
+ metadata::Type::PCSTR => quote! { PCSTR },
+ metadata::Type::PCWSTR => quote! { PCWSTR },
+ metadata::Type::BSTR => quote! { BSTR },
+ metadata::Type::PrimitiveOrEnum(_, ty) => self.ty(ty),
+ rest => unimplemented!("{rest:?}"),
+ }
+ }
+
+ fn namespace(&self, namespace: &str) -> TokenStream {
+ // TODO: handle nested structs?
+ if namespace.is_empty() || self.namespace == namespace {
+ quote! {}
+ } else {
+ // TODO: problem with making relative paths here is that we don't have the context to disambiguate
+
+ // let mut relative = self.namespace.split('.').peekable();
+ // let mut namespace = namespace.split('.').peekable();
+ // let mut related = false;
+
+ // while relative.peek() == namespace.peek() {
+ // related = true;
+
+ // if relative.next().is_none() {
+ // break;
+ // }
+
+ // namespace.next();
+ // }
+
+ // let mut tokens = TokenStream::new();
+
+ // if related {
+ // for _ in 0..relative.count() {
+ // tokens.push_str("super::");
+ // }
+ // }
+
+ // for namespace in namespace {
+ // tokens.push_str(namespace);
+ // tokens.push_str("::");
+ // }
+
+ // tokens
+
+ // TODO: so instead we just gen it out in full
+
+ let mut tokens = TokenStream::new();
+
+ for namespace in namespace.split('.') {
+ tokens.push_str(namespace);
+ tokens.push_str("::");
+ }
+
+ tokens
+ }
+ }
+}
diff --git a/vendor/windows-bindgen/src/rdl/mod.rs b/vendor/windows-bindgen/src/rdl/mod.rs
new file mode 100644
index 000000000..6cabb168b
--- /dev/null
+++ b/vendor/windows-bindgen/src/rdl/mod.rs
@@ -0,0 +1,338 @@
+use super::*;
+mod fmt;
+mod from_reader;
+mod to_winmd;
+use crate::Result;
+pub use from_reader::from_reader;
+use syn::spanned::Spanned;
+
+// TODO: may want to finally get rid of `syn` as it also doesn't support preserving code comments
+
+impl File {
+ pub fn parse_str(input: &str) -> Result<Self> {
+ Ok(syn::parse_str::<Self>(input)?)
+ }
+
+ // Note: this isn't called automatically by `parse_str` to avoid canonicalizing when we're merely formatting IDL.
+ pub fn canonicalize(&mut self) -> Result<()> {
+ // TODO maybe we rewrite the `File` here to resolve any `super` references and use declarations so that
+ // subsequently the rdl-to-winmd conversion can just assume everything's fully qualified?
+ // * super can't refer to something outside of the IDL file
+ // * use declarations are only used for unqualified names that aren't defined in the IDL file
+ // * use declarations don't support globs and must name all externally defined types
+ // This way we can quickly kick out common invalid IDL files before we lost file/span context info
+
+ Ok(())
+ }
+
+ pub fn fmt(&self) -> String {
+ fmt::Writer::new(self).into_string()
+ }
+
+ pub fn into_winmd(mut self) -> Result<Vec<u8>> {
+ self.canonicalize()?;
+ to_winmd::rdl_to_winmd(&self)
+ }
+}
+
+// The value of the IDL-specific memory representation is that it allows for constructs that are not modeled in the abstract Module
+// tree such as the use declarations and if we get rid of it we'd always "format" IDL by stripping out any of that into a single
+// canonical form which would not be very friendly to developers.
+#[derive(Debug)]
+pub struct File {
+ pub winrt: bool,
+ pub references: Vec<syn::ItemUse>,
+ pub modules: Vec<Module>,
+}
+
+// TODO: need to change these to unpack the syn types and store strings we can reference for efficiency along with spans since the syn
+// is made for value semantics.
+
+#[derive(Clone, Debug)]
+pub struct Module {
+ pub namespace: String,
+ pub members: Vec<ModuleMember>,
+}
+
+#[derive(Clone, Debug)]
+pub enum ModuleMember {
+ Module(Module),
+ Interface(Interface),
+ Struct(Struct),
+ Enum(Enum),
+ Class(Class),
+ Function(Function),
+ Constant(Constant),
+}
+
+impl ModuleMember {
+ pub fn name(&self) -> &str {
+ match self {
+ Self::Module(module) => crate::extension(&module.namespace),
+ Self::Interface(member) => &member.name,
+ Self::Struct(member) => &member.name,
+ Self::Enum(member) => &member.name,
+ Self::Class(member) => &member.name,
+ Self::Function(member) => &member.name,
+ Self::Constant(member) => &member.name,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct Enum {
+ pub winrt: bool,
+ pub name: String,
+ pub item: syn::ItemEnum,
+}
+
+#[derive(Clone, Debug)]
+pub struct Constant {
+ pub name: String,
+ pub item: syn::ItemConst,
+}
+
+#[derive(Clone, Debug)]
+pub struct Struct {
+ pub winrt: bool,
+ pub name: String,
+ pub attributes: Vec<syn::Attribute>,
+ pub span: proc_macro2::Span,
+ pub fields: Vec<Field>,
+}
+
+#[derive(Clone, Debug)]
+pub struct Field {
+ pub name: String,
+ pub attributes: Vec<syn::Attribute>,
+ pub span: proc_macro2::Span,
+ pub ty: syn::Type,
+}
+
+#[derive(Clone, Debug)]
+pub struct Class {
+ pub name: String,
+ pub attributes: Vec<syn::Attribute>,
+ pub base: Option<syn::TypePath>,
+ pub extends: Vec<syn::TypePath>,
+}
+
+#[derive(Clone, Debug)]
+pub struct Function {
+ pub name: String,
+ pub item: syn::TraitItemFn,
+}
+
+#[derive(Clone, Debug)]
+pub struct Interface {
+ pub winrt: bool,
+ pub name: String,
+ pub generics: Vec<String>,
+ pub attributes: Vec<syn::Attribute>,
+ pub extends: Vec<syn::TypePath>,
+ pub methods: Vec<syn::TraitItemFn>,
+}
+
+syn::custom_keyword!(interface);
+syn::custom_keyword!(class);
+
+fn winrt(input: syn::parse::ParseStream) -> syn::Result<bool> {
+ let attributes = input.call(syn::Attribute::parse_inner)?;
+ if attributes.len() == 1 {
+ if let syn::Meta::Path(path) = &attributes[0].meta {
+ if path.is_ident("winrt") {
+ return Ok(true);
+ }
+
+ if path.is_ident("win32") {
+ return Ok(false);
+ }
+ }
+ }
+
+ Err(syn::Error::new(input.span(), "A single `#![win32]` or `#![winrt]` attribute required"))
+}
+
+impl syn::parse::Parse for File {
+ fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+ let mut references = vec![];
+ let mut modules = vec![];
+ let winrt = winrt(input)?;
+
+ while !input.is_empty() {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(syn::Token![mod]) {
+ modules.push(Module::parse("", winrt, input)?);
+ } else if lookahead.peek(syn::Token![use]) {
+ references.push(input.parse()?);
+ } else {
+ return Err(lookahead.error());
+ }
+ }
+ Ok(Self { winrt, references, modules })
+ }
+}
+
+impl Module {
+ fn name(&self) -> &str {
+ self.namespace.rsplit_once('.').map_or(&self.namespace, |(_, name)| name)
+ }
+
+ fn parse(namespace: &str, winrt: bool, input: syn::parse::ParseStream) -> syn::Result<Self> {
+ input.parse::<syn::Token![mod]>()?;
+ let name = input.parse::<syn::Ident>()?.to_string();
+
+ let namespace = if namespace.is_empty() { name.to_string() } else { format!("{namespace}.{name}") };
+
+ let content;
+ syn::braced!(content in input);
+ let mut members = vec![];
+ while !content.is_empty() {
+ members.push(ModuleMember::parse(&namespace, winrt, &content)?);
+ }
+ Ok(Self { namespace, members })
+ }
+}
+
+impl ModuleMember {
+ fn parse(namespace: &str, winrt: bool, input: syn::parse::ParseStream) -> syn::Result<Self> {
+ let attributes: Vec<syn::Attribute> = input.call(syn::Attribute::parse_outer)?;
+ let lookahead = input.lookahead1();
+ if lookahead.peek(syn::Token![mod]) {
+ if let Some(attribute) = attributes.first() {
+ return Err(syn::Error::new(attribute.span(), "`use` attributes not supported"));
+ }
+ Ok(ModuleMember::Module(Module::parse(namespace, winrt, input)?))
+ } else if lookahead.peek(interface) {
+ Ok(ModuleMember::Interface(Interface::parse(namespace, winrt, attributes, input)?))
+ } else if lookahead.peek(syn::Token![struct]) {
+ Ok(ModuleMember::Struct(Struct::parse(namespace, winrt, attributes, input)?))
+ } else if lookahead.peek(syn::Token![enum]) {
+ Ok(ModuleMember::Enum(Enum::parse(namespace, winrt, attributes, input)?))
+ } else if lookahead.peek(class) {
+ Ok(ModuleMember::Class(Class::parse(attributes, input)?))
+ } else if lookahead.peek(syn::Token![fn]) {
+ Ok(ModuleMember::Function(Function::parse(namespace, attributes, input)?))
+ } else if lookahead.peek(syn::Token![const]) {
+ Ok(ModuleMember::Constant(Constant::parse(namespace, attributes, input)?))
+ } else {
+ Err(lookahead.error())
+ }
+ }
+}
+
+impl Class {
+ fn parse(attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> {
+ input.parse::<class>()?;
+ let name = input.parse::<syn::Ident>()?.to_string();
+ let mut extends = Vec::new();
+ let mut base = None;
+
+ if input.peek(syn::Token![:]) {
+ input.parse::<syn::Token![:]>()?;
+ while !input.peek(syn::Token![;]) {
+ if input.peek(class) {
+ input.parse::<class>()?;
+ base = Some(input.parse()?);
+ } else {
+ extends.push(input.parse()?);
+ }
+ _ = input.parse::<syn::Token![,]>();
+ }
+ }
+
+ input.parse::<syn::Token![;]>()?;
+ Ok(Self { attributes, name, base, extends })
+ }
+}
+
+impl Interface {
+ fn parse(_namespace: &str, winrt: bool, attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> {
+ input.parse::<interface>()?;
+ let name = input.parse::<syn::Ident>()?.to_string();
+
+ let mut generics = Vec::new();
+
+ if input.peek(syn::Token![<]) {
+ input.parse::<syn::Token![<]>()?;
+ while input.peek(syn::Ident) {
+ generics.push(input.parse::<syn::Ident>()?.to_string());
+ _ = input.parse::<syn::Token![,]>();
+ }
+
+ input.parse::<syn::Token![>]>()?;
+ }
+
+ let mut extends = Vec::new();
+
+ if input.peek(syn::Token![:]) {
+ input.parse::<syn::Token![:]>()?;
+ while !input.peek(syn::token::Brace) {
+ extends.push(input.parse()?);
+ _ = input.parse::<syn::Token![,]>();
+ }
+ }
+
+ let content;
+ syn::braced!(content in input);
+ let mut methods = vec![];
+ while !content.is_empty() {
+ methods.push(content.parse()?);
+ }
+ Ok(Self { winrt, attributes, generics, extends, name, methods })
+ }
+}
+
+impl Struct {
+ fn parse(_namespace: &str, winrt: bool, attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> {
+ // TODO: need to validate that the struct is valid according to the constraints of the winmd type system.
+ // Same for the other types. That way we can spit out errors quickly for things like unnamed fields.
+ let span = input.span();
+ let item: syn::ItemStruct = input.parse()?;
+ let name = item.ident.to_string();
+ let mut fields = vec![];
+
+ let syn::Fields::Named(named) = item.fields else {
+ return Err(syn::Error::new(item.span(), "unnamed fields not supported"));
+ };
+
+ for field in named.named {
+ fields.push(Field {
+ span: field.span(),
+ attributes: field.attrs,
+ // Simply unwrapping since we already know that it is a named field.
+ name: field.ident.unwrap().to_string(),
+ ty: field.ty,
+ });
+ }
+
+ Ok(Self { winrt, name, attributes, span, fields })
+ }
+}
+
+impl Enum {
+ fn parse(_namespace: &str, winrt: bool, attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> {
+ let mut item: syn::ItemEnum = input.parse()?;
+ item.attrs = attributes;
+ let name = item.ident.to_string();
+ Ok(Self { winrt, name, item })
+ }
+}
+
+impl Constant {
+ fn parse(_namespace: &str, attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> {
+ let mut item: syn::ItemConst = input.parse()?;
+ item.attrs = attributes;
+ let name = item.ident.to_string();
+ Ok(Self { name, item })
+ }
+}
+
+impl Function {
+ fn parse(_namespace: &str, attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> {
+ let mut item: syn::TraitItemFn = input.parse()?;
+ item.attrs = attributes;
+ let name = item.sig.ident.to_string();
+ Ok(Self { name, item })
+ }
+}
diff --git a/vendor/windows-bindgen/src/rdl/to_winmd.rs b/vendor/windows-bindgen/src/rdl/to_winmd.rs
new file mode 100644
index 000000000..d1dc65b12
--- /dev/null
+++ b/vendor/windows-bindgen/src/rdl/to_winmd.rs
@@ -0,0 +1,335 @@
+use super::*;
+use crate::winmd::{self, writer};
+use crate::{rdl, Result};
+
+// TODO: store span in winmd so that errors resolving type references can be traced back to file/line/column
+use std::collections::HashMap;
+//use syn::spanned::Spanned;
+
+// TODO: this creates a temporary in-memory winmd used to treat the IDL content uniformly as metadata.
+// The winmd_to_winmd does the harder job of validating and producing canonical winmd for public consumption.
+
+pub fn rdl_to_winmd(file: &rdl::File) -> Result<Vec<u8>> {
+ // Local-to-qualified type names found in use declaration - e.g. "IStringable" -> "Windows.Foundation.IStringable"
+ // This is just a convenience for the developer to shorten common references like this but would not support globs or renames.
+ // Note that none of these are verified to be real until much later when the winmd is validated since we don't
+ // know what other metadata may be combined
+ let mut _use_map = HashMap::<String, String>::new();
+
+ // TODO: read file and populate use_map
+
+ // Types are collected here in two passes - this allows us to figure out whether a local name points to a relative type
+ // or a type from a use declaration...?
+ let mut collector = HashMap::<String, HashMap<&str, rdl::ModuleMember>>::new();
+
+ file.modules.iter().for_each(|module| collect_module(&mut collector, module));
+
+ // TODO: collect type names into hashmap (phase 1) and just drop clones of the IDL members into the collector
+
+ // TODO: Can we just walk the collector at this point and populate the winmd writer and thus need the read-phase?
+ // this second walking of the collector is basically the "define" phase
+
+ let mut writer = winmd::Writer::new("temp.winmd");
+
+ collector.iter().for_each(|(namespace, members)| members.iter().for_each(|(name, member)| write_member(&mut writer, namespace, name, member)));
+
+ Ok(writer.into_stream())
+}
+
+fn collect_module<'a>(collector: &mut HashMap<String, HashMap<&'a str, rdl::ModuleMember>>, module: &'a rdl::Module) {
+ module.members.iter().for_each(|member| collect_member(collector, module, member));
+}
+
+fn collect_member<'a>(collector: &mut HashMap<String, HashMap<&'a str, rdl::ModuleMember>>, module: &'a rdl::Module, member: &'a rdl::ModuleMember) {
+ match member {
+ rdl::ModuleMember::Module(module) => collect_module(collector, module),
+ rdl::ModuleMember::Constant(_) | rdl::ModuleMember::Function(_) => {
+ collector.entry(module.namespace.to_string()).or_default().entry("Apis").or_insert(member.clone());
+ }
+ _ => {
+ collector.entry(module.namespace.to_string()).or_default().entry(member.name()).or_insert(member.clone());
+ }
+ }
+}
+
+fn write_member(writer: &mut winmd::Writer, namespace: &str, name: &str, member: &rdl::ModuleMember) {
+ match member {
+ rdl::ModuleMember::Interface(member) => write_interface(writer, namespace, name, member),
+ rdl::ModuleMember::Struct(member) => write_struct(writer, namespace, name, member),
+ rdl::ModuleMember::Enum(member) => write_enum(writer, namespace, name, member),
+ rdl::ModuleMember::Class(member) => write_class(writer, namespace, name, member),
+ rest => unimplemented!("{rest:?}"),
+ }
+}
+
+fn write_interface(writer: &mut winmd::Writer, namespace: &str, name: &str, member: &rdl::Interface) {
+ let mut flags = metadata::TypeAttributes::Public | metadata::TypeAttributes::Interface | metadata::TypeAttributes::Abstract;
+
+ if member.winrt {
+ flags |= metadata::TypeAttributes::WindowsRuntime
+ }
+
+ writer.tables.TypeDef.push(winmd::TypeDef {
+ Extends: 0,
+ FieldList: writer.tables.Field.len() as u32,
+ MethodList: writer.tables.MethodDef.len() as u32,
+ Flags: flags.0,
+ TypeName: writer.strings.insert(name),
+ TypeNamespace: writer.strings.insert(namespace),
+ });
+
+ for (number, generic) in member.generics.iter().enumerate() {
+ writer.tables.GenericParam.push(writer::GenericParam {
+ Number: number as u16,
+ Flags: 0,
+ Owner: writer::TypeOrMethodDef::TypeDef(writer.tables.TypeDef.len() as u32 - 1).encode(),
+ Name: writer.strings.insert(generic),
+ });
+ }
+
+ for type_path in &member.extends {
+ let ty = syn_type_path(namespace, &member.generics, type_path);
+
+ let reference = match &ty {
+ winmd::Type::TypeRef(type_name) if type_name.generics.is_empty() => writer.insert_type_ref(&type_name.namespace, &type_name.name),
+ winmd::Type::TypeRef(_) => writer.insert_type_spec(ty),
+ rest => unimplemented!("{rest:?}"),
+ };
+
+ writer.tables.InterfaceImpl.push(writer::InterfaceImpl { Class: writer.tables.TypeDef.len() as u32 - 1, Interface: reference });
+ }
+
+ for method in &member.methods {
+ let signature = syn_signature(namespace, &member.generics, &method.sig);
+
+ let params: Vec<winmd::Type> = signature.params.iter().map(|param| param.ty.clone()).collect();
+
+ let signature_blob = writer.insert_method_sig(metadata::MethodCallAttributes(0), &signature.return_type, &params);
+
+ let flags = metadata::MethodAttributes::Abstract | metadata::MethodAttributes::HideBySig | metadata::MethodAttributes::HideBySig | metadata::MethodAttributes::NewSlot | metadata::MethodAttributes::Public | metadata::MethodAttributes::Virtual;
+
+ writer.tables.MethodDef.push(winmd::MethodDef {
+ RVA: 0,
+ ImplFlags: 0,
+ Flags: flags.0,
+ Name: writer.strings.insert(&method.sig.ident.to_string()),
+ Signature: signature_blob,
+ ParamList: writer.tables.Param.len() as u32,
+ });
+
+ for (sequence, param) in signature.params.iter().enumerate() {
+ writer.tables.Param.push(winmd::Param { Flags: 0, Sequence: (sequence + 1) as u16, Name: writer.strings.insert(&param.name) });
+ }
+ }
+}
+
+fn write_struct(writer: &mut winmd::Writer, namespace: &str, name: &str, member: &rdl::Struct) {
+ let mut flags = metadata::TypeAttributes::Public | metadata::TypeAttributes::Sealed | metadata::TypeAttributes::SequentialLayout;
+
+ if member.winrt {
+ flags |= metadata::TypeAttributes::WindowsRuntime
+ }
+
+ let extends = writer.insert_type_ref("System", "ValueType");
+
+ writer.tables.TypeDef.push(winmd::TypeDef {
+ Extends: extends,
+ FieldList: writer.tables.Field.len() as u32,
+ MethodList: writer.tables.MethodDef.len() as u32,
+ Flags: flags.0,
+ TypeName: writer.strings.insert(name),
+ TypeNamespace: writer.strings.insert(namespace),
+ });
+
+ for field in &member.fields {
+ let flags = metadata::FieldAttributes::Public;
+ let ty = syn_type(namespace, &[], &field.ty);
+ let signature = writer.insert_field_sig(&ty);
+
+ writer.tables.Field.push(winmd::Field { Flags: flags.0, Name: writer.strings.insert(&field.name), Signature: signature });
+ }
+}
+
+fn write_enum(_writer: &mut winmd::Writer, _namespace: &str, _name: &str, _member: &rdl::Enum) {}
+
+fn write_class(writer: &mut winmd::Writer, namespace: &str, name: &str, member: &rdl::Class) {
+ let flags = metadata::TypeAttributes::Public | metadata::TypeAttributes::Sealed | metadata::TypeAttributes::WindowsRuntime;
+
+ let extends = if let Some(base) = &member.base {
+ match syn_type_path(namespace, &[], base) {
+ winmd::Type::TypeRef(base) => writer.insert_type_ref(&base.namespace, &base.name),
+ rest => unimplemented!("{rest:?}"),
+ }
+ } else {
+ writer.insert_type_ref("System", "Object")
+ };
+
+ writer.tables.TypeDef.push(winmd::TypeDef {
+ Extends: extends,
+ // Even though ECMA-335 says these can be "null", bugs in ILDASM necessitate this to avoid "misreading" the list terminators.
+ FieldList: writer.tables.Field.len() as u32,
+ MethodList: writer.tables.MethodDef.len() as u32,
+ Flags: flags.0,
+ TypeName: writer.strings.insert(name),
+ TypeNamespace: writer.strings.insert(namespace),
+ });
+
+ for (index, extends) in member.extends.iter().enumerate() {
+ let ty = syn_type_path(namespace, &[], extends);
+
+ let reference = match &ty {
+ winmd::Type::TypeRef(type_name) if type_name.generics.is_empty() => writer.insert_type_ref(&type_name.namespace, &type_name.name),
+ winmd::Type::TypeRef(_) => writer.insert_type_spec(ty),
+ winmd::Type::IUnknown => writer.insert_type_ref("Windows.Win32.System.Com", "IUnknown"),
+ winmd::Type::IInspectable => writer.insert_type_ref("Windows.Win32.System.WinRT", "IInspectable"),
+ rest => unimplemented!("{rest:?}"),
+ };
+
+ writer.tables.InterfaceImpl.push(writer::InterfaceImpl { Class: writer.tables.TypeDef.len() as u32 - 1, Interface: reference });
+
+ if index == 0 {
+ // TODO: add the DefaultAttribute to the first interface
+ }
+ }
+}
+
+fn syn_signature(namespace: &str, generics: &[String], sig: &syn::Signature) -> winmd::Signature {
+ let params = sig
+ .inputs
+ .iter()
+ .map(|param| match param {
+ syn::FnArg::Typed(pat_type) => {
+ let name = match &*pat_type.pat {
+ syn::Pat::Ident(pat_ident) => pat_ident.ident.to_string(),
+ rest => unimplemented!("{rest:?}"),
+ };
+ let ty = syn_type(namespace, generics, &pat_type.ty);
+ winmd::SignatureParam { name, ty }
+ }
+ rest => unimplemented!("{rest:?}"),
+ })
+ .collect();
+
+ let return_type = if let syn::ReturnType::Type(_, ty) = &sig.output { syn_type(namespace, generics, ty) } else { winmd::Type::Void };
+
+ winmd::Signature { params, return_type, call_flags: 0 }
+}
+
+fn syn_type(namespace: &str, generics: &[String], ty: &syn::Type) -> winmd::Type {
+ match ty {
+ syn::Type::Path(ty) => syn_type_path(namespace, generics, ty),
+ syn::Type::Ptr(ptr) => syn_type_ptr(namespace, ptr),
+ syn::Type::Array(array) => syn_type_array(namespace, array),
+ rest => unimplemented!("{rest:?}"),
+ }
+}
+
+fn syn_type_array(namespace: &str, array: &syn::TypeArray) -> winmd::Type {
+ let ty = syn_type(namespace, &[], &array.elem);
+
+ if let syn::Expr::Lit(lit) = &array.len {
+ if let syn::Lit::Int(lit) = &lit.lit {
+ if let Ok(len) = lit.base10_parse() {
+ return ty.into_array(len);
+ }
+ }
+ }
+
+ unimplemented!()
+}
+
+fn syn_type_ptr(namespace: &str, ptr: &syn::TypePtr) -> winmd::Type {
+ let ty = syn_type(namespace, &[], &ptr.elem);
+ if ptr.mutability.is_some() {
+ ty.into_mut_ptr()
+ } else {
+ ty.into_const_ptr()
+ }
+}
+
+fn syn_type_path(namespace: &str, generics: &[String], ty: &syn::TypePath) -> winmd::Type {
+ if ty.qself.is_none() {
+ return syn_path(namespace, generics, &ty.path);
+ }
+
+ unimplemented!()
+}
+
+fn syn_path(namespace: &str, generics: &[String], path: &syn::Path) -> winmd::Type {
+ if let Some(segment) = path.segments.first() {
+ if path.segments.len() == 1 && segment.arguments.is_empty() {
+ let name = segment.ident.to_string();
+
+ if let Some(number) = generics.iter().position(|generic| generic == &name) {
+ return winmd::Type::GenericParam(number as u16);
+ }
+
+ match name.as_str() {
+ "void" => return winmd::Type::Void,
+ "bool" => return winmd::Type::Bool,
+ "char" => return winmd::Type::Char,
+ "i8" => return winmd::Type::I8,
+ "u8" => return winmd::Type::U8,
+ "i16" => return winmd::Type::I16,
+ "u16" => return winmd::Type::U16,
+ "i32" => return winmd::Type::I32,
+ "u32" => return winmd::Type::U32,
+ "i64" => return winmd::Type::I64,
+ "u64" => return winmd::Type::U64,
+ "f32" => return winmd::Type::F32,
+ "f64" => return winmd::Type::F64,
+ "isize" => return winmd::Type::ISize,
+ "usize" => return winmd::Type::USize,
+ "HSTRING" => return winmd::Type::String,
+ "GUID" => return winmd::Type::GUID,
+ "IUnknown" => return winmd::Type::IUnknown,
+ "IInspectable" => return winmd::Type::IInspectable,
+ "HRESULT" => return winmd::Type::HRESULT,
+ "PSTR" => return winmd::Type::PSTR,
+ "PWSTR" => return winmd::Type::PWSTR,
+ "PCSTR" => return winmd::Type::PCSTR,
+ "PCWSTR" => return winmd::Type::PCWSTR,
+ "BSTR" => return winmd::Type::BSTR,
+ _ => {}
+ };
+ }
+ }
+
+ // TODO: Here we assume that paths are absolute since there's no way to disambiguate between nested and absolute paths
+ // The canonicalize function (should maybe) preprocesses the IDL to make this work
+
+ let mut builder = vec![];
+
+ for segment in &path.segments {
+ let segment = segment.ident.to_string();
+
+ if segment == "super" {
+ if builder.is_empty() {
+ for segment in namespace.split('.') {
+ builder.push(segment.to_string());
+ }
+ }
+ builder.pop();
+ } else {
+ builder.push(segment);
+ }
+ }
+
+ // Unwrapping is fine as there should always be at least one segment.
+ let (name, type_namespace) = builder.split_last().unwrap();
+ let type_namespace = if type_namespace.is_empty() { namespace.to_string() } else { type_namespace.join(".") };
+ let mut type_generics = vec![];
+
+ if let Some(segment) = path.segments.last() {
+ if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
+ for arg in &args.args {
+ match arg {
+ syn::GenericArgument::Type(ty) => type_generics.push(syn_type(namespace, generics, ty)),
+ rest => unimplemented!("{rest:?}"),
+ }
+ }
+ }
+ }
+
+ winmd::Type::TypeRef(winmd::TypeName { namespace: type_namespace, name: name.to_string(), generics: type_generics })
+}