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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
mod derive_input_helper;

pub use derive_input_helper::DeriveInputHelper;

use syn::{spanned::Spanned};

// eg: Option<T>; get_generic_inner_type(&f.ty, "Option") -> Some(T: syn::Type)
// eg: Vec<T>; get_generic_inner_type(&f.ty, "Vec") -> Some(T: syn::Type)
pub fn get_type_inner_type_ident<'a>(r#type: &'a syn::Type, type_ident_name: &str) -> Option<&'a syn::Type> {
    if let syn::Type::Path(
        syn::TypePath {
            path: syn::Path {
                segments,
                ..
            },
            ..
        }
    ) = r#type {
        if let Some(seg) = segments.last() {
            if seg.ident.to_string() == type_ident_name {
                if let syn::PathArguments::AngleBracketed(
                    syn::AngleBracketedGenericArguments {
                        args,
                        ..
                    }
                ) = &seg.arguments {
                    if let Some(syn::GenericArgument::Type(inner_type)) = args.first() {
                        return Some(inner_type);
                    }
                }
            }
        }
    }
    None
}

pub fn parse_attrs_to_metas(attrs: &Vec<syn::Attribute>) -> syn::Result<Vec<syn::Meta>> {
    attrs.iter().map(|attr| attr.parse_meta()).collect::<syn::Result<Vec<syn::Meta>>>()
}

pub fn get_macro_nested_attr_value_ident(nested_metas: Vec<&syn::NestedMeta>, attr_name: &str, namespaces: Option<Vec<&str>>, namespace_allow_attrs: Option<Vec<&str>>) -> syn::Result<Option<syn::Ident>> {
    match namespaces {
        Some(namespaces) => {
            if let Some(nested_metas_vec) = get_namespace_nested_metas_vec_from_nested_metas(nested_metas, namespaces)? {
                // 多个同名,寻找第一个满足条件
                for nested_metas in nested_metas_vec.iter() {
                    // 校验每个属性是否有拼错或者不支持
                    for nested_meta in nested_metas.iter() {
                        if let syn::NestedMeta::Meta(meta) = nested_meta {
                            check_meta_available(meta, &namespace_allow_attrs)?;
                        }
                    }
                    for nested_meta in nested_metas.iter() {
                        if let syn::NestedMeta::Meta(meta) = nested_meta {
                            if let Some(ident) = get_macro_attr_value_from_meta(meta, attr_name)? {
                                return Ok(Some(ident))
                            }
                        }
                    }
                }
            }
        },
        None => {
            return get_macro_nested_attr_value_ident(nested_metas, attr_name, Some(vec![]), namespace_allow_attrs);
        },
    }
    Ok(None)
}
pub fn get_macro_attr_value_ident(metas: Vec<&syn::Meta>, attr_name: &str, namespaces: Option<Vec<&str>>, namespace_allow_attrs: Option<Vec<&str>>) -> syn::Result<Option<syn::Ident>> {
    match namespaces {
        Some(namespaces) => {
            // eg: #[arel="users"]
            if namespaces.len() == 0 {
                for meta in metas {
                    // 校验属性是否有拼错或者不支持
                    check_meta_available(meta, &namespace_allow_attrs)?;
                    if let Some(ident) = get_macro_attr_value_from_meta(&meta, attr_name)? {
                        return Ok(Some(ident))
                    }
                }
            } else { // eg: #[arel(name="uuid")], #[arel(column(name="uuid"))]
                if let Some(nested_metas_vec) = get_namespace_nested_metas_vec_from_metas(metas, namespaces)? {
                    for nested_metas in nested_metas_vec.iter() {
                        return get_macro_nested_attr_value_ident(nested_metas.clone(), attr_name, None, namespace_allow_attrs)
                    }
                }
            }
        },
        _ => {
            return get_macro_attr_value_ident(metas, attr_name, Some(vec![]), namespace_allow_attrs);
        },
    }
    Ok(None)
}

