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
use proc_macro2::{Ident, Span};
use syn::parse::ParseStream;
use syn::Result;
use syn::{Expr, Field, GenericArgument, PathArguments, Token, Type};

pub fn type_is_option(ty: &Type) -> bool {
    type_of_option(ty).is_some()
}

pub fn type_of_option(ty: &Type) -> Option<&Type> {
    let path = match ty {
        Type::Path(ty) => &ty.path,
        _ => return None,
    };

    let last = path.segments.last().unwrap();
    if last.ident != "Option" {
        return None;
    }

    let bracketed = match &last.arguments {
        PathArguments::AngleBracketed(bracketed) => bracketed,
        _ => return None,
    };

    if bracketed.args.len() != 1 {
        return None;
    }

    match &bracketed.args[0] {
        GenericArgument::Type(arg) => Some(arg),
        _ => None,
    }
}

pub fn type_add_colon2(ret: &mut Type) {
    if let Type::Path(p) = ret {
        let path = &mut p.path;
        let segs = &mut path.segments;
        for seg in segs {
            if let PathArguments::AngleBracketed(ref mut ab) = &mut seg.arguments {
                if ab.colon2_token.is_none() {
                    ab.colon2_token = Some(<Token![::]>::default());
                }
            }
        }
    }
}

pub fn meta_list_to_fields(list: &syn::MetaList) -> Result<Vec<Field>> {
    list.parse_args_with(|stream: ParseStream| -> Result<Vec<Field>> {
        let mut fields: Vec<Field> = vec![];
        let named = stream.parse_terminated(Field::parse_named, Token![,])?;
        for field in named {
            fields.push(field);
        }
        Ok(fields)
    })
}

pub fn meta_list_to_expr(list: &syn::MetaList) -> Result<Vec<Expr>> {
    list.parse_args_with(|stream: ParseStream| -> Result<Vec<Expr>> {
        let mut exprs = vec![];
        while !stream.is_empty() {
            let field: Expr = stream.parse()?;
            exprs.push(field);
            if !stream.is_empty() {
                stream.parse::<Token![,]>()?;
            }
        }
        Ok(exprs)
    })
}

pub fn get_unname_field_ident(index: usize) -> Ident {
    Ident::new(&format!("_unamedfield_{index}"), Span::call_site())
}

pub fn is_new_type(fields: &syn::Fields) -> bool {
    if let syn::Fields::Unnamed(fields) = fields {
        if fields.unnamed.len() == 1 {
            return true;
        }
    }
    false
}