Skip to content

Commit

Permalink
Mark bridged *void typedefs as CF types too
Browse files Browse the repository at this point in the history
Namely `CFType` and `CFPropertyList`.
  • Loading branch information
madsmtm committed Jan 8, 2025
1 parent f2f7b94 commit c37bb63
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 65 deletions.
11 changes: 6 additions & 5 deletions crates/header-translator/src/rust_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1410,9 +1410,7 @@ impl Ty {
// Typedefs to void* are CF types if the typedef is
// bridged, or in pre-defined list.
Self::Primitive(Primitive::Void) => {
// TODO
let enabled = false;
enabled && (typedef_is_bridged || KNOWN_CF_TYPES.contains(&typedef_name))
typedef_is_bridged || KNOWN_CF_TYPES.contains(&typedef_name)
}
_ => false,
},
Expand Down Expand Up @@ -2117,7 +2115,7 @@ impl Ty {
matches!(self, Self::Enum { .. })
}

pub(crate) fn pointer_to_opaque_struct(&self) -> Option<&str> {
pub(crate) fn pointer_to_opaque_struct_or_void(&self) -> Option<Option<String>> {
if let Self::Pointer {
pointee,
is_const: _, // const-ness doesn't matter when defining the type
Expand All @@ -2135,9 +2133,12 @@ impl Ty {
error!(?id, ?lifetime, "opaque pointer had lifetime");
}

return Some(&id.name);
return Some(Some(id.name.to_string()));
}
}
if let Self::Primitive(Primitive::Void) = &**pointee {
return Some(None);
}
}
None
}
Expand Down
51 changes: 32 additions & 19 deletions crates/header-translator/src/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ pub enum Stmt {
/// typedef struct CF_BRIDGED_TYPE(id) CGColorSpace *CGColorSpaceRef;
OpaqueDecl {
id: ItemIdentifier,
encoding_name: String,
encoding_name: Option<String>,
availability: Availability,
documentation: Documentation,
is_cf: bool,
Expand Down Expand Up @@ -1138,15 +1138,20 @@ impl Stmt {
let is_cf = ty.is_inner_cf_type(&id.name, is_bridged(entity, context));
let id = context.replace_typedef_name(id, is_cf);

if let Some(encoding_name) = ty.pointer_to_opaque_struct() {
if let Some(encoding_name) = ty.pointer_to_opaque_struct_or_void() {
if kind.is_some() {
error!(?kind, "unknown kind on opaque struct");
error!(?kind, "unknown kind on opaque type");
}

let entity = inner_struct.unwrap();
assert_eq!(entity.get_name().unwrap(), encoding_name);
assert_eq!(
inner_struct
.as_ref()
.map(|entity| entity.get_name().unwrap()),
encoding_name,
"inner struct must be the same that `pointer_to_opaque_struct_or_void` found",
);

return if is_cf {
if is_cf {
// If the class name contains the word "Mutable"
// exactly once per the usual word-boundary rules, a
// corresponding class name without the word "Mutable"
Expand All @@ -1163,19 +1168,19 @@ impl Stmt {
None
};

vec![Self::OpaqueDecl {
return vec![Self::OpaqueDecl {
id,
encoding_name: encoding_name.to_string(),
encoding_name,
availability,
documentation,
is_cf,
superclass,
}]
} else {
vec![
}];
} else if let Some(entity) = inner_struct {
return vec![
Self::OpaqueDecl {
id: ItemIdentifier::new(&entity, context),
encoding_name: encoding_name.to_string(),
encoding_name,
availability: Availability::parse(&entity, context),
documentation: Documentation::from_entity(&entity),
is_cf,
Expand All @@ -1188,8 +1193,8 @@ impl Stmt {
kind,
documentation,
},
]
};
];
}
}

vec![Self::AliasDecl {
Expand Down Expand Up @@ -2793,7 +2798,11 @@ impl Stmt {
// SAFETY: The type is a CoreFoundation type, and
// correctly declared as a #[repr(C)] ZST.
writeln!(f, "cf_type!(")?;
writeln!(f, " #[encoding_name = {encoding_name:?}]")?;
if let Some(encoding_name) = &encoding_name {
writeln!(f, " #[encoding_name = {encoding_name:?}]")?;
} else {
writeln!(f, " #[encoding_void]")?;
}

if let Some(superclass) = superclass {
writeln!(f, " unsafe impl {}: {} {{}}", id.name, superclass.name)?;
Expand All @@ -2810,10 +2819,14 @@ impl Stmt {
write!(f, "{cfg_encoding}")?;
writeln!(f, "unsafe impl RefEncode for {} {{", id.name)?;
write!(f, " const ENCODING_REF: Encoding = ")?;
writeln!(f, "Encoding::Pointer(&Encoding::Struct(")?;
writeln!(f, " {encoding_name:?},")?;
writeln!(f, " &[],")?;
writeln!(f, " ));")?;
if let Some(encoding_name) = &encoding_name {
writeln!(f, "Encoding::Pointer(&Encoding::Struct(")?;
writeln!(f, " {encoding_name:?},")?;
writeln!(f, " &[],")?;
writeln!(f, " ));")?;
} else {
writeln!(f, "Encoding::Pointer(&Encoding::Void);")?;
}
writeln!(f, "}}")?;
}
}
Expand Down
110 changes: 70 additions & 40 deletions framework-crates/objc2-core-foundation/src/cf_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,31 @@ macro_rules! cf_type {
#[encoding_name = $encoding_name:expr]
unsafe impl $ty:ident $(: $superclass:ty)? {}
) => {
$crate::__cf_type_common!($ty);
$crate::__cf_type_superclass!($ty $(: $superclass)?);

// Objective-C interop
$crate::__cf_type_objc2!(
$ty,
$crate::__cf_macro_helpers::Encoding::Struct($encoding_name, &[])
);
};
(
#[encoding_void]
unsafe impl $ty:ident $(: $superclass:ty)? {}
) => {
$crate::__cf_type_common!($ty);
$crate::__cf_type_superclass!($ty $(: $superclass)?);

// Objective-C interop
$crate::__cf_type_objc2!($ty, $crate::__cf_macro_helpers::Encoding::Void);
};
}

#[doc(hidden)]
#[macro_export]
macro_rules! __cf_type_common {
($ty:ident) => {
// Reflexive AsRef impl.
impl $crate::__cf_macro_helpers::AsRef<Self> for $ty {
#[inline]
Expand All @@ -40,67 +65,72 @@ macro_rules! cf_type {
}
}

// If has superclass.
$(
// Similar to `objc2::extern_class!`, we implement Deref for the
// type to allow easy conversion to the super class.
impl $crate::__cf_macro_helpers::Deref for $ty {
type Target = $superclass;

#[inline]
fn deref(&self) -> &Self::Target {
// SAFETY: It is valid to re-interpret a type as its superclass.
unsafe { core::mem::transmute(self) }
}
}

// Allow converting to superclasses.
// Similar to `objc2::__extern_class_impl_as_ref_borrow!`.

impl $crate::__cf_macro_helpers::AsRef<$superclass> for $ty {
#[inline]
fn as_ref(&self) -> &$superclass {
self // Through Deref
}
}

impl $crate::__cf_macro_helpers::Borrow<$superclass> for $ty {
#[inline]
fn borrow(&self) -> &$superclass {
self // Through Deref
}
}
)?

impl $crate::__cf_macro_helpers::fmt::Debug for $ty {
fn fmt(&self, f: &mut $crate::__cf_macro_helpers::fmt::Formatter<'_>) -> $crate::__cf_macro_helpers::fmt::Result {
f.debug_struct($crate::__cf_macro_helpers::stringify!($ty)).finish_non_exhaustive()
fn fmt(
&self,
f: &mut $crate::__cf_macro_helpers::fmt::Formatter<'_>,
) -> $crate::__cf_macro_helpers::fmt::Result {
f.debug_struct($crate::__cf_macro_helpers::stringify!($ty))
.finish_non_exhaustive()
}
}
};
}

#[doc(hidden)]
#[macro_export]
macro_rules! __cf_type_superclass {
// No superclass
($ty:ident) => {
// NOTE: We intentionally don't implement `Deref` with
// `Target = AnyObject` when there isn't a superclass, as we want
// conversions to Objective-C types to be explicit.
//
// TODO: Maybe implement `Deref<Target = CFTypeRef>`?
};
// If has superclass.
($ty:ident: $superclass:ty) => {
// Similar to `objc2::extern_class!`, we implement Deref for the
// type to allow easy conversion to the super class.
impl $crate::__cf_macro_helpers::Deref for $ty {
type Target = $superclass;

// Objective-C interop
$crate::__cf_type_objc2!($ty, $encoding_name);
#[inline]
fn deref(&self) -> &Self::Target {
// SAFETY: It is valid to re-interpret a type as its superclass.
unsafe { core::mem::transmute(self) }
}
}

// Allow converting to superclasses.
// Similar to `objc2::__extern_class_impl_as_ref_borrow!`.

impl $crate::__cf_macro_helpers::AsRef<$superclass> for $ty {
#[inline]
fn as_ref(&self) -> &$superclass {
self // Through Deref
}
}

impl $crate::__cf_macro_helpers::Borrow<$superclass> for $ty {
#[inline]
fn borrow(&self) -> &$superclass {
self // Through Deref
}
}
};
}

#[cfg(feature = "objc2")]
#[doc(hidden)]
#[macro_export]
macro_rules! __cf_type_objc2 {
($ty:ty, $encoding_name:expr) => {
($ty:ty, $encoding:expr) => {
// SAFETY: Caller upholds that the struct is a ZST type, and
// represents a C struct with the given encoding.
unsafe impl $crate::__cf_macro_helpers::RefEncode for $ty {
const ENCODING_REF: $crate::__cf_macro_helpers::Encoding =
$crate::__cf_macro_helpers::Encoding::Pointer(
&$crate::__cf_macro_helpers::Encoding::Struct($encoding_name, &[]),
);
$crate::__cf_macro_helpers::Encoding::Pointer(&$encoding);
}

// SAFETY: CF types are message-able in the Objective-C runtime.
Expand Down

0 comments on commit c37bb63

Please sign in to comment.