1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/*
 * SPDX-License-Identifier: MIT
 */
use proc_macro2::Ident;
use syn::parse::ParseStream;
use syn::punctuated::Punctuated;
use syn::{
    AttrStyle, Attribute, Field, GenericArgument, GenericParam, Generics, ItemStruct, Meta,
    PathArguments, Type,
};

pub mod derive_raw_wrapper;
pub mod derive_wrapper;
pub mod interface;
pub mod object_type_impl;
pub mod proxy_wrapper;
pub mod spa_interface;

const ATTR_RAW: &str = "raw";
const ATTR_RAW_WRAPPER: &str = "raw_wrapper";

const ARG_METHODS: &str = "methods";
const ARG_INTERFACE: &str = "interface";

fn escape_ident(ident_name: &str) -> &str {
    match ident_name {
        "type" => "type_",
        _ => ident_name,
    }
}

fn parse_wrapped_struct_info(
    input: ParseStream,
    attr_ident_name: &'static str,
) -> syn::Result<(Ident, Generics, Field, Vec<Field>)> {
    let item_struct: ItemStruct = input.parse()?;

    let mut field_with_attr: Option<Field> = None;
    let mut other_fields: Vec<Field> = Vec::new();
    for field in item_struct.fields {
        if field
            .attrs
            .iter()
            .any(|attr| is_attribute_with_ident_name(attr, attr_ident_name))
        {
            field_with_attr = Some(field);
        } else {
            other_fields.push(field);
        }
    }

    if let Some(field_with_attr) = field_with_attr {
        Ok((
            item_struct.ident,
            item_struct.generics,
            field_with_attr,
            other_fields,
        ))
    } else {
        Err(input.error(format!(
            "Cannot find field with #[{}] attribute in wrapped struct",
            attr_ident_name
        )))
    }
}

fn is_attribute_with_ident_name(attr: &Attribute, ident_name: &'static str) -> bool {
    if let AttrStyle::Outer = attr.style {
        if let Meta::Path(path) = &attr.meta {
            if let Some(ident) = path.get_ident() {
                return ident == ident_name;
            }
        }
    }
    false
}

fn get_field_type(field: &Field) -> &Type {
    if let Type::Path(type_path) = &field.ty {
        let last_segment = type_path.path.segments.last().unwrap();
        if let PathArguments::AngleBracketed(generic_arg) = &last_segment.arguments {
            if let Some(GenericArgument::Type(generic_type)) = generic_arg.args.first() {
                return generic_type;
            }
        }
    }
    &field.ty
}

fn strip_defaults_from_generics(generics: &mut Generics) {
    generics.params.iter_mut().for_each(|p| {
        if let GenericParam::Type(ty) = p {
            ty.eq_token = None;
            ty.default = None;
        }
    });
}

fn strip_bounds_from_generics(generics: &mut Generics) {
    generics.params.iter_mut().for_each(|p| {
        if let GenericParam::Type(ty) = p {
            ty.colon_token = None;
            ty.bounds = Punctuated::default();
        }
    });
}