async_graphql_derive/
output_type.rs

1use proc_macro2::{Ident, Span};
2use quote::quote;
3use syn::{Error, GenericArgument, PathArguments, Result, Type};
4
5pub enum OutputType<'a> {
6    Value(&'a Type),
7    Result(&'a Type),
8}
9
10impl<'a> OutputType<'a> {
11    pub fn parse(input: &'a Type) -> Result<Self> {
12        let ty = if let Type::Path(p) = input {
13            if p.path.segments.last().unwrap().ident == "Result"
14                || p.path.segments.last().unwrap().ident == "FieldResult"
15            {
16                if let PathArguments::AngleBracketed(args) =
17                    &p.path.segments.last().unwrap().arguments
18                {
19                    if args.args.is_empty() {
20                        return Err(Error::new_spanned(input, "Invalid type"));
21                    }
22                    let mut res = None;
23                    for arg in &args.args {
24                        if let GenericArgument::Type(value_ty) = arg {
25                            res = Some(OutputType::Result(value_ty));
26                            break;
27                        }
28                    }
29                    if res.is_none() {
30                        return Err(Error::new_spanned(input, "Invalid type"));
31                    }
32                    res.unwrap()
33                } else {
34                    return Err(Error::new_spanned(input, "Invalid type"));
35                }
36            } else {
37                OutputType::Value(input)
38            }
39        } else {
40            OutputType::Value(input)
41        };
42        Ok(ty)
43    }
44
45    pub fn value_type(&self) -> Type {
46        let tokens = match self {
47            OutputType::Value(ty) => quote! {#ty},
48            OutputType::Result(ty) => quote! {#ty},
49        };
50        let mut ty = syn::parse2::<syn::Type>(tokens).unwrap();
51        Self::remove_lifecycle(&mut ty);
52        ty
53    }
54
55    fn remove_lifecycle(ty: &mut Type) {
56        match ty {
57            Type::Reference(r) => {
58                r.lifetime = None;
59                Self::remove_lifecycle(&mut r.elem);
60            }
61            Type::Path(r) => {
62                for s in &mut r.path.segments {
63                    if let PathArguments::AngleBracketed(args) = &mut s.arguments {
64                        for arg in &mut args.args {
65                            match arg {
66                                GenericArgument::Lifetime(lt) => {
67                                    lt.ident = Ident::new("_", Span::call_site());
68                                }
69                                GenericArgument::Type(ty) => {
70                                    Self::remove_lifecycle(ty);
71                                }
72                                _ => {}
73                            }
74                        }
75                    }
76                }
77            }
78            _ => {}
79        }
80    }
81}