Skip to content

Commit

Permalink
use tuples for specifying interface lists
Browse files Browse the repository at this point in the history
Instead of the impl_class! macro, introduce an InterfaceList trait with
blanket impls for tuples of Interfaces up to size 15, and have classes
specify their interfaces via the Class::Interfaces associated type.
  • Loading branch information
glowcoil committed Jun 9, 2023
1 parent ed15fd7 commit 1175028
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 182 deletions.
137 changes: 79 additions & 58 deletions com-scrape-types/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,8 @@ use std::sync::Arc;

use super::{ComPtr, ComRef, Guid, Interface};

#[doc(hidden)]
#[macro_export]
macro_rules! impl_class_inner {
($class:ident: $($interface:ident),* $(,)?) => {
#[allow(non_snake_case)]
const _: () = {
struct __Header {
$($interface: $interface,)*
}

unsafe impl $crate::Class for $class {
type Header = __Header;

#[inline]
fn header<W: $crate::Wrapper<Self>>() -> Self::Header {
__Header {
$(
$interface: <$interface as $crate::Construct<$class, W, { unsafe { $crate::offset_of!(__Header, $interface) } }>>::OBJ,
)*
}
}

#[inline]
fn query_interface(iid: &$crate::Guid) -> Option<isize> {
$(
if <$interface as $crate::Interface>::inherits(iid) {
return Some(unsafe { $crate::offset_of!(__Header, $interface) });
}
)*

None
}
}
};
}
}

#[macro_export]
macro_rules! impl_class {
($class:ident: $interface:ident $(+ $interfaces:ident)* $(+)?) => {
$crate::impl_class_inner!($class: $interface, $($interfaces),*);
}
}

#[macro_export]
macro_rules! offset_of {
($struct:ty, $field:ident) => {{
($struct:ty, $field:tt) => {{
use ::std::ffi::c_void;
use ::std::mem::MaybeUninit;
use ::std::ptr::addr_of;
Expand All @@ -64,8 +19,8 @@ macro_rules! offset_of {
}

pub trait Wrapper<C: Class + ?Sized> {
unsafe fn data_from_header(ptr: *mut C::Header) -> *mut C;
unsafe fn header_from_data(ptr: *mut C) -> *mut C::Header;
unsafe fn data_from_header(ptr: *mut Header<C>) -> *mut C;
unsafe fn header_from_data(ptr: *mut C) -> *mut Header<C>;
unsafe fn add_ref(ptr: *mut C) -> usize;
unsafe fn release(ptr: *mut C) -> usize;
}
Expand All @@ -74,16 +29,81 @@ pub trait Construct<C, W, const OFFSET: isize> {
const OBJ: Self;
}

pub unsafe trait Class {
pub unsafe trait InterfaceList {
type Header;

fn header<W: Wrapper<Self>>() -> Self::Header;
fn query_interface(iid: &Guid) -> Option<isize>;
fn query(iid: &Guid) -> Option<isize>;
}

pub trait MakeHeader<C, W>: InterfaceList
where
C: Class,
W: Wrapper<C>,
{
fn header() -> Self::Header;
}

pub trait Class {
type Interfaces: InterfaceList;
}

pub type Header<C> = <<C as Class>::Interfaces as InterfaceList>::Header;

pub unsafe trait Implements<I> {
const OFFSET: isize;
}

macro_rules! interface_list {
($header:ident, $($interface:ident $index:tt),*) => {
#[repr(C)]
pub struct $header<$($interface),*>($($interface),*);

unsafe impl<$($interface: Interface),*> InterfaceList for ($($interface,)*) {
type Header = $header<$($interface),*>;

fn query(iid: &Guid) -> Option<isize> {
$(
if $interface::inherits(iid) {
return Some(unsafe { offset_of!(Self::Header, $index) });
}
)*

None
}
}

impl<C, W $(, $interface)*> MakeHeader<C, W> for ($($interface,)*)
where
C: Class,
W: Wrapper<C>,
$($interface: Interface + Construct<C, W, { $index * std::mem::size_of::<*mut ()>() as isize }>,)*
{
fn header() -> Self::Header {
$header($($interface::OBJ),*)
}
}
}
}

interface_list!(Header1, I0 0);
interface_list!(Header2, I0 0, I1 1);
interface_list!(Header3, I0 0, I1 1, I2 2);
interface_list!(Header4, I0 0, I1 1, I2 2, I3 3);
interface_list!(Header5, I0 0, I1 1, I2 2, I3 3, I4 4);
interface_list!(Header6, I0 0, I1 1, I2 2, I3 3, I4 4, I5 5);
interface_list!(Header7, I0 0, I1 1, I2 2, I3 3, I4 4, I5 5, I6 6);
interface_list!(Header8, I0 0, I1 1, I2 2, I3 3, I4 4, I5 5, I6 6, I7 7);
interface_list!(Header9, I0 0, I1 1, I2 2, I3 3, I4 4, I5 5, I6 6, I7 7, I8 8);
interface_list!(Header10, I0 0, I1 1, I2 2, I3 3, I4 4, I5 5, I6 6, I7 7, I8 8, I9 9);
interface_list!(Header11, I0 0, I1 1, I2 2, I3 3, I4 4, I5 5, I6 6, I7 7, I8 8, I9 9, I10 10);
interface_list!(Header12, I0 0, I1 1, I2 2, I3 3, I4 4, I5 5, I6 6, I7 7, I8 8, I9 9, I10 10, I11 11);
interface_list!(Header13, I0 0, I1 1, I2 2, I3 3, I4 4, I5 5, I6 6, I7 7, I8 8, I9 9, I10 10, I11 11, I12 12);
interface_list!(Header14, I0 0, I1 1, I2 2, I3 3, I4 4, I5 5, I6 6, I7 7, I8 8, I9 9, I10 10, I11 11, I12 12, I13 13);
interface_list!(Header15, I0 0, I1 1, I2 2, I3 3, I4 4, I5 5, I6 6, I7 7, I8 8, I9 9, I10 10, I11 11, I12 12, I13 13, I14 14);

#[repr(C)]
struct ComWrapperInner<C: Class> {
header: C::Header,
header: Header<C>,
data: C,
}

Expand Down Expand Up @@ -113,17 +133,17 @@ impl<C: Class> Deref for ComWrapper<C> {

impl<C: Class> Wrapper<C> for ComWrapper<C> {
#[inline]
unsafe fn data_from_header(ptr: *mut C::Header) -> *mut C {
unsafe fn data_from_header(ptr: *mut Header<C>) -> *mut C {
(ptr as *mut u8)
.offset(-offset_of!(ComWrapperInner<C>, header))
.offset(offset_of!(ComWrapperInner<C>, data)) as *mut C
}

#[inline]
unsafe fn header_from_data(ptr: *mut C) -> *mut C::Header {
unsafe fn header_from_data(ptr: *mut C) -> *mut Header<C> {
(ptr as *mut u8)
.offset(-offset_of!(ComWrapperInner<C>, data))
.offset(offset_of!(ComWrapperInner<C>, header)) as *mut C::Header
.offset(offset_of!(ComWrapperInner<C>, header)) as *mut Header<C>
}

#[inline]
Expand Down Expand Up @@ -160,18 +180,19 @@ impl<C: Class> ComWrapper<C> {
pub fn new(data: C) -> ComWrapper<C>
where
C: 'static,
C::Interfaces: MakeHeader<C, Self>,
{
ComWrapper {
inner: Arc::new(ComWrapperInner {
header: C::header::<Self>(),
header: C::Interfaces::header(),
data,
}),
}
}

#[inline]
pub fn as_com_ref<'a, I: Interface>(&'a self) -> Option<ComRef<'a, I>> {
if let Some(offset) = C::query_interface(&I::IID) {
if let Some(offset) = C::Interfaces::query(&I::IID) {
unsafe {
let wrapper_ptr = Arc::as_ptr(&self.inner) as *mut ComWrapperInner<C>;
let interface_ptr = (wrapper_ptr as *mut u8)
Expand All @@ -186,7 +207,7 @@ impl<C: Class> ComWrapper<C> {

#[inline]
pub fn to_com_ptr<I: Interface>(&self) -> Option<ComPtr<I>> {
if let Some(offset) = C::query_interface(&I::IID) {
if let Some(offset) = C::Interfaces::query(&I::IID) {
unsafe {
let wrapper_ptr = Arc::into_raw(self.inner.clone()) as *mut ComWrapperInner<C>;
let interface_ptr = (wrapper_ptr as *mut u8)
Expand Down
2 changes: 1 addition & 1 deletion com-scrape-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ mod tests;

use std::ffi::c_void;

pub use class::{Class, ComWrapper, Construct, Wrapper};
pub use class::{Class, ComWrapper, Construct, Header, InterfaceList, Wrapper};
pub use ptr::{ComPtr, ComRef, SmartPtr};

pub type Guid = [u8; 16];
Expand Down
124 changes: 10 additions & 114 deletions com-scrape-types/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ impl IUnknown {
C: Class,
W: Wrapper<C>,
{
let header_ptr = (this as *mut u8).offset(-OFFSET) as *mut C::Header;
if let Some(result) = C::query_interface(&*(_iid as *const Guid)) {
let header_ptr = (this as *mut u8).offset(-OFFSET) as *mut Header<C>;
if let Some(result) = C::Interfaces::query(&*(_iid as *const Guid)) {
let ptr = W::data_from_header(header_ptr);
W::add_ref(ptr);

Expand All @@ -85,7 +85,7 @@ impl IUnknown {
C: Class,
W: Wrapper<C>,
{
let header_ptr = (this as *mut u8).offset(-OFFSET) as *mut C::Header;
let header_ptr = (this as *mut u8).offset(-OFFSET) as *mut Header<C>;
let ptr = W::data_from_header(header_ptr);
W::add_ref(ptr) as c_ulong
}
Expand All @@ -95,7 +95,7 @@ impl IUnknown {
C: Class,
W: Wrapper<C>,
{
let header_ptr = (this as *mut u8).offset(-OFFSET) as *mut C::Header;
let header_ptr = (this as *mut u8).offset(-OFFSET) as *mut Header<C>;
let ptr = W::data_from_header(header_ptr);
W::release(ptr) as c_ulong
}
Expand Down Expand Up @@ -184,7 +184,7 @@ impl IMyInterface {
C: IMyInterfaceTrait + Class,
W: Wrapper<C>,
{
let header_ptr = (this as *mut u8).offset(-OFFSET) as *mut C::Header;
let header_ptr = (this as *mut u8).offset(-OFFSET) as *mut Header<C>;
let ptr = W::data_from_header(header_ptr);
(*ptr).my_method()
}
Expand Down Expand Up @@ -272,7 +272,7 @@ impl IOtherInterface {
C: IOtherInterfaceTrait + Class,
W: Wrapper<C>,
{
let header_ptr = (this as *mut u8).offset(-OFFSET) as *mut C::Header;
let header_ptr = (this as *mut u8).offset(-OFFSET) as *mut Header<C>;
let ptr = W::data_from_header(header_ptr);
(*ptr).other_method()
}
Expand Down Expand Up @@ -421,6 +421,10 @@ struct MyClass2 {
dropped: Rc<Cell<bool>>,
}

impl Class for MyClass2 {
type Interfaces = (IMyInterface, IOtherInterface);
}

impl Drop for MyClass2 {
fn drop(&mut self) {
self.dropped.set(true);
Expand All @@ -439,43 +443,6 @@ impl IOtherInterfaceTrait for MyClass2 {
}
}

struct MyClass2Header {
my_interface: IMyInterface,
other_interface: IOtherInterface,
}

unsafe impl Class for MyClass2 {
type Header = MyClass2Header;

fn header<W: Wrapper<Self>>() -> Self::Header {
MyClass2Header {
my_interface: <IMyInterface as Construct<
Self,
W,
{ unsafe { offset_of!(MyClass2Header, my_interface) } },
>>::OBJ,
other_interface: <IOtherInterface as Construct<
Self,
W,
{ unsafe { offset_of!(MyClass2Header, other_interface) } },
>>::OBJ,
}
}

#[inline]
fn query_interface(iid: &Guid) -> Option<isize> {
if IMyInterface::inherits(iid) {
return Some(unsafe { offset_of!(MyClass2Header, my_interface) });
}

if IOtherInterface::inherits(iid) {
return Some(unsafe { offset_of!(MyClass2Header, other_interface) });
}

None
}
}

#[test]
fn com_wrapper() {
let dropped = Rc::new(Cell::new(false));
Expand Down Expand Up @@ -520,74 +487,3 @@ fn com_wrapper() {
drop(com_ptr_4);
assert_eq!(dropped.get(), true);
}

struct MyClass3 {
x: u32,
y: u32,
dropped: Rc<Cell<bool>>,
}

impl_class!(MyClass3: IMyInterface + IOtherInterface);

impl Drop for MyClass3 {
fn drop(&mut self) {
self.dropped.set(true);
}
}

impl IMyInterfaceTrait for MyClass3 {
fn my_method(&self) -> u32 {
self.x
}
}

impl IOtherInterfaceTrait for MyClass3 {
fn other_method(&self) -> u32 {
self.y
}
}

#[test]
fn impl_class_macro() {
let dropped = Rc::new(Cell::new(false));
let obj = ComWrapper::new(MyClass3 {
x: 1,
y: 2,
dropped: dropped.clone(),
});

let com_ref_1 = obj.as_com_ref::<IMyInterface>().unwrap();
assert_eq!(com_ref_1.my_method(), 1);

let com_ref_2 = obj.as_com_ref::<IOtherInterface>().unwrap();
assert_eq!(com_ref_2.other_method(), 2);

let com_ptr_1 = com_ref_2
.upcast::<IUnknown>()
.cast::<IMyInterface>()
.unwrap();
assert_eq!(com_ptr_1.my_method(), 1);

let com_ptr_2 = com_ref_1
.upcast::<IUnknown>()
.cast::<IOtherInterface>()
.unwrap();
assert_eq!(com_ptr_2.other_method(), 2);

assert_eq!(dropped.get(), false);

let com_ptr_3 = obj.to_com_ptr::<IMyInterface>().unwrap();
assert_eq!(com_ptr_3.my_method(), 1);

let com_ptr_4 = obj.to_com_ptr::<IOtherInterface>().unwrap();
assert_eq!(com_ptr_4.other_method(), 2);

drop(obj);
drop(com_ptr_1);
drop(com_ptr_2);
drop(com_ptr_3);
assert_eq!(dropped.get(), false);

drop(com_ptr_4);
assert_eq!(dropped.get(), true);
}
2 changes: 1 addition & 1 deletion com-scrape/src/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ impl<'a, W: Write> RustPrinter<'a, W> {
writeln!(self.sink, "{indent} C: {name}Trait + ::com_scrape_types::Class,")?;
writeln!(self.sink, "{indent} W: ::com_scrape_types::Wrapper<C>,")?;
writeln!(self.sink, "{indent} {{")?;
writeln!(self.sink, "{indent} let header_ptr = (this as *mut u8).offset(-OFFSET) as *mut C::Header;")?;
writeln!(self.sink, "{indent} let header_ptr = (this as *mut u8).offset(-OFFSET) as *mut Header<C>;")?;
writeln!(self.sink, "{indent} let ptr = <W as ::com_scrape_types::Wrapper<C>>::data_from_header(header_ptr);")?;
writeln!(self.sink, "{indent} (*ptr).{method_name}(")?;

Expand Down
Loading

0 comments on commit 1175028

Please sign in to comment.