pipewire_wrapper_macro_impl/
lib.rs

1/*
2 * SPDX-License-Identifier: MIT
3 */
4use 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}