rocket_codegen/bang/
typed_stream.rs1use proc_macro2::TokenStream;
2use syn::parse::{Parse, ParseStream, discouraged::Speculative};
3
4#[derive(Debug)]
5pub enum Input {
6 Type(syn::Type, Option<(syn::Token![+], syn::Lifetime)>),
7 Tokens(TokenStream)
8}
9
10#[derive(Debug)]
11struct Invocation {
12 ty_stream_ty: syn::Path,
13 stream_mac: syn::Path,
14 stream_trait: syn::Path,
15 input: Input,
16}
17
18fn trait_obj_recast(ty: &syn::Type) -> Option<(syn::Type, syn::Token![+], syn::Lifetime)> {
20 let bounds = match ty {
21 syn::Type::TraitObject(t) if t.dyn_token.is_none() => &t.bounds,
22 _ => return None
23 };
24
25 let mut bounds = bounds.pairs();
26 let (first, second) = (bounds.next()?, bounds.next()?);
27 let plus = **first.punct().expect("have two so have punct");
28
29 let first = first.value();
30 let real_ty = syn::parse2(quote!(#first)).ok()?;
31 let lifetime = match second.value() {
32 syn::TypeParamBound::Lifetime(lt) => lt.clone(),
33 _ => return None,
34 };
35
36 Some((real_ty, plus, lifetime))
37}
38
39impl Parse for Input {
40 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
41 let fork = input.fork();
42 if let Ok(mut ty) = fork.parse() {
43 let mut bound = match fork.parse() {
45 Ok(plus) => Some((plus, fork.parse()?)),
46 _ => None,
47 };
48
49 if let Some((real_ty, plus, lt)) = trait_obj_recast(&ty) {
51 ty = real_ty;
52 bound = Some((plus, lt));
53 }
54
55 if fork.is_empty() {
57 input.advance_to(&fork);
58 Ok(Input::Type(ty, bound))
59 } else {
60 Ok(Input::Tokens(input.parse()?))
61 }
62 } else {
63 Ok(Input::Tokens(input.parse()?))
64 }
65 }
66}
67
68impl Parse for Invocation {
69 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
70 Ok(Invocation {
71 ty_stream_ty: (input.parse()?, input.parse::<syn::Token![,]>()?).0,
72 stream_mac: (input.parse()?, input.parse::<syn::Token![,]>()?).0,
73 stream_trait: (input.parse()?, input.parse::<syn::Token![,]>()?).0,
74 input: input.parse()?,
75 })
76 }
77}
78
79pub fn _macro(input: proc_macro::TokenStream) -> devise::Result<TokenStream> {
84 let tokens = proc_macro2::TokenStream::from(input);
85 let i: Invocation = syn::parse2(tokens)?;
86 let (s_ty, mac, s_trait) = (i.ty_stream_ty, i.stream_mac, i.stream_trait);
87 let tokens = match i.input {
88 Input::Tokens(tt) => quote!(#s_ty::from(#mac!(#tt))),
89 Input::Type(ty, Some((p, l))) => quote!(#s_ty<impl #s_trait<Item = #ty> #p #l>),
90 Input::Type(ty, None) => quote!(#s_ty<impl #s_trait<Item = #ty>>),
91 };
92
93 Ok(tokens)
94}