pipewire_wrapper_macro_impl/
spa_interface.rs1use 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}