Skip to content

Commit

Permalink
bindgen
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr committed Sep 13, 2023
1 parent 132fb5b commit 97064e0
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 150 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,6 @@ fn param_or_enum(reader: &Reader, row: Param) -> Option<String> {
})
}

pub fn signature_param_is_borrowed(reader: &Reader, param: &SignatureParam) -> bool {
type_is_borrowed(reader, &param.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, &param.ty) || type_is_non_exclusive_winrt_interface(reader, &param.ty) || type_is_trivially_convertible(reader, &param.ty))
}
Expand Down Expand Up @@ -268,7 +264,10 @@ fn signature_param_is_retval(reader: &Reader, param: &SignatureParam) -> bool {
}
// Win32 callbacks are defined as `Option<T>` so we don't include them here to avoid
// producing the `Result<Option<T>>` anti-pattern.
!type_is_callback(reader, &param.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 {
Expand All @@ -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 });
}
}
}
Expand All @@ -312,12 +309,14 @@ fn signature_is_retval(reader: &Reader, signature: &Signature) -> bool {
})
}

fn signature_param_is_query_guid(reader: &Reader, params: &[SignatureParam]) -> Option<usize> {
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<usize> {
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 {
Expand All @@ -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,
Expand Down Expand Up @@ -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,
}
}
Expand Down Expand Up @@ -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)))
}
Expand All @@ -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<GUID> {
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),
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<GUID> {
reader.find_attribute(row, "GuidAttribute").map(|attribute| GUID::from_args(&reader.attribute_args(attribute)))
}
Expand All @@ -816,23 +718,6 @@ pub fn type_def_bases(reader: &Reader, mut row: TypeDef) -> Vec<TypeDef> {
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<i64> {
let mut values = Vec::new();
for attribute in reader.attributes(row) {
Expand All @@ -845,15 +730,6 @@ pub fn type_def_invalid_values(reader: &Reader, row: TypeDef) -> Vec<i64> {
values
}

pub fn type_def_usable_for(reader: &Reader, row: TypeDef) -> Option<TypeDef> {
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,
Expand Down Expand Up @@ -906,11 +782,3 @@ pub fn type_def_vtables(reader: &Reader, row: TypeDef) -> Vec<Type> {
pub fn type_def_interfaces<'a>(reader: &'a Reader<'a>, row: TypeDef, generics: &'a [Type]) -> impl Iterator<Item = Type> + '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(),
}
}
24 changes: 24 additions & 0 deletions crates/libs/bindgen/src/rust/classes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
24 changes: 24 additions & 0 deletions crates/libs/bindgen/src/rust/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<GUID> {
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(),
}
}
13 changes: 13 additions & 0 deletions crates/libs/bindgen/src/rust/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!()
}
}
9 changes: 9 additions & 0 deletions crates/libs/bindgen/src/rust/handles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TypeDef> {
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
}
26 changes: 26 additions & 0 deletions crates/libs/bindgen/src/rust/method_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
2 changes: 1 addition & 1 deletion crates/libs/bindgen/src/rust/winrt_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ fn gen_winrt_abi_args(writer: &Writer, params: &[SignatureParam]) -> TokenStream
}
} else if type_is_non_exclusive_winrt_interface(writer.reader, &param.ty) {
quote! { #name.try_into_param()?.abi(), }
} else if signature_param_is_borrowed(writer.reader, param) {
} else if type_is_borrowed(writer.reader, &param.ty) {
quote! { #name.into_param().abi(), }
} else if type_is_blittable(writer.reader, &param.ty) {
if param.ty.is_const_ref() {
Expand Down
Loading

0 comments on commit 97064e0

Please sign in to comment.