serde_columnar_derive/
utils.rs1#![allow(dead_code)]
2use proc_macro2::Ident;
3use quote::ToTokens;
4use syn::{parse_quote, GenericArgument, PathArguments, Type};
5
6pub fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
29 let path = match ungroup(ty) {
30 syn::Type::Path(ty) => &ty.path,
31 _ => {
32 return false;
33 }
34 };
35 let seg = match path.segments.last() {
36 Some(seg) => seg,
37 None => {
38 return false;
39 }
40 };
41 let args = match &seg.arguments {
42 syn::PathArguments::AngleBracketed(bracketed) => &bracketed.args,
43 _ => {
44 return false;
45 }
46 };
47 seg.ident == "Cow"
48 && args.len() == 2
49 && match (&args[0], &args[1]) {
50 (syn::GenericArgument::Lifetime(_), syn::GenericArgument::Type(arg)) => elem(arg),
51 _ => false,
52 }
53}
54
55pub fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
56 let path = match ungroup(ty) {
57 syn::Type::Path(ty) => &ty.path,
58 _ => {
59 return false;
60 }
61 };
62 let seg = match path.segments.last() {
63 Some(seg) => seg,
64 None => {
65 return false;
66 }
67 };
68 let args = match &seg.arguments {
69 syn::PathArguments::AngleBracketed(bracketed) => &bracketed.args,
70 _ => {
71 return false;
72 }
73 };
74 seg.ident == "Option"
75 && args.len() == 1
76 && match &args[0] {
77 syn::GenericArgument::Type(arg) => elem(arg),
78 _ => false,
79 }
80}
81
82pub fn is_reference(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool {
103 match ungroup(ty) {
104 syn::Type::Reference(ty) => ty.mutability.is_none() && elem(&ty.elem),
105 _ => false,
106 }
107}
108
109pub fn is_str(ty: &syn::Type) -> bool {
110 is_primitive_type(ty, "str")
111}
112
113pub fn is_slice_u8(ty: &syn::Type) -> bool {
114 match ungroup(ty) {
115 syn::Type::Slice(ty) => is_primitive_type(&ty.elem, "u8"),
116 _ => false,
117 }
118}
119
120pub fn is_primitive_type(ty: &syn::Type, primitive: &str) -> bool {
121 match ungroup(ty) {
122 syn::Type::Path(ty) => ty.qself.is_none() && is_primitive_path(&ty.path, primitive),
123 _ => false,
124 }
125}
126
127pub fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool {
128 path.leading_colon.is_none()
129 && path.segments.len() == 1
130 && path.segments[0].ident == primitive
131 && path.segments[0].arguments.is_empty()
132}
133
134pub fn ungroup(mut ty: &Type) -> &Type {
135 while let Type::Group(group) = ty {
136 ty = &group.elem;
137 }
138 ty
139}
140
141pub fn add_lifetime_to_type<F>(
142 ty: &mut Type,
143 lifetime: GenericArgument,
144 map_name_fn: Option<F>,
145) -> syn::Result<()>
146where
147 F: FnMut(&mut Ident),
148{
149 match ty {
150 Type::Path(type_path) => {
151 let last_segment = type_path
152 .path
153 .segments
154 .last_mut()
155 .expect("Expected at least one segment");
156
157 match &mut last_segment.arguments {
158 PathArguments::AngleBracketed(angle_bracketed) => {
159 angle_bracketed.args.insert(0, lifetime);
160 }
161 PathArguments::None => {
162 let args = vec![lifetime];
163 last_segment.arguments =
164 PathArguments::AngleBracketed(parse_quote!(<#(#args),*>));
165 }
166 _ => {
167 return Err(syn::Error::new_spanned(
168 ty.into_token_stream(),
169 "the field type cannot add lifetime",
170 ))
171 }
172 };
173
174 if let Some(mut map_name_fn) = map_name_fn {
175 let ident = &mut last_segment.ident;
176 map_name_fn(ident);
177 }
178
179 Ok(())
180 }
181 _ => Err(syn::Error::new_spanned(
182 ty.into_token_stream(),
183 "the field type need be Path",
184 )),
185 }
186}