fn check_meta_available(meta: &syn::Meta, allow_attrs: &Option<Vec<&str>>) -> syn::Result<bool> {
    if let Some(allow_attrs) = allow_attrs {
        if let syn::Meta::NameValue(kv) = meta {
            let mut can_kv_path_allow = false;
            for attr_name in allow_attrs {
                if kv.path.is_ident(attr_name) {
                    can_kv_path_allow = true;
                }
            }
            if !can_kv_path_allow {
                return Err(syn::Error::new_spanned(&kv.path, format!("Support Macro Attr List: {:?}", &allow_attrs)));
            }
        }
    }
    Ok(true)
}

fn get_macro_attr_value_from_meta(meta: &syn::Meta, attr_name: &str) -> syn::Result<Option<syn::Ident>> {
    if let syn::Meta::NameValue(kv) = meta {
        if let syn::Lit::Str(ref ident_str) = kv.lit {
            if kv.path.is_ident(attr_name) {
                return Ok(Some(syn::Ident::new(ident_str.value().as_str(), kv.span())));
            }
        }
    }
    Ok(None)
}

// 可能会存在多个同名属性,所以要用vec来存储
pub fn get_namespace_nested_metas_vec_from_metas<'a>(metas: Vec<&'a syn::Meta>, namespaces: Vec<&str>) -> syn::Result<Option<Vec<Vec<&'a syn::NestedMeta>>>> {
    let mut namespace_nested_metas_vec = vec![];
    if namespaces.len() != 0 {
        for meta in metas {
            if let  syn::Meta::List(meta_list) = meta {
                for segment in meta_list.path.segments.iter() {
                    let mut namespaces: Vec<&str> = namespaces.iter().map(|&i| i).collect();
                    let first_namespace = namespaces.remove(0);
                    if segment.ident == first_namespace {
                        let nested_metas = meta_list.nested.iter().map(|i| i).collect();
                        if let Some(mut nested_metas_vec) = get_namespace_nested_metas_vec_from_nested_metas(nested_metas, namespaces)? {
                            namespace_nested_metas_vec.append(&mut nested_metas_vec);
                        }
                    }
                }
            }
        }
    }
    if namespace_nested_metas_vec.len() > 0 {
        Ok(Some(namespace_nested_metas_vec))
    } else {
        Ok(None)
    }
}
// 可能会存在多个同名属性,所以要用vec来存储
pub fn get_namespace_nested_metas_vec_from_nested_metas<'a>(nested_metas: Vec<&'a syn::NestedMeta>, namespaces: Vec<&str>) -> syn::Result<Option<Vec<Vec<&'a syn::NestedMeta>>>> {
    let mut namespace_nested_metas_vec = vec![];
    if namespaces.len() != 0 {
        let metas = nested_metas.iter().filter_map(|item| {
            if let syn::NestedMeta::Meta(meta) = item { Some(meta) } else { None }
        }).collect::<Vec<_>>();
        for meta in metas {
            if let  syn::Meta::List(meta_list) = meta {
                for segment in meta_list.path.segments.iter() {
                    let mut namespaces: Vec<&str> = namespaces.iter().map(|&i| i).collect();
                    let first_namespace = namespaces.remove(0);
                    if segment.ident == first_namespace {
                        let nested_metas = meta_list.nested.iter().map(|i| i).collect();
                        if let Some(mut nested_metas_vec) = get_namespace_nested_metas_vec_from_nested_metas(nested_metas, namespaces)? {
                            namespace_nested_metas_vec.append(&mut nested_metas_vec);
                        }
                    }
                }
            }
        }
    } else {
        namespace_nested_metas_vec.push(nested_metas);
        return Ok(Some(namespace_nested_metas_vec))
    }
    if namespace_nested_metas_vec.len() > 0 {
        Ok(Some(namespace_nested_metas_vec))
    } else {
        Ok(None)
    }
}