1use proc_macro::TokenStream;
2use proc_macro2::TokenStream as TokenStream2;
3use quote::quote;
4use venial::{Declaration, Error, Function};
5
6#[proc_macro_attribute]
35pub fn try_fn(_attr: TokenStream, item: TokenStream) -> TokenStream {
36 impl_try_fn(item.into())
37 .unwrap_or_else(|e| e.to_compile_error())
38 .into()
39}
40
41#[proc_macro_attribute]
42#[deprecated(note = "renamed to `try_fn`")]
43pub fn tryvial(_attr: TokenStream, item: TokenStream) -> TokenStream {
44 impl_try_fn(item.into())
45 .unwrap_or_else(|e| e.to_compile_error())
46 .into()
47}
48
49fn impl_try_fn(input: TokenStream2) -> Result<TokenStream2, Error> {
50 let decl = venial::parse_declaration(input)?;
51 let Function {
52 attributes,
53 vis_marker,
54 qualifiers,
55 tk_fn_keyword,
56 name,
57 generic_params,
58 tk_params_parens: _,
59 params,
60 where_clause,
61 tk_return_arrow: _,
62 return_ty,
63 tk_semicolon: _,
64 body,
65 } = match decl {
66 Declaration::Function(item) => item,
67 _ => Err(Error::new("`#[try_fn]` is supported only on `fn` items"))?,
68 };
69
70 let body = body.ok_or(Error::new(
71 "`#[try_fn]` can only be used on functions with a body",
72 ))?;
73
74 let return_ty = return_ty.map_or_else(|| quote! { () }, |ty| quote! { #ty });
75
76 Ok(quote! {
77 #(#attributes)*
78 #vis_marker #qualifiers #tk_fn_keyword #name #generic_params ( #params ) -> #return_ty
79 #where_clause
80 {
81 ::core::iter::empty().try_fold(#body, |_, __x: ::core::convert::Infallible| match __x {})
82 }
83 })
84}