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