use proc_macro2::{Ident, Span}; use quote::quote; use syn::{Error, GenericArgument, PathArguments, Result, Type}; pub enum OutputType<'a> { Value(&'a Type), Result(&'a Type, &'a Type), } impl<'a> OutputType<'a> { pub fn parse(input: &'a Type) -> Result { let ty = if let Type::Path(p) = input { if p.path.segments.last().unwrap().ident == "Result" || p.path.segments.last().unwrap().ident == "FieldResult" { if let PathArguments::AngleBracketed(args) = &p.path.segments.last().unwrap().arguments { if args.args.is_empty() { return Err(Error::new_spanned(input, "Invalid type")); } let mut res = None; for arg in &args.args { if let GenericArgument::Type(value_ty) = arg { res = Some(OutputType::Result(input, value_ty)); break; } } if res.is_none() { return Err(Error::new_spanned(input, "Invalid type")); } res.unwrap() } else { return Err(Error::new_spanned(input, "Invalid type")); } } else { OutputType::Value(input) } } else { OutputType::Value(input) }; Ok(ty) } pub fn value_type(&self) -> Type { let tokens = match self { OutputType::Value(ty) => quote! {#ty}, OutputType::Result(_, ty) => quote! {#ty}, }; let mut ty = syn::parse2::(tokens).unwrap(); Self::remove_lifecycle(&mut ty); ty } fn remove_lifecycle(ty: &mut Type) { match ty { Type::Reference(r) => { r.lifetime = None; Self::remove_lifecycle(&mut r.elem); } Type::Path(r) => { for s in &mut r.path.segments { if let PathArguments::AngleBracketed(args) = &mut s.arguments { for arg in &mut args.args { match arg { GenericArgument::Lifetime(lt) => { lt.ident = Ident::new("_", Span::call_site()); } GenericArgument::Type(ty) => { Self::remove_lifecycle(ty); } _ => {} } } } } } _ => {} } } }