Skip to content

Commit

Permalink
Fix TCFType macros for generic types (#652)
Browse files Browse the repository at this point in the history
* Improve TCFType macros

This adds the following new features:

* `declare_TCFType!`: Generics are accepted.
* `impl_TCFType!`: Non-defaulted generics are accepted, and impls are
  fixed to be for all generics.

In addition, some warnings are silenced and the macros no longer depend
on any traits being in scope in the caller.

* Support generics in impl_CFComparison

* Add generic test for macros
  • Loading branch information
tmandry authored Aug 13, 2024
1 parent fb71d45 commit 9d8c74e
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 19 deletions.
2 changes: 0 additions & 2 deletions core-foundation/src/characterset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@

pub use core_foundation_sys::characterset::*;

use crate::base::TCFType;

declare_TCFType! {
/// An immutable set of Unicode characters.
CFCharacterSet, CFCharacterSetRef
Expand Down
57 changes: 40 additions & 17 deletions core-foundation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,25 @@ macro_rules! declare_TCFType {
(
$(#[$doc:meta])*
$ty:ident, $raw:ident
) => {
declare_TCFType!($(#[$doc])* $ty<>, $raw);
};

(
$(#[$doc:meta])*
$ty:ident<$($p:ident $(: $bound:path)*),*>, $raw:ident
) => {
$(#[$doc])*
pub struct $ty($raw);
pub struct $ty<$($p $(: $bound)*),*>($raw, $(::std::marker::PhantomData<$p>),*);

impl Drop for $ty {
#[allow(unused_imports)]
impl<$($p $(: $bound)*),*> Drop for $ty<$($p),*> {
fn drop(&mut self) {
use $crate::base::TCFType;
unsafe { $crate::base::CFRelease(self.as_CFTypeRef()) }
}
}
}
};
}

/// Provide an implementation of the [`TCFType`] trait for the Rust
Expand All @@ -82,6 +91,7 @@ macro_rules! impl_TCFType {
impl<$($p $(: $bound)*),*> $crate::base::TCFType for $ty<$($p),*> {
type Ref = $ty_ref;

#[allow(non_snake_case)]
#[inline]
fn as_concrete_TypeRef(&self) -> $ty_ref {
self.0
Expand All @@ -94,6 +104,7 @@ macro_rules! impl_TCFType {
$crate::base::TCFType::wrap_under_create_rule(reference)
}

#[allow(non_snake_case)]
#[inline]
fn as_CFTypeRef(&self) -> $crate::base::CFTypeRef {
self.as_concrete_TypeRef() as $crate::base::CFTypeRef
Expand All @@ -115,39 +126,46 @@ macro_rules! impl_TCFType {
}
}

impl Clone for $ty {
#[allow(unused_imports)]
impl<$($p $(: $bound)*),*> Clone for $ty<$($p),*> {
#[inline]
fn clone(&self) -> $ty {
fn clone(&self) -> Self {
use $crate::base::TCFType;
unsafe {
$ty::wrap_under_get_rule(self.0)
}
}
}

impl PartialEq for $ty {
#[allow(unused_imports)]
impl<$($p $(: $bound)*),*> PartialEq for $ty<$($p),*> {
#[inline]
fn eq(&self, other: &$ty) -> bool {
fn eq(&self, other: &Self) -> bool {
use $crate::base::TCFType;
self.as_CFType().eq(&other.as_CFType())
}
}

impl Eq for $ty { }
impl<$($p $(: $bound)*),*> Eq for $ty<$($p),*> { }

unsafe impl<'a> $crate::base::ToVoid<$ty> for &'a $ty {
#[allow(unused_imports)]
unsafe impl<'a, $($p $(: $bound)*),*> $crate::base::ToVoid<$ty<$($p),*>> for &'a $ty<$($p),*> {
fn to_void(&self) -> *const ::core::ffi::c_void {
use $crate::base::TCFTypeRef;
use $crate::base::{TCFType, TCFTypeRef};
self.as_concrete_TypeRef().as_void_ptr()
}
}

unsafe impl $crate::base::ToVoid<$ty> for $ty {
#[allow(unused_imports)]
unsafe impl<$($p $(: $bound)*),*> $crate::base::ToVoid<$ty<$($p),*>> for $ty<$($p),*> {
fn to_void(&self) -> *const ::core::ffi::c_void {
use $crate::base::TCFTypeRef;
use $crate::base::{TCFType, TCFTypeRef};
self.as_concrete_TypeRef().as_void_ptr()
}
}

unsafe impl $crate::base::ToVoid<$ty> for $ty_ref {
#[allow(unused_imports)]
unsafe impl<$($p $(: $bound)*),*> $crate::base::ToVoid<$ty<$($p),*>> for $ty_ref {
fn to_void(&self) -> *const ::core::ffi::c_void {
use $crate::base::TCFTypeRef;
self.as_void_ptr()
Expand Down Expand Up @@ -178,8 +196,10 @@ macro_rules! impl_CFTypeDescription {
impl_CFTypeDescription!($ty<>);
};
($ty:ident<$($p:ident $(: $bound:path)*),*>) => {
#[allow(unused_imports)]
impl<$($p $(: $bound)*),*> ::std::fmt::Debug for $ty<$($p),*> {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
use $crate::base::TCFType;
self.as_CFType().fmt(f)
}
}
Expand All @@ -189,9 +209,12 @@ macro_rules! impl_CFTypeDescription {
#[macro_export]
macro_rules! impl_CFComparison {
($ty:ident, $compare:ident) => {
impl PartialOrd for $ty {
impl_CFComparison!($ty<>, $compare);
};
($ty:ident<$($p:ident $(: $bound:path)*),*>, $compare:ident) => {
impl<$($p $(: $bound)*),*> PartialOrd for $ty<$($p),*> {
#[inline]
fn partial_cmp(&self, other: &$ty) -> Option<::std::cmp::Ordering> {
fn partial_cmp(&self, other: &$ty<$($p),*>) -> Option<::std::cmp::Ordering> {
unsafe {
Some(
$compare(
Expand All @@ -205,9 +228,9 @@ macro_rules! impl_CFComparison {
}
}

impl Ord for $ty {
impl<$($p $(: $bound)*),*> Ord for $ty<$($p),*> {
#[inline]
fn cmp(&self, other: &$ty) -> ::std::cmp::Ordering {
fn cmp(&self, other: &$ty<$($p),*>) -> ::std::cmp::Ordering {
self.partial_cmp(other).unwrap()
}
}
Expand Down
5 changes: 5 additions & 0 deletions core-foundation/tests/use_macro_outside_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ declare_TCFType!(CFFooBar, CFFooBarRef);
impl_TCFType!(CFFooBar, CFFooBarRef, CFFooBarGetTypeID);
impl_CFTypeDescription!(CFFooBar);
impl_CFComparison!(CFFooBar, fake_compare);

declare_TCFType!(CFGenericFooBar<T: Clone>, CFFooBarRef);
impl_TCFType!(CFGenericFooBar<T: Clone>, CFFooBarRef, CFFooBarGetTypeID);
impl_CFTypeDescription!(CFGenericFooBar<T: Clone>);
impl_CFComparison!(CFGenericFooBar<T: Clone>, fake_compare);

0 comments on commit 9d8c74e

Please sign in to comment.