pipewire_wrapper_macro_impl/
interface.rs

1use proc_macro2::{Ident, Span, TokenStream};
2use quote::quote;
3use syn::parse::{Parse, ParseStream};
4use syn::punctuated::Punctuated;
5use syn::{parse2, Expr, Lit, LitStr, MetaNameValue, Token, Type, TypePath};
6
7use crate::derive_raw_wrapper::WrappedRawStructInfo;
8use crate::{ARG_INTERFACE, ARG_METHODS};
9
10struct InterfaceAttr {
11    methods: Type,
12    interface: LitStr,
13}
14
15impl Parse for InterfaceAttr {
16    fn parse(input: ParseStream) -> syn::Result<Self> {
17        let mut methods_arg_value: Option<Type> = None;
18        let mut interface_arg_value: Option<LitStr> = None;
19
20        let key_value_list: Punctuated<MetaNameValue, Token![,]> =
21            Punctuated::parse_terminated(input)?;
22        for key_value in key_value_list {
23            if key_value.path.is_ident(ARG_METHODS) {
24                if let Expr::Path(path) = key_value.value {
25                    methods_arg_value = Some(Type::Path(TypePath {
26                        qself: path.qself,
27                        path: path.path,
28                    }));
29                } else {
30                    return Err(input.error("Methods struct type path expected"));
31                }
32            } else if key_value.path.is_ident(ARG_INTERFACE) {
33                if let Expr::Lit(lit) = key_value.value {
34                    if let Lit::Str(lit_str) = lit.lit {
35                        interface_arg_value = Some(lit_str);
36                    }
37                }
38            } else {
39                return Err(input.error("Unexpected attribute name"));
40            }
41        }
42
43        if methods_arg_value.is_none() {
44            return Err(input.error("Methods meta attribute is missing"));
45        }
46        if interface_arg_value.is_none() {
47            return Err(input.error("Interface meta attribute is missing"));
48        }
49
50        Ok(Self {
51            methods: methods_arg_value.unwrap(),
52            interface: interface_arg_value.unwrap(),
53        })
54    }
55}
56
57pub fn interface(attr: TokenStream, input: TokenStream) -> TokenStream {
58    let struct_info = match parse2::<WrappedRawStructInfo>(input.clone()) {
59        Ok(parsed) => parsed,
60        Err(error) => return error.to_compile_error(),
61    };
62    let interface_attr = match parse2::<InterfaceAttr>(attr) {
63        Ok(parsed) => parsed,
64        Err(error) => return error.to_compile_error(),
65    };
66
67    let struct_ident = &struct_info.struct_ident;
68    let raw_field_ident = &struct_info.raw_field.ident;
69    let methods_type = interface_attr.methods;
70    let interface_name = interface_attr.interface;
71    let interface_name_ident = Ident::new(
72        format!("{}_TYPE_INFO", interface_name.value().to_uppercase()).as_str(),
73        Span::call_site(),
74    );
75
76    quote!(
77        #input
78
79        pub const #interface_name_ident: crate::core_api::type_info::TypeInfo = crate::interface_type!(#interface_name);
80
81        impl crate::core_api::proxy::Proxied for #struct_ident {
82            fn type_info() -> crate::core_api::type_info::TypeInfo<'static> {
83                #interface_name_ident
84            }
85        }
86
87        impl crate::wrapper::SpaInterface for #struct_ident {
88            type Methods = #methods_type;
89
90            fn spa_interface(&self) -> &crate::spa::interface::InterfaceRef {
91                use crate::wrapper::RawWrapper;
92                unsafe {
93                    assert_eq!(0, std::mem::size_of::<#struct_ident>(),
94                        "Objects with pw_interface should not have any data, they are just zero-size \
95                        pointers. Probably #[spa_interface(...)] should be used here");
96                    crate::spa::interface::InterfaceRef::from_raw_ptr(
97                        std::ptr::addr_of!(self.#raw_field_ident).cast())
98                }
99            }
100        }
101    )
102}