Skip to main content

windows_interface/
lib.rs

1//! Define COM interfaces to call or implement.
2//!
3//! See [`interface`] for an example.
4
5use syn::spanned::Spanned;
6
7mod generation;
8mod guid;
9pub(crate) use guid::Guid;
10
11#[cfg(test)]
12mod tests;
13
14/// Defines a COM interface to call or implement.
15///
16/// ```
17/// use windows_core::*;
18///
19/// #[interface("094d70d6-5202-44b8-abb8-43860da5aca2")]
20/// unsafe trait IValue: IUnknown {
21///     fn GetValue(&self, value: *mut i32) -> HRESULT;
22/// }
23///
24/// #[implement(IValue)]
25/// struct Value(i32);
26///
27/// impl IValue_Impl for Value_Impl {
28///     unsafe fn GetValue(&self, value: *mut i32) -> HRESULT {
29///         unsafe { *value = self.0 };
30///         HRESULT(0)
31///     }
32/// }
33///
34/// let _: IValue = Value(123).into();
35/// ```
36#[proc_macro_attribute]
37pub fn interface(
38    attributes: proc_macro::TokenStream,
39    original_type: proc_macro::TokenStream,
40) -> proc_macro::TokenStream {
41    interface_core(attributes.into(), original_type.into()).into()
42}
43
44fn interface_core(
45    attributes: proc_macro2::TokenStream,
46    item_tokens: proc_macro2::TokenStream,
47) -> proc_macro2::TokenStream {
48    let guid = match syn::parse2::<Guid>(attributes) {
49        Ok(g) => g,
50        Err(e) => return e.into_compile_error(),
51    };
52    let interface = match syn::parse2::<Interface>(item_tokens) {
53        Ok(i) => i,
54        Err(e) => return e.into_compile_error(),
55    };
56    match interface.gen_tokens(&guid) {
57        Ok(t) => t,
58        Err(e) => e.into_compile_error(),
59    }
60}
61
62/// A parsed `#[interface]` trait definition.
63pub(crate) struct Interface {
64    pub(crate) visibility: syn::Visibility,
65    pub(crate) name: syn::Ident,
66    pub(crate) parent: Option<syn::Path>,
67    pub(crate) methods: Vec<InterfaceMethod>,
68    pub(crate) docs: Vec<syn::Attribute>,
69}
70
71impl syn::parse::Parse for Interface {
72    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
73        let attributes = input.call(syn::Attribute::parse_outer)?;
74        let mut docs = Vec::new();
75        for attr in attributes.into_iter() {
76            let path = attr.path();
77            if path.is_ident("doc") {
78                docs.push(attr);
79            } else {
80                return Err(syn::Error::new(path.span(), "Unrecognized attribute"));
81            }
82        }
83
84        let visibility = input.parse::<syn::Visibility>()?;
85        _ = input.parse::<syn::Token![unsafe]>()?;
86        _ = input.parse::<syn::Token![trait]>()?;
87        let name = input.parse::<syn::Ident>()?;
88        _ = input.parse::<syn::Token![:]>();
89        let parent = input.parse::<syn::Path>().ok();
90        let content;
91        syn::braced!(content in input);
92        let mut methods = Vec::new();
93        while !content.is_empty() {
94            methods.push(content.parse::<InterfaceMethod>()?);
95        }
96        Ok(Self {
97            visibility,
98            methods,
99            name,
100            parent,
101            docs,
102        })
103    }
104}
105
106/// A method declaration inside an `#[interface]` trait.
107pub(crate) struct InterfaceMethod {
108    pub(crate) name: syn::Ident,
109    pub(crate) visibility: syn::Visibility,
110    pub(crate) args: Vec<InterfaceMethodArg>,
111    pub(crate) ret: syn::ReturnType,
112    pub(crate) docs: Vec<syn::Attribute>,
113}
114
115impl syn::parse::Parse for InterfaceMethod {
116    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
117        let docs = input.call(syn::Attribute::parse_outer)?;
118        let visibility = input.parse::<syn::Visibility>()?;
119        let method = input.parse::<syn::TraitItemFn>()?;
120
121        // Reject non-doc attributes.
122        if let Some(i) = docs.iter().find(|a| !a.path().is_ident("doc")) {
123            return Err(syn::Error::new(i.span(), "unexpected attribute"));
124        }
125        // Reject default method bodies.
126        if let Some(i) = &method.default {
127            return Err(syn::Error::new(
128                i.span(),
129                "unexpected default method implementation",
130            ));
131        }
132
133        let sig = method.sig;
134
135        // Reject unsupported function-signature features.
136        if let Some(i) = &sig.abi {
137            return Err(syn::Error::new(i.span(), "unexpected abi declaration"));
138        }
139        if let Some(i) = &sig.asyncness {
140            return Err(syn::Error::new(i.span(), "unexpected async declaration"));
141        }
142        if let Some(i) = sig.generics.params.iter().next() {
143            return Err(syn::Error::new(i.span(), "unexpected generics declaration"));
144        }
145        if let Some(i) = &sig.constness {
146            return Err(syn::Error::new(i.span(), "unexpected const declaration"));
147        }
148        if sig.receiver().is_none() {
149            return Err(syn::Error::new(
150                sig.span(),
151                "expected the method to have &self as its first argument",
152            ));
153        }
154        if let Some(i) = &sig.variadic {
155            return Err(syn::Error::new(i.span(), "unexpected variadic args"));
156        }
157
158        let args = sig
159            .inputs
160            .into_iter()
161            .filter_map(|a| match a {
162                syn::FnArg::Receiver(_) => None,
163                syn::FnArg::Typed(p) => Some(p),
164            })
165            .map(|p| {
166                Ok(InterfaceMethodArg {
167                    ty: p.ty,
168                    pat: p.pat,
169                })
170            })
171            .collect::<Result<Vec<InterfaceMethodArg>, syn::Error>>()?;
172
173        let ret = sig.output;
174        Ok(Self {
175            name: sig.ident,
176            visibility,
177            args,
178            ret,
179            docs,
180        })
181    }
182}
183
184/// A single argument in an [`InterfaceMethod`].
185pub(crate) struct InterfaceMethodArg {
186    /// The type of the argument.
187    pub(crate) ty: Box<syn::Type>,
188    /// The pattern (name) of the argument.
189    pub(crate) pat: Box<syn::Pat>,
190}