• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Special types handling
2 
3 use super::spanned::Sp;
4 
5 use syn::{
6     spanned::Spanned, GenericArgument, Path, PathArguments, PathArguments::AngleBracketed,
7     PathSegment, Type, TypePath,
8 };
9 
10 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
11 pub enum Ty {
12     Unit,
13     Vec,
14     VecVec,
15     Option,
16     OptionOption,
17     OptionVec,
18     OptionVecVec,
19     Other,
20 }
21 
22 impl Ty {
from_syn_ty(ty: &syn::Type) -> Sp<Self>23     pub fn from_syn_ty(ty: &syn::Type) -> Sp<Self> {
24         use self::Ty::*;
25         let t = |kind| Sp::new(kind, ty.span());
26 
27         if is_unit_ty(ty) {
28             t(Unit)
29         } else if let Some(vt) = get_vec_ty(ty, Vec, VecVec) {
30             t(vt)
31         } else if let Some(subty) = subty_if_name(ty, "Option") {
32             if is_generic_ty(subty, "Option") {
33                 t(OptionOption)
34             } else if let Some(vt) = get_vec_ty(subty, OptionVec, OptionVecVec) {
35                 t(vt)
36             } else {
37                 t(Option)
38             }
39         } else {
40             t(Other)
41         }
42     }
43 
as_str(&self) -> &'static str44     pub fn as_str(&self) -> &'static str {
45         match self {
46             Self::Unit => "()",
47             Self::Vec => "Vec<T>",
48             Self::Option => "Option<T>",
49             Self::OptionOption => "Option<Option<T>>",
50             Self::OptionVec => "Option<Vec<T>>",
51             Self::VecVec => "Vec<Vec<T>>",
52             Self::OptionVecVec => "Option<Vec<Vec<T>>>",
53             Self::Other => "...other...",
54         }
55     }
56 }
57 
inner_type(field_ty: &syn::Type) -> &syn::Type58 pub fn inner_type(field_ty: &syn::Type) -> &syn::Type {
59     let ty = Ty::from_syn_ty(field_ty);
60     match *ty {
61         Ty::Vec | Ty::Option => sub_type(field_ty).unwrap_or(field_ty),
62         Ty::OptionOption | Ty::OptionVec | Ty::VecVec => {
63             sub_type(field_ty).and_then(sub_type).unwrap_or(field_ty)
64         }
65         Ty::OptionVecVec => sub_type(field_ty)
66             .and_then(sub_type)
67             .and_then(sub_type)
68             .unwrap_or(field_ty),
69         _ => field_ty,
70     }
71 }
72 
sub_type(ty: &syn::Type) -> Option<&syn::Type>73 pub fn sub_type(ty: &syn::Type) -> Option<&syn::Type> {
74     subty_if(ty, |_| true)
75 }
76 
only_last_segment(mut ty: &syn::Type) -> Option<&PathSegment>77 fn only_last_segment(mut ty: &syn::Type) -> Option<&PathSegment> {
78     while let syn::Type::Group(syn::TypeGroup { elem, .. }) = ty {
79         ty = elem;
80     }
81     match ty {
82         Type::Path(TypePath {
83             qself: None,
84             path:
85                 Path {
86                     leading_colon: None,
87                     segments,
88                 },
89         }) => only_one(segments.iter()),
90 
91         _ => None,
92     }
93 }
94 
subty_if<F>(ty: &syn::Type, f: F) -> Option<&syn::Type> where F: FnOnce(&PathSegment) -> bool,95 fn subty_if<F>(ty: &syn::Type, f: F) -> Option<&syn::Type>
96 where
97     F: FnOnce(&PathSegment) -> bool,
98 {
99     only_last_segment(ty)
100         .filter(|segment| f(segment))
101         .and_then(|segment| {
102             if let AngleBracketed(args) = &segment.arguments {
103                 only_one(args.args.iter()).and_then(|genneric| {
104                     if let GenericArgument::Type(ty) = genneric {
105                         Some(ty)
106                     } else {
107                         None
108                     }
109                 })
110             } else {
111                 None
112             }
113         })
114 }
115 
subty_if_name<'a>(ty: &'a syn::Type, name: &str) -> Option<&'a syn::Type>116 pub fn subty_if_name<'a>(ty: &'a syn::Type, name: &str) -> Option<&'a syn::Type> {
117     subty_if(ty, |seg| seg.ident == name)
118 }
119 
is_simple_ty(ty: &syn::Type, name: &str) -> bool120 pub fn is_simple_ty(ty: &syn::Type, name: &str) -> bool {
121     only_last_segment(ty)
122         .map(|segment| {
123             if let PathArguments::None = segment.arguments {
124                 segment.ident == name
125             } else {
126                 false
127             }
128         })
129         .unwrap_or(false)
130 }
131 
is_generic_ty(ty: &syn::Type, name: &str) -> bool132 fn is_generic_ty(ty: &syn::Type, name: &str) -> bool {
133     subty_if_name(ty, name).is_some()
134 }
135 
is_unit_ty(ty: &syn::Type) -> bool136 fn is_unit_ty(ty: &syn::Type) -> bool {
137     if let syn::Type::Tuple(tuple) = ty {
138         tuple.elems.is_empty()
139     } else {
140         false
141     }
142 }
143 
only_one<I, T>(mut iter: I) -> Option<T> where I: Iterator<Item = T>,144 fn only_one<I, T>(mut iter: I) -> Option<T>
145 where
146     I: Iterator<Item = T>,
147 {
148     iter.next().filter(|_| iter.next().is_none())
149 }
150 
151 #[cfg(feature = "unstable-v5")]
get_vec_ty(ty: &Type, vec_ty: Ty, vecvec_ty: Ty) -> Option<Ty>152 fn get_vec_ty(ty: &Type, vec_ty: Ty, vecvec_ty: Ty) -> Option<Ty> {
153     subty_if_name(ty, "Vec").map(|subty| {
154         if is_generic_ty(subty, "Vec") {
155             vecvec_ty
156         } else {
157             vec_ty
158         }
159     })
160 }
161 
162 #[cfg(not(feature = "unstable-v5"))]
get_vec_ty(ty: &Type, vec_ty: Ty, _vecvec_ty: Ty) -> Option<Ty>163 fn get_vec_ty(ty: &Type, vec_ty: Ty, _vecvec_ty: Ty) -> Option<Ty> {
164     is_generic_ty(ty, "Vec").then_some(vec_ty)
165 }
166