pipewire_wrapper_macro_impl/
spa_interface.rs

1use proc_macro2::{Ident, TokenStream};
2use quote::quote;
3use syn::parse::{Parse, ParseStream};
4use syn::{parse2, Token, Type};
5
6use crate::derive_raw_wrapper::WrappedRawStructInfo;
7use crate::ARG_METHODS;
8
9struct SpaInterfaceAttr {
10    methods: Type,
11}
12
13impl Parse for SpaInterfaceAttr {
14    fn parse(input: ParseStream) -> syn::Result<Self> {
15        let methods_arg_ident: Ident = input.parse()?;
16        let _name_value_separator: Token![=] = input.parse()?;
17        let methods_arg_value: Type = input.parse()?;
18
19        if methods_arg_ident == ARG_METHODS {
20            Ok(Self {
21                methods: methods_arg_value,
22            })
23        } else {
24            Err(input.error(format!(
25                "Expected single methods = MethodsStructType attribute argument, found {}",
26                input
27            )))
28        }
29    }
30}
31
32pub fn spa_interface(attr: TokenStream, input: TokenStream) -> TokenStream {
33    let struct_info = match parse2::<WrappedRawStructInfo>(input.clone()) {
34        Ok(parsed) => parsed,
35        Err(error) => return error.to_compile_error(),
36    };
37    let spa_interface_attr = match parse2::<SpaInterfaceAttr>(attr) {
38        Ok(parsed) => parsed,
39        Err(error) => return error.to_compile_error(),
40    };
41
42    let struct_ident = &struct_info.struct_ident;
43    let raw_field_ident = &struct_info.raw_field.ident;
44    let methods_type = spa_interface_attr.methods;
45
46    quote!(
47        #input
48
49        impl crate::wrapper::SpaInterface for #struct_ident {
50            type Methods = #methods_type;
51
52            fn spa_interface(&self) -> &crate::spa::interface::InterfaceRef {
53                use crate::wrapper::RawWrapper;
54                unsafe {
55                    assert_ne!(0, std::mem::size_of::<#struct_ident>(),
56                        "Objects with spa_interface should contain the iface pointer, they cannot \
57                        be zero-size pointers. Probably #[pw_interface(...)] should be used here");
58                    crate::spa::interface::InterfaceRef::from_raw_ptr(
59                        std::ptr::addr_of!(self.#raw_field_ident).cast())
60                }
61            }
62        }
63    )
64}