pub(crate) fn unwrap_option_type(ty: &syn::Type) -> Option<&syn::Type> {
is_option_helper(ty).1
}
pub(crate) fn is_option(ty: &syn::Type) -> bool {
is_option_helper(ty).0
}
fn is_option_helper(ty: &syn::Type) -> (bool, Option<&syn::Type>) {
if let syn::Type::Path(syn::TypePath { path, .. }) = ty {
if let Some(syn::PathSegment {
ident: id,
arguments:
syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { args, .. }),
}) = path.segments.first()
{
if id == "Option" {
return (
true,
args.first().and_then(|arg| match arg {
syn::GenericArgument::Type(inner_ty) => Some(inner_ty),
_ => None,
}),
);
}
}
}
(false, None)
}
pub(crate) fn insert_lifetime(
ty: &syn::Type,
lifetime_char: proc_macro2::TokenStream,
) -> syn::Type {
let lifetime = syn::Lifetime::new(
lifetime_char.to_string().as_str(),
proc_macro2::Span::call_site(),
);
match ty {
syn::Type::Reference(ty_ref) => syn::Type::Reference(syn::TypeReference {
and_token: Default::default(),
lifetime: Some(lifetime),
mutability: ty_ref.mutability,
elem: ty_ref.elem.clone(),
}),
_ => syn::Type::Reference(syn::TypeReference {
and_token: Default::default(),
lifetime: Some(lifetime),
mutability: None,
elem: Box::new(ty.clone()),
}),
}
}
pub(crate) fn u8_slice() -> syn::Type {
syn::Type::Reference(syn::TypeReference {
and_token: Default::default(),
lifetime: None,
mutability: None,
elem: Box::new(syn::Type::Slice(syn::TypeSlice {
bracket_token: Default::default(),
elem: Box::new(syn::Type::Path(syn::TypePath {
qself: None,
path: syn::parse_quote! { u8 },
})),
})),
})
}
pub(crate) fn type2fish(ty: &syn::Type) -> proc_macro2::TokenStream {
match ty {
syn::Type::Path(type_path) => {
let mut tokens = proc_macro2::TokenStream::new();
for (i, segment) in type_path.path.segments.iter().enumerate() {
if i > 0 {
tokens.extend(quote::quote!(::));
}
let ident = &segment.ident;
tokens.extend(quote::quote!(#ident));
if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
let args_tokens: Vec<proc_macro2::TokenStream> = args
.args
.iter()
.map(|arg| {
match arg {
syn::GenericArgument::Type(ty) => type2fish(ty),
_ => quote::quote!(#arg),
}
})
.collect();
if !args_tokens.is_empty() {
tokens.extend(quote::quote!(::<#(#args_tokens),*>));
}
}
}
tokens
}
_ => quote::quote!(#ty),
}
}