diff --git a/crates/libs/bindgen/src/metadata/mod.rs b/crates/libs/bindgen/src/metadata.rs similarity index 82% rename from crates/libs/bindgen/src/metadata/mod.rs rename to crates/libs/bindgen/src/metadata.rs index d879625d3b..12e1f6da49 100644 --- a/crates/libs/bindgen/src/metadata/mod.rs +++ b/crates/libs/bindgen/src/metadata.rs @@ -235,10 +235,6 @@ fn param_or_enum(reader: &Reader, row: Param) -> Option { }) } -pub fn signature_param_is_borrowed(reader: &Reader, param: &SignatureParam) -> bool { - type_is_borrowed(reader, ¶m.ty) -} - pub fn signature_param_is_convertible(reader: &Reader, param: &SignatureParam) -> bool { !reader.param_flags(param.def).contains(ParamAttributes::Out) && !param.ty.is_winrt_array() && !param.ty.is_pointer() && !param.kind.is_array() && (type_is_borrowed(reader, ¶m.ty) || type_is_non_exclusive_winrt_interface(reader, ¶m.ty) || type_is_trivially_convertible(reader, ¶m.ty)) } @@ -268,7 +264,10 @@ fn signature_param_is_retval(reader: &Reader, param: &SignatureParam) -> bool { } // Win32 callbacks are defined as `Option` so we don't include them here to avoid // producing the `Result>` anti-pattern. - !type_is_callback(reader, ¶m.ty.deref()) + match param.ty.deref() { + Type::TypeDef(def, _) => !type_def_is_callback(reader, def), + _ => true, + } } pub fn signature_kind(reader: &Reader, signature: &Signature) -> SignatureKind { @@ -280,13 +279,11 @@ pub fn signature_kind(reader: &Reader, signature: &Signature) -> SignatureKind { Type::Void => SignatureKind::ReturnVoid, Type::HRESULT => { if signature.params.len() >= 2 { - if let Some(guid) = signature_param_is_query_guid(reader, &signature.params) { - if let Some(object) = signature_param_is_query_object(reader, &signature.params) { - if reader.param_flags(signature.params[object].def).contains(ParamAttributes::Optional) { - return SignatureKind::QueryOptional(QueryPosition { object, guid }); - } else { - return SignatureKind::Query(QueryPosition { object, guid }); - } + if let Some((guid, object)) = signature_param_is_query(reader, &signature.params) { + if reader.param_flags(signature.params[object].def).contains(ParamAttributes::Optional) { + return SignatureKind::QueryOptional(QueryPosition { object, guid }); + } else { + return SignatureKind::Query(QueryPosition { object, guid }); } } } @@ -312,12 +309,14 @@ fn signature_is_retval(reader: &Reader, signature: &Signature) -> bool { }) } -fn signature_param_is_query_guid(reader: &Reader, params: &[SignatureParam]) -> Option { - params.iter().rposition(|param| param.ty == Type::ConstPtr(Box::new(Type::GUID), 1) && !reader.param_flags(param.def).contains(ParamAttributes::Out)) -} +fn signature_param_is_query(reader: &Reader, params: &[SignatureParam]) -> Option<(usize, usize)> { + if let Some(guid) = params.iter().rposition(|param| param.ty == Type::ConstPtr(Box::new(Type::GUID), 1) && !reader.param_flags(param.def).contains(ParamAttributes::Out)) { + if let Some(object) = params.iter().rposition(|param| param.ty == Type::MutPtr(Box::new(Type::Void), 2) && reader.has_attribute(param.def, "ComOutPtrAttribute")) { + return Some((guid, object)); + } + } -fn signature_param_is_query_object(reader: &Reader, params: &[SignatureParam]) -> Option { - params.iter().rposition(|param| param.ty == Type::MutPtr(Box::new(Type::Void), 2) && reader.has_attribute(param.def, "ComOutPtrAttribute")) + None } fn method_def_last_error(reader: &Reader, row: MethodDef) -> bool { @@ -328,7 +327,7 @@ fn method_def_last_error(reader: &Reader, row: MethodDef) -> bool { } } -fn type_is_borrowed(reader: &Reader, ty: &Type) -> bool { +pub fn type_is_borrowed(reader: &Reader, ty: &Type) -> bool { match ty { Type::TypeDef(row, _) => !type_def_is_blittable(reader, *row), Type::BSTR | Type::PCSTR | Type::PCWSTR | Type::IInspectable | Type::IUnknown | Type::GenericParam(_) => true, @@ -360,14 +359,6 @@ fn type_is_trivially_convertible(reader: &Reader, ty: &Type) -> bool { TypeKind::Struct => type_def_is_handle(reader, *row), _ => false, }, - Type::PCSTR | Type::PCWSTR => true, - _ => false, - } -} - -fn type_is_callback(reader: &Reader, ty: &Type) -> bool { - match ty { - Type::TypeDef(row, _) => type_def_is_callback(reader, *row), _ => false, } } @@ -479,16 +470,6 @@ fn type_name<'a>(reader: &Reader<'a>, ty: &Type) -> &'a str { } } -pub fn type_def_async_kind(reader: &Reader, row: TypeDef) -> AsyncKind { - match reader.type_def_type_name(row) { - TypeName::IAsyncAction => AsyncKind::Action, - TypeName::IAsyncActionWithProgress => AsyncKind::ActionWithProgress, - TypeName::IAsyncOperation => AsyncKind::Operation, - TypeName::IAsyncOperationWithProgress => AsyncKind::OperationWithProgress, - _ => AsyncKind::None, - } -} - pub fn field_is_blittable(reader: &Reader, row: Field, enclosing: TypeDef) -> bool { type_is_blittable(reader, &reader.field_type(row, Some(enclosing))) } @@ -497,14 +478,6 @@ pub fn field_is_copyable(reader: &Reader, row: Field, enclosing: TypeDef) -> boo type_is_copyable(reader, &reader.field_type(row, Some(enclosing))) } -pub fn field_guid(reader: &Reader, row: Field) -> Option { - reader.find_attribute(row, "GuidAttribute").map(|attribute| GUID::from_args(&reader.attribute_args(attribute))) -} - -pub fn field_is_ansi(reader: &Reader, row: Field) -> bool { - reader.find_attribute(row, "NativeEncodingAttribute").is_some_and(|attribute| matches!(reader.attribute_args(attribute).get(0), Some((_, Value::String(encoding))) if encoding == "ansi")) -} - pub fn type_is_blittable(reader: &Reader, ty: &Type) -> bool { match ty { Type::TypeDef(row, _) => type_def_is_blittable(reader, *row), @@ -549,73 +522,10 @@ pub fn type_def_is_copyable(reader: &Reader, row: TypeDef) -> bool { } } -pub fn method_def_special_name(reader: &Reader, row: MethodDef) -> String { - let name = reader.method_def_name(row); - if reader.method_def_flags(row).contains(MethodAttributes::SpecialName) { - if name.starts_with("get") { - name[4..].to_string() - } else if name.starts_with("put") { - format!("Set{}", &name[4..]) - } else if name.starts_with("add") { - name[4..].to_string() - } else if name.starts_with("remove") { - format!("Remove{}", &name[7..]) - } else { - name.to_string() - } - } else { - if let Some(attribute) = reader.find_attribute(row, "OverloadAttribute") { - for (_, arg) in reader.attribute_args(attribute) { - if let Value::String(name) = arg { - return name; - } - } - } - name.to_string() - } -} - -pub fn method_def_extern_abi(reader: &Reader, def: MethodDef) -> &'static str { - let impl_map = reader.method_def_impl_map(def).expect("ImplMap not found"); - let flags = reader.impl_map_flags(impl_map); - - if flags.contains(PInvokeAttributes::CallConvPlatformapi) { - "system" - } else if flags.contains(PInvokeAttributes::CallConvCdecl) { - "cdecl" - } else { - unimplemented!() - } -} - -pub fn type_def_has_default_constructor(reader: &Reader, row: TypeDef) -> bool { - for attribute in reader.attributes(row) { - if reader.attribute_name(attribute) == "ActivatableAttribute" { - if reader.attribute_args(attribute).iter().any(|arg| matches!(arg.1, Value::TypeName(_))) { - continue; - } else { - return true; - } - } - } - false -} - -pub fn type_def_has_default_interface(reader: &Reader, row: TypeDef) -> bool { - reader.type_def_interface_impls(row).any(|imp| reader.has_attribute(imp, "DefaultAttribute")) -} - pub fn type_def_is_exclusive(reader: &Reader, row: TypeDef) -> bool { reader.has_attribute(row, "ExclusiveToAttribute") } -pub fn type_is_exclusive(reader: &Reader, ty: &Type) -> bool { - match ty { - Type::TypeDef(row, _) => type_def_is_exclusive(reader, *row), - _ => false, - } -} - pub fn type_is_struct(reader: &Reader, ty: &Type) -> bool { // This check is used to detect virtual functions that return C-style PODs that affect how the stack is packed for x86. // It could be defined as a struct with more than one field but that check is complicated as it would have to detect @@ -790,14 +700,6 @@ pub fn type_def_is_handle(reader: &Reader, row: TypeDef) -> bool { reader.has_attribute(row, "NativeTypedefAttribute") } -pub fn type_has_replacement(reader: &Reader, ty: &Type) -> bool { - match ty { - Type::HRESULT | Type::PCSTR | Type::PCWSTR => true, - Type::TypeDef(row, _) => type_def_is_handle(reader, *row) || reader.type_def_kind(*row) == TypeKind::Enum, - _ => false, - } -} - pub fn type_def_guid(reader: &Reader, row: TypeDef) -> Option { reader.find_attribute(row, "GuidAttribute").map(|attribute| GUID::from_args(&reader.attribute_args(attribute))) } @@ -816,23 +718,6 @@ pub fn type_def_bases(reader: &Reader, mut row: TypeDef) -> Vec { bases } -pub fn type_def_is_agile(reader: &Reader, row: TypeDef) -> bool { - for attribute in reader.attributes(row) { - match reader.attribute_name(attribute) { - "AgileAttribute" => return true, - "MarshalingBehaviorAttribute" => { - if let Some((_, Value::EnumDef(_, value))) = reader.attribute_args(attribute).get(0) { - if let Value::I32(2) = **value { - return true; - } - } - } - _ => {} - } - } - matches!(reader.type_def_type_name(row), TypeName::IAsyncAction | TypeName::IAsyncActionWithProgress | TypeName::IAsyncOperation | TypeName::IAsyncOperationWithProgress) -} - pub fn type_def_invalid_values(reader: &Reader, row: TypeDef) -> Vec { let mut values = Vec::new(); for attribute in reader.attributes(row) { @@ -845,15 +730,6 @@ pub fn type_def_invalid_values(reader: &Reader, row: TypeDef) -> Vec { values } -pub fn type_def_usable_for(reader: &Reader, row: TypeDef) -> Option { - if let Some(attribute) = reader.find_attribute(row, "AlsoUsableForAttribute") { - if let Some((_, Value::String(name))) = reader.attribute_args(attribute).get(0) { - return reader.get_type_def(TypeName::new(reader.type_def_namespace(row), name.as_str())).next(); - } - } - None -} - fn type_def_is_nullable(reader: &Reader, row: TypeDef) -> bool { match reader.type_def_kind(row) { TypeKind::Interface | TypeKind::Class => true, @@ -906,11 +782,3 @@ pub fn type_def_vtables(reader: &Reader, row: TypeDef) -> Vec { pub fn type_def_interfaces<'a>(reader: &'a Reader<'a>, row: TypeDef, generics: &'a [Type]) -> impl Iterator + 'a { reader.type_def_interface_impls(row).map(move |row| reader.interface_impl_type(row, generics)) } - -pub fn type_underlying_type(reader: &Reader, ty: &Type) -> Type { - match ty { - Type::TypeDef(row, _) => reader.type_def_underlying_type(*row), - Type::HRESULT => Type::I32, - _ => ty.clone(), - } -} diff --git a/crates/libs/bindgen/src/rust/classes.rs b/crates/libs/bindgen/src/rust/classes.rs index 349d7c5436..b20d99beaa 100644 --- a/crates/libs/bindgen/src/rust/classes.rs +++ b/crates/libs/bindgen/src/rust/classes.rs @@ -158,3 +158,27 @@ fn gen_conversions(writer: &Writer, def: TypeDef, name: &TokenStream, interfaces tokens } + +fn type_def_has_default_constructor(reader: &Reader, row: TypeDef) -> bool { + for attribute in reader.attributes(row) { + if reader.attribute_name(attribute) == "ActivatableAttribute" { + if reader.attribute_args(attribute).iter().any(|arg| matches!(arg.1, Value::TypeName(_))) { + continue; + } else { + return true; + } + } + } + false +} + +fn type_def_has_default_interface(reader: &Reader, row: TypeDef) -> bool { + reader.type_def_interface_impls(row).any(|imp| reader.has_attribute(imp, "DefaultAttribute")) +} + +fn type_is_exclusive(reader: &Reader, ty: &Type) -> bool { + match ty { + Type::TypeDef(row, _) => type_def_is_exclusive(reader, *row), + _ => false, + } +} diff --git a/crates/libs/bindgen/src/rust/constants.rs b/crates/libs/bindgen/src/rust/constants.rs index 672dbcc8af..1943cd8809 100644 --- a/crates/libs/bindgen/src/rust/constants.rs +++ b/crates/libs/bindgen/src/rust/constants.rs @@ -183,3 +183,27 @@ fn read_literal_array(input: &str, len: usize) -> (Vec<&str>, &str) { (result, read_token(input, b'}')) } + +fn field_guid(reader: &Reader, row: Field) -> Option { + reader.find_attribute(row, "GuidAttribute").map(|attribute| GUID::from_args(&reader.attribute_args(attribute))) +} + +fn field_is_ansi(reader: &Reader, row: Field) -> bool { + reader.find_attribute(row, "NativeEncodingAttribute").is_some_and(|attribute| matches!(reader.attribute_args(attribute).get(0), Some((_, Value::String(encoding))) if encoding == "ansi")) +} + +fn type_has_replacement(reader: &Reader, ty: &Type) -> bool { + match ty { + Type::HRESULT | Type::PCSTR | Type::PCWSTR => true, + Type::TypeDef(row, _) => type_def_is_handle(reader, *row) || reader.type_def_kind(*row) == TypeKind::Enum, + _ => false, + } +} + +fn type_underlying_type(reader: &Reader, ty: &Type) -> Type { + match ty { + Type::TypeDef(row, _) => reader.type_def_underlying_type(*row), + Type::HRESULT => Type::I32, + _ => ty.clone(), + } +} diff --git a/crates/libs/bindgen/src/rust/functions.rs b/crates/libs/bindgen/src/rust/functions.rs index 97d83aebfa..e790a34ed2 100644 --- a/crates/libs/bindgen/src/rust/functions.rs +++ b/crates/libs/bindgen/src/rust/functions.rs @@ -265,3 +265,16 @@ fn handle_last_error(writer: &Writer, def: MethodDef, signature: &Signature) -> } false } + +fn method_def_extern_abi(reader: &Reader, def: MethodDef) -> &'static str { + let impl_map = reader.method_def_impl_map(def).expect("ImplMap not found"); + let flags = reader.impl_map_flags(impl_map); + + if flags.contains(PInvokeAttributes::CallConvPlatformapi) { + "system" + } else if flags.contains(PInvokeAttributes::CallConvCdecl) { + "cdecl" + } else { + unimplemented!() + } +} diff --git a/crates/libs/bindgen/src/rust/handles.rs b/crates/libs/bindgen/src/rust/handles.rs index e213679e06..7e067a492c 100644 --- a/crates/libs/bindgen/src/rust/handles.rs +++ b/crates/libs/bindgen/src/rust/handles.rs @@ -106,3 +106,12 @@ pub fn gen_win_handle(writer: &Writer, def: TypeDef) -> TokenStream { tokens } + +fn type_def_usable_for(reader: &Reader, row: TypeDef) -> Option { + if let Some(attribute) = reader.find_attribute(row, "AlsoUsableForAttribute") { + if let Some((_, Value::String(name))) = reader.attribute_args(attribute).get(0) { + return reader.get_type_def(TypeName::new(reader.type_def_namespace(row), name.as_str())).next(); + } + } + None +} diff --git a/crates/libs/bindgen/src/rust/method_names.rs b/crates/libs/bindgen/src/rust/method_names.rs index 2d5a508ae4..9271e8c021 100644 --- a/crates/libs/bindgen/src/rust/method_names.rs +++ b/crates/libs/bindgen/src/rust/method_names.rs @@ -28,3 +28,29 @@ impl MethodNames { } } } + +fn method_def_special_name(reader: &Reader, row: MethodDef) -> String { + let name = reader.method_def_name(row); + if reader.method_def_flags(row).contains(MethodAttributes::SpecialName) { + if name.starts_with("get") { + name[4..].to_string() + } else if name.starts_with("put") { + format!("Set{}", &name[4..]) + } else if name.starts_with("add") { + name[4..].to_string() + } else if name.starts_with("remove") { + format!("Remove{}", &name[7..]) + } else { + name.to_string() + } + } else { + if let Some(attribute) = reader.find_attribute(row, "OverloadAttribute") { + for (_, arg) in reader.attribute_args(attribute) { + if let Value::String(name) = arg { + return name; + } + } + } + name.to_string() + } +} diff --git a/crates/libs/bindgen/src/rust/winrt_methods.rs b/crates/libs/bindgen/src/rust/winrt_methods.rs index f98843e66d..a2f1ca7234 100644 --- a/crates/libs/bindgen/src/rust/winrt_methods.rs +++ b/crates/libs/bindgen/src/rust/winrt_methods.rs @@ -144,7 +144,7 @@ fn gen_winrt_abi_args(writer: &Writer, params: &[SignatureParam]) -> TokenStream } } else if type_is_non_exclusive_winrt_interface(writer.reader, ¶m.ty) { quote! { #name.try_into_param()?.abi(), } - } else if signature_param_is_borrowed(writer.reader, param) { + } else if type_is_borrowed(writer.reader, ¶m.ty) { quote! { #name.into_param().abi(), } } else if type_is_blittable(writer.reader, ¶m.ty) { if param.ty.is_const_ref() { diff --git a/crates/libs/bindgen/src/rust/writer.rs b/crates/libs/bindgen/src/rust/writer.rs index ac2dfaa797..74b55301dd 100644 --- a/crates/libs/bindgen/src/rust/writer.rs +++ b/crates/libs/bindgen/src/rust/writer.rs @@ -1178,6 +1178,33 @@ fn gen_const_ptrs(pointers: usize) -> TokenStream { "*const ".repeat(pointers).into() } +fn type_def_async_kind(reader: &Reader, row: TypeDef) -> AsyncKind { + match reader.type_def_type_name(row) { + TypeName::IAsyncAction => AsyncKind::Action, + TypeName::IAsyncActionWithProgress => AsyncKind::ActionWithProgress, + TypeName::IAsyncOperation => AsyncKind::Operation, + TypeName::IAsyncOperationWithProgress => AsyncKind::OperationWithProgress, + _ => AsyncKind::None, + } +} + +fn type_def_is_agile(reader: &Reader, row: TypeDef) -> bool { + for attribute in reader.attributes(row) { + match reader.attribute_name(attribute) { + "AgileAttribute" => return true, + "MarshalingBehaviorAttribute" => { + if let Some((_, Value::EnumDef(_, value))) = reader.attribute_args(attribute).get(0) { + if let Value::I32(2) = **value { + return true; + } + } + } + _ => {} + } + } + matches!(reader.type_def_type_name(row), TypeName::IAsyncAction | TypeName::IAsyncActionWithProgress | TypeName::IAsyncOperation | TypeName::IAsyncOperationWithProgress) +} + #[cfg(test)] mod tests { use super::*;