119625d8cSopenharmony_ci//! Special types handling
219625d8cSopenharmony_ci
319625d8cSopenharmony_ciuse super::spanned::Sp;
419625d8cSopenharmony_ci
519625d8cSopenharmony_ciuse syn::{
619625d8cSopenharmony_ci    spanned::Spanned, GenericArgument, Path, PathArguments, PathArguments::AngleBracketed,
719625d8cSopenharmony_ci    PathSegment, Type, TypePath,
819625d8cSopenharmony_ci};
919625d8cSopenharmony_ci
1019625d8cSopenharmony_ci#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1119625d8cSopenharmony_cipub enum Ty {
1219625d8cSopenharmony_ci    Unit,
1319625d8cSopenharmony_ci    Vec,
1419625d8cSopenharmony_ci    VecVec,
1519625d8cSopenharmony_ci    Option,
1619625d8cSopenharmony_ci    OptionOption,
1719625d8cSopenharmony_ci    OptionVec,
1819625d8cSopenharmony_ci    OptionVecVec,
1919625d8cSopenharmony_ci    Other,
2019625d8cSopenharmony_ci}
2119625d8cSopenharmony_ci
2219625d8cSopenharmony_ciimpl Ty {
2319625d8cSopenharmony_ci    pub fn from_syn_ty(ty: &syn::Type) -> Sp<Self> {
2419625d8cSopenharmony_ci        use self::Ty::*;
2519625d8cSopenharmony_ci        let t = |kind| Sp::new(kind, ty.span());
2619625d8cSopenharmony_ci
2719625d8cSopenharmony_ci        if is_unit_ty(ty) {
2819625d8cSopenharmony_ci            t(Unit)
2919625d8cSopenharmony_ci        } else if let Some(vt) = get_vec_ty(ty, Vec, VecVec) {
3019625d8cSopenharmony_ci            t(vt)
3119625d8cSopenharmony_ci        } else if let Some(subty) = subty_if_name(ty, "Option") {
3219625d8cSopenharmony_ci            if is_generic_ty(subty, "Option") {
3319625d8cSopenharmony_ci                t(OptionOption)
3419625d8cSopenharmony_ci            } else if let Some(vt) = get_vec_ty(subty, OptionVec, OptionVecVec) {
3519625d8cSopenharmony_ci                t(vt)
3619625d8cSopenharmony_ci            } else {
3719625d8cSopenharmony_ci                t(Option)
3819625d8cSopenharmony_ci            }
3919625d8cSopenharmony_ci        } else {
4019625d8cSopenharmony_ci            t(Other)
4119625d8cSopenharmony_ci        }
4219625d8cSopenharmony_ci    }
4319625d8cSopenharmony_ci
4419625d8cSopenharmony_ci    pub fn as_str(&self) -> &'static str {
4519625d8cSopenharmony_ci        match self {
4619625d8cSopenharmony_ci            Self::Unit => "()",
4719625d8cSopenharmony_ci            Self::Vec => "Vec<T>",
4819625d8cSopenharmony_ci            Self::Option => "Option<T>",
4919625d8cSopenharmony_ci            Self::OptionOption => "Option<Option<T>>",
5019625d8cSopenharmony_ci            Self::OptionVec => "Option<Vec<T>>",
5119625d8cSopenharmony_ci            Self::VecVec => "Vec<Vec<T>>",
5219625d8cSopenharmony_ci            Self::OptionVecVec => "Option<Vec<Vec<T>>>",
5319625d8cSopenharmony_ci            Self::Other => "...other...",
5419625d8cSopenharmony_ci        }
5519625d8cSopenharmony_ci    }
5619625d8cSopenharmony_ci}
5719625d8cSopenharmony_ci
5819625d8cSopenharmony_cipub fn inner_type(field_ty: &syn::Type) -> &syn::Type {
5919625d8cSopenharmony_ci    let ty = Ty::from_syn_ty(field_ty);
6019625d8cSopenharmony_ci    match *ty {
6119625d8cSopenharmony_ci        Ty::Vec | Ty::Option => sub_type(field_ty).unwrap_or(field_ty),
6219625d8cSopenharmony_ci        Ty::OptionOption | Ty::OptionVec | Ty::VecVec => {
6319625d8cSopenharmony_ci            sub_type(field_ty).and_then(sub_type).unwrap_or(field_ty)
6419625d8cSopenharmony_ci        }
6519625d8cSopenharmony_ci        Ty::OptionVecVec => sub_type(field_ty)
6619625d8cSopenharmony_ci            .and_then(sub_type)
6719625d8cSopenharmony_ci            .and_then(sub_type)
6819625d8cSopenharmony_ci            .unwrap_or(field_ty),
6919625d8cSopenharmony_ci        _ => field_ty,
7019625d8cSopenharmony_ci    }
7119625d8cSopenharmony_ci}
7219625d8cSopenharmony_ci
7319625d8cSopenharmony_cipub fn sub_type(ty: &syn::Type) -> Option<&syn::Type> {
7419625d8cSopenharmony_ci    subty_if(ty, |_| true)
7519625d8cSopenharmony_ci}
7619625d8cSopenharmony_ci
7719625d8cSopenharmony_cifn only_last_segment(mut ty: &syn::Type) -> Option<&PathSegment> {
7819625d8cSopenharmony_ci    while let syn::Type::Group(syn::TypeGroup { elem, .. }) = ty {
7919625d8cSopenharmony_ci        ty = elem;
8019625d8cSopenharmony_ci    }
8119625d8cSopenharmony_ci    match ty {
8219625d8cSopenharmony_ci        Type::Path(TypePath {
8319625d8cSopenharmony_ci            qself: None,
8419625d8cSopenharmony_ci            path:
8519625d8cSopenharmony_ci                Path {
8619625d8cSopenharmony_ci                    leading_colon: None,
8719625d8cSopenharmony_ci                    segments,
8819625d8cSopenharmony_ci                },
8919625d8cSopenharmony_ci        }) => only_one(segments.iter()),
9019625d8cSopenharmony_ci
9119625d8cSopenharmony_ci        _ => None,
9219625d8cSopenharmony_ci    }
9319625d8cSopenharmony_ci}
9419625d8cSopenharmony_ci
9519625d8cSopenharmony_cifn subty_if<F>(ty: &syn::Type, f: F) -> Option<&syn::Type>
9619625d8cSopenharmony_ciwhere
9719625d8cSopenharmony_ci    F: FnOnce(&PathSegment) -> bool,
9819625d8cSopenharmony_ci{
9919625d8cSopenharmony_ci    only_last_segment(ty)
10019625d8cSopenharmony_ci        .filter(|segment| f(segment))
10119625d8cSopenharmony_ci        .and_then(|segment| {
10219625d8cSopenharmony_ci            if let AngleBracketed(args) = &segment.arguments {
10319625d8cSopenharmony_ci                only_one(args.args.iter()).and_then(|genneric| {
10419625d8cSopenharmony_ci                    if let GenericArgument::Type(ty) = genneric {
10519625d8cSopenharmony_ci                        Some(ty)
10619625d8cSopenharmony_ci                    } else {
10719625d8cSopenharmony_ci                        None
10819625d8cSopenharmony_ci                    }
10919625d8cSopenharmony_ci                })
11019625d8cSopenharmony_ci            } else {
11119625d8cSopenharmony_ci                None
11219625d8cSopenharmony_ci            }
11319625d8cSopenharmony_ci        })
11419625d8cSopenharmony_ci}
11519625d8cSopenharmony_ci
11619625d8cSopenharmony_cipub fn subty_if_name<'a>(ty: &'a syn::Type, name: &str) -> Option<&'a syn::Type> {
11719625d8cSopenharmony_ci    subty_if(ty, |seg| seg.ident == name)
11819625d8cSopenharmony_ci}
11919625d8cSopenharmony_ci
12019625d8cSopenharmony_cipub fn is_simple_ty(ty: &syn::Type, name: &str) -> bool {
12119625d8cSopenharmony_ci    only_last_segment(ty)
12219625d8cSopenharmony_ci        .map(|segment| {
12319625d8cSopenharmony_ci            if let PathArguments::None = segment.arguments {
12419625d8cSopenharmony_ci                segment.ident == name
12519625d8cSopenharmony_ci            } else {
12619625d8cSopenharmony_ci                false
12719625d8cSopenharmony_ci            }
12819625d8cSopenharmony_ci        })
12919625d8cSopenharmony_ci        .unwrap_or(false)
13019625d8cSopenharmony_ci}
13119625d8cSopenharmony_ci
13219625d8cSopenharmony_cifn is_generic_ty(ty: &syn::Type, name: &str) -> bool {
13319625d8cSopenharmony_ci    subty_if_name(ty, name).is_some()
13419625d8cSopenharmony_ci}
13519625d8cSopenharmony_ci
13619625d8cSopenharmony_cifn is_unit_ty(ty: &syn::Type) -> bool {
13719625d8cSopenharmony_ci    if let syn::Type::Tuple(tuple) = ty {
13819625d8cSopenharmony_ci        tuple.elems.is_empty()
13919625d8cSopenharmony_ci    } else {
14019625d8cSopenharmony_ci        false
14119625d8cSopenharmony_ci    }
14219625d8cSopenharmony_ci}
14319625d8cSopenharmony_ci
14419625d8cSopenharmony_cifn only_one<I, T>(mut iter: I) -> Option<T>
14519625d8cSopenharmony_ciwhere
14619625d8cSopenharmony_ci    I: Iterator<Item = T>,
14719625d8cSopenharmony_ci{
14819625d8cSopenharmony_ci    iter.next().filter(|_| iter.next().is_none())
14919625d8cSopenharmony_ci}
15019625d8cSopenharmony_ci
15119625d8cSopenharmony_ci#[cfg(feature = "unstable-v5")]
15219625d8cSopenharmony_cifn get_vec_ty(ty: &Type, vec_ty: Ty, vecvec_ty: Ty) -> Option<Ty> {
15319625d8cSopenharmony_ci    subty_if_name(ty, "Vec").map(|subty| {
15419625d8cSopenharmony_ci        if is_generic_ty(subty, "Vec") {
15519625d8cSopenharmony_ci            vecvec_ty
15619625d8cSopenharmony_ci        } else {
15719625d8cSopenharmony_ci            vec_ty
15819625d8cSopenharmony_ci        }
15919625d8cSopenharmony_ci    })
16019625d8cSopenharmony_ci}
16119625d8cSopenharmony_ci
16219625d8cSopenharmony_ci#[cfg(not(feature = "unstable-v5"))]
16319625d8cSopenharmony_cifn get_vec_ty(ty: &Type, vec_ty: Ty, _vecvec_ty: Ty) -> Option<Ty> {
16419625d8cSopenharmony_ci    is_generic_ty(ty, "Vec").then_some(vec_ty)
16519625d8cSopenharmony_ci}
166