com_rs/
macros.rs

1// Copyright (c) 2016 com-rs developers
2//
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
5// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. All files in the project carrying such notice may not be copied,
7// modified, or distributed except according to those terms.
8
9/**
10Macro for generating COM interface definitions.
11
12# Usage
13```
14#[macro_use]
15extern crate com_rs;
16use com_rs::IUnknown;
17
18iid!(IID_IFOO =
19    0x12345678, 0x90AB, 0xCDEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF);
20
21com_interface! {
22    interface IFoo: IUnknown {
23        iid: IID_IFOO,
24        vtable: IFooVtbl,
25        fn foo() -> bool;
26    }
27}
28# fn main() { }
29```
30
31This example defines an interface called `IFoo`. In this case, the base type is
32IUnknown, the root COM type. The IID for the interface must also be defined,
33along with the name of the vtable type, `IFooVtbl`. This isn't publicly exposed,
34but there is currently no way to generate an ident within a macro so the callee
35must define one instead.
36
37The trait `Foo` defines the methods available for the interface, in this case
38a single method named `foo`. Note that any methods that return no value
39(e.g. the `void` type in C/C++) should return the unit type `()`.
40
41## Inheritance
42To define interfaces with a deeper hierarchy, add additional parent identifiers
43to the type definitions. e.g:
44
45```
46# #[macro_use]
47# extern crate com_rs;
48# use com_rs::IUnknown;
49# iid!(IID_IFOO = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
50# com_interface! {
51#     interface IFoo: IUnknown {
52#         iid: IID_IFOO,
53#         vtable: IFooVtbl,
54#         fn foo() -> bool;
55#     }
56# }
57iid!(IID_IBAR =
58    0x12345678, 0x90AB, 0xCDEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF);
59com_interface! {
60    interface IBar: IFoo, IUnknown {
61        iid: IID_IBAR,
62        vtable: IBarVtbl,
63        fn bar(baz: i32) -> ();
64    }
65}
66# fn main() { }
67```
68
69This example defines an interface called `IBar` which extends `IFoo` from the
70previous example. Note that it is necessary to specify the parent types
71for both the interface and trait declarations.
72
73The interface hierarchy automates pointer conversion using the `AsComPtr` trait,
74and the trait hierarchy automatically implements the parent methods for the
75child interface.
76*/
77#[macro_export]
78macro_rules! com_interface {
79    (
80        $(#[$iface_attr:meta])*
81        interface $iface:ident: $base_iface:ty {
82            iid: $iid:ident,
83            vtable: $vtable:ident,
84            $(
85                $(#[$fn_attr:meta])*
86                fn $func:ident($($i:ident: $t:ty),*) -> $rt:ty;
87            )*
88        }
89    ) => (
90        #[allow(missing_debug_implementations)]
91        #[doc(hidden)]
92        #[repr(C)]
93        pub struct $vtable {
94            base: <$base_iface as $crate::ComInterface>::Vtable,
95            $($func: extern "stdcall" fn(*const $iface, $($t),*) -> $rt),*
96        }
97
98        $(#[$iface_attr])*
99        #[derive(Debug)]
100        #[repr(C)]
101        pub struct $iface {
102            vtable: *const $vtable
103        }
104
105        impl $iface {
106            $($(#[$fn_attr])*
107            pub unsafe fn $func(&self, $($i: $t),*) -> $rt {
108                ((*self.vtable).$func)(self $(,$i)*)
109            })*
110        }
111
112        impl ::std::ops::Deref for $iface {
113            type Target = $base_iface;
114            fn deref(&self) -> &$base_iface {
115                unsafe { ::std::mem::transmute(self) }
116            }
117        }
118
119        unsafe impl $crate::AsComPtr<$iface> for $iface {}
120        unsafe impl $crate::AsComPtr<$base_iface> for $iface {}
121
122        unsafe impl $crate::ComInterface for $iface {
123            #[doc(hidden)]
124            type Vtable = $vtable;
125            #[allow(unused_unsafe)]
126            fn iid() -> $crate::IID { unsafe { $iid } }
127        }
128    );
129
130    (
131        $(#[$iface_attr:meta])*
132        interface $iface:ident: $base_iface:ty, $($extra_base:ty),+ {
133            iid: $iid:ident,
134            vtable: $vtable:ident,
135            $(
136                $(#[$fn_attr:meta])*
137                fn $func:ident($($i:ident: $t:ty),*) -> $rt:ty;
138            )*
139        }
140    ) => (
141        com_interface! {
142            $(#[$iface_attr])*
143            interface $iface: $base_iface {
144                iid: $iid,
145                vtable: $vtable,
146                $($(#[$fn_attr])* fn $func($($i: $t),*) -> $rt;)*
147            }
148        }
149
150        $(unsafe impl $crate::AsComPtr<$extra_base> for $iface {})*
151    )
152}
153
154/**
155Helper macro for defining [`IID`](struct.IID.html) constants.
156
157# Usage
158```
159# #[macro_use]
160# extern crate com_rs;
161iid!(IID_IFOO = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
162# fn main() {}
163```
164
165IIDs are private by default as they are only supposed to be exposed by the
166`ComPtr::iid` method. If you want to make them public, just add the `pub`
167keyword before the identifier.
168
169```
170# #[macro_use]
171# extern crate com_rs;
172iid!(pub IID_IBAR = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
173# fn main() {}
174```
175
176*/
177#[macro_export]
178macro_rules! iid {
179    ($(#[$iid_attr:meta])*
180    $name:ident = $d1:expr, $d2:expr, $d3:expr, $($d4:expr),*) => (
181        $(#[$iid_attr])*
182        const $name: $crate::IID = $crate::IID {
183            data1: $d1,
184            data2: $d2,
185            data3: $d3,
186            data4: [$($d4),*],
187        };
188    );
189    ($(#[$iid_attr:meta])*
190    pub $name:ident = $d1:expr, $d2:expr, $d3:expr, $($d4:expr),*) => (
191        $(#[$iid_attr])*
192        pub const $name: $crate::IID = $crate::IID {
193            data1: $d1,
194            data2: $d2,
195            data3: $d3,
196            data4: [$($d4),*],
197        };
198    );
199}