pipewire_wrapper_macro_impl/
lib.rs1use proc_macro2::Ident;
5use syn::parse::ParseStream;
6use syn::punctuated::Punctuated;
7use syn::{
8 AttrStyle, Attribute, Field, GenericArgument, GenericParam, Generics, ItemStruct, Meta,
9 PathArguments, Type,
10};
11
12pub mod derive_raw_wrapper;
13pub mod derive_wrapper;
14pub mod interface;
15pub mod object_type_impl;
16pub mod proxy_wrapper;
17pub mod spa_interface;
18
19const ATTR_RAW: &str = "raw";
20const ATTR_RAW_WRAPPER: &str = "raw_wrapper";
21
22const ARG_METHODS: &str = "methods";
23const ARG_INTERFACE: &str = "interface";
24
25fn escape_ident(ident_name: &str) -> &str {
26 match ident_name {
27 "type" => "type_",
28 _ => ident_name,
29 }
30}
31
32fn parse_wrapped_struct_info(
33 input: ParseStream,
34 attr_ident_name: &'static str,
35) -> syn::Result<(Ident, Generics, Field, Vec<Field>)> {
36 let item_struct: ItemStruct = input.parse()?;
37
38 let mut field_with_attr: Option<Field> = None;
39 let mut other_fields: Vec<Field> = Vec::new();
40 for field in item_struct.fields {
41 if field
42 .attrs
43 .iter()
44 .any(|attr| is_attribute_with_ident_name(attr, attr_ident_name))
45 {
46 field_with_attr = Some(field);
47 } else {
48 other_fields.push(field);
49 }
50 }
51
52 if let Some(field_with_attr) = field_with_attr {
53 Ok((
54 item_struct.ident,
55 item_struct.generics,
56 field_with_attr,
57 other_fields,
58 ))
59 } else {
60 Err(input.error(format!(
61 "Cannot find field with #[{}] attribute in wrapped struct",
62 attr_ident_name
63 )))
64 }
65}
66
67fn is_attribute_with_ident_name(attr: &Attribute, ident_name: &'static str) -> bool {
68 if let AttrStyle::Outer = attr.style {
69 if let Meta::Path(path) = &attr.meta {
70 if let Some(ident) = path.get_ident() {
71 return ident == ident_name;
72 }
73 }
74 }
75 false
76}
77
78fn get_field_type(field: &Field) -> &Type {
79 if let Type::Path(type_path) = &field.ty {
80 let last_segment = type_path.path.segments.last().unwrap();
81 if let PathArguments::AngleBracketed(generic_arg) = &last_segment.arguments {
82 if let Some(GenericArgument::Type(generic_type)) = generic_arg.args.first() {
83 return generic_type;
84 }
85 }
86 }
87 &field.ty
88}
89
90fn strip_defaults_from_generics(generics: &mut Generics) {
91 generics.params.iter_mut().for_each(|p| {
92 if let GenericParam::Type(ty) = p {
93 ty.eq_token = None;
94 ty.default = None;
95 }
96 });
97}
98
99fn strip_bounds_from_generics(generics: &mut Generics) {
100 generics.params.iter_mut().for_each(|p| {
101 if let GenericParam::Type(ty) = p {
102 ty.colon_token = None;
103 ty.bounds = Punctuated::default();
104 }
105 });
106}