aboutsummaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs103
1 files changed, 93 insertions, 10 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 2c9bd77..d0be8b4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,7 +2,7 @@
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
-//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
+//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
//!
//! <br>
//!
@@ -119,31 +119,110 @@
//! [Kixunil]: https://github.com/Kixunil
//! [`dont_panic`]: https://github.com/Kixunil/dont_panic
+#![doc(html_root_url = "https://docs.rs/no-panic/0.1.21")]
+#![allow(
+ clippy::doc_markdown,
+ clippy::match_same_arms,
+ clippy::missing_panics_doc
+)]
+#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))]
+
extern crate proc_macro;
use proc_macro::TokenStream;
-use proc_macro2::Span;
+use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::quote;
-use syn::{parse_macro_input, parse_quote, Attribute, FnArg, Ident, ItemFn, PatType, ReturnType};
+use syn::parse::{Error, Nothing, Result};
+use syn::{
+ parse_quote, Attribute, FnArg, GenericArgument, Ident, ItemFn, Pat, PatType, Path,
+ PathArguments, ReturnType, Token, Type, TypeInfer, TypeParamBound,
+};
#[proc_macro_attribute]
-pub fn no_panic(args: TokenStream, function: TokenStream) -> TokenStream {
- assert!(args.is_empty());
+pub fn no_panic(args: TokenStream, input: TokenStream) -> TokenStream {
+ let args = TokenStream2::from(args);
+ let input = TokenStream2::from(input);
+ let expanded = match parse(args, input.clone()) {
+ Ok(function) => expand_no_panic(function),
+ Err(parse_error) => {
+ let compile_error = parse_error.to_compile_error();
+ quote!(#compile_error #input)
+ }
+ };
+ TokenStream::from(expanded)
+}
+
+fn parse(args: TokenStream2, input: TokenStream2) -> Result<ItemFn> {
+ let function: ItemFn = syn::parse2(input)?;
+ let _: Nothing = syn::parse2::<Nothing>(args)?;
+ if function.sig.asyncness.is_some() {
+ return Err(Error::new(
+ Span::call_site(),
+ "no_panic attribute on async fn is not supported",
+ ));
+ }
+ Ok(function)
+}
+
+// Convert `Path<impl Trait>` to `Path<_>`
+fn make_impl_trait_wild(ret: &mut Type) {
+ match ret {
+ Type::ImplTrait(impl_trait) => {
+ *ret = Type::Infer(TypeInfer {
+ underscore_token: Token![_](impl_trait.impl_token.span),
+ });
+ }
+ Type::Array(ret) => make_impl_trait_wild(&mut ret.elem),
+ Type::Group(ret) => make_impl_trait_wild(&mut ret.elem),
+ Type::Paren(ret) => make_impl_trait_wild(&mut ret.elem),
+ Type::Path(ret) => make_impl_trait_wild_in_path(&mut ret.path),
+ Type::Ptr(ret) => make_impl_trait_wild(&mut ret.elem),
+ Type::Reference(ret) => make_impl_trait_wild(&mut ret.elem),
+ Type::Slice(ret) => make_impl_trait_wild(&mut ret.elem),
+ Type::TraitObject(ret) => {
+ for bound in &mut ret.bounds {
+ if let TypeParamBound::Trait(bound) = bound {
+ make_impl_trait_wild_in_path(&mut bound.path);
+ }
+ }
+ }
+ Type::Tuple(ret) => ret.elems.iter_mut().for_each(make_impl_trait_wild),
+ Type::BareFn(_) | Type::Infer(_) | Type::Macro(_) | Type::Never(_) | Type::Verbatim(_) => {}
+ #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
+ _ => {}
+ }
+}
- let mut function = parse_macro_input!(function as ItemFn);
+fn make_impl_trait_wild_in_path(path: &mut Path) {
+ for segment in &mut path.segments {
+ if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
+ for arg in &mut bracketed.args {
+ if let GenericArgument::Type(arg) = arg {
+ make_impl_trait_wild(arg);
+ }
+ }
+ }
+ }
+}
+fn expand_no_panic(mut function: ItemFn) -> TokenStream2 {
let mut move_self = None;
let mut arg_pat = Vec::new();
let mut arg_val = Vec::new();
for (i, input) in function.sig.inputs.iter_mut().enumerate() {
let numbered = Ident::new(&format!("__arg{}", i), Span::call_site());
match input {
- FnArg::Typed(PatType { pat, .. }) => {
+ FnArg::Typed(PatType { pat, .. })
+ if match pat.as_ref() {
+ Pat::Ident(pat) => pat.ident != "self",
+ _ => true,
+ } =>
+ {
arg_pat.push(quote!(#pat));
arg_val.push(quote!(#numbered));
*pat = parse_quote!(mut #numbered);
}
- FnArg::Receiver(_) => {
+ FnArg::Typed(_) | FnArg::Receiver(_) => {
move_self = Some(quote! {
if false {
loop {}
@@ -168,7 +247,11 @@ pub fn no_panic(args: TokenStream, function: TokenStream) -> TokenStream {
let ret = match &function.sig.output {
ReturnType::Default => quote!(-> ()),
- output @ ReturnType::Type(..) => quote!(#output),
+ ReturnType::Type(arrow, output) => {
+ let mut output = output.clone();
+ make_impl_trait_wild(&mut output);
+ quote!(#arrow #output)
+ }
};
let stmts = function.block.stmts;
let message = format!(
@@ -200,5 +283,5 @@ pub fn no_panic(args: TokenStream, function: TokenStream) -> TokenStream {
__result
}));
- TokenStream::from(quote!(#function))
+ quote!(#function)
}