diff --git a/macros/src/throws.rs b/macros/src/throws.rs index 1e862db..27acd2d 100644 --- a/macros/src/throws.rs +++ b/macros/src/throws.rs @@ -111,7 +111,9 @@ impl Fold for Throws { return i; } let return_type = self.args.ret(i); - let syn::ReturnType::Type(_, ty) = &return_type else { unreachable!() }; + let syn::ReturnType::Type(_, ty) = &return_type else { + unreachable!() + }; struct ImplTraitToInfer; impl Fold for ImplTraitToInfer { fn fold_type(&mut self, i: syn::Type) -> syn::Type { @@ -139,10 +141,13 @@ impl Fold for Throws { fn make_fn_block(ty: &syn::Type, inner: &syn::Block) -> syn::Block { let mut block: syn::Block = syn::parse2(quote::quote! {{ - let __ret = #inner; + #[allow(clippy::diverging_sub_expression)] + { + let __ret = { #inner }; - #[allow(unreachable_code)] - <#ty as ::culpa::__internal::_Succeed>::from_ok(__ret) + #[allow(unreachable_code)] + <#ty as ::culpa::__internal::_Succeed>::from_ok(__ret) + } }}) .unwrap(); block.brace_token = inner.brace_token; diff --git a/src/lib.rs b/src/lib.rs index a608795..b246601 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,92 +1,97 @@ #![no_std] + +//! Annotations a function that "throws" a Result. +//! +//! Inside functions tagged with `throws`, you can use `?` and the `throw!` macro to return errors, +//! but you don't need to wrap the successful return values in `Ok`. +//! +//! Using this syntax, you can write fallible functions almost as if they were nonfallible. Every +//! time a function call would return a `Result`, you "re-raise" the error using `?`, and if you +//! wish to raise your own error, you can return it with the `throw!` macro. +//! +//! ## Example +//! ``` +//! use std::io::{self, Read}; +//! +//! use culpa::{throw, throws}; +//! +//! #[throws(io::Error)] +//! fn check() { +//! let mut file = std::fs::File::open("The_House_of_the_Spirits.txt")?; +//! let mut text = String::new(); +//! file.read_to_string(&mut text)?; +//! +//! if !text.starts_with("Barrabas came to us by sea, the child Clara wrote") { +//! throw!(io::Error::from_raw_os_error(22)); +//! } +//! +//! println!("Okay!"); +//! } +//! ``` +//! +//! # Default Error Type +//! +//! This macro supports a "default error type" - if you do not pass a type to the macro, it will +//! use the type named `Error` in this scope. So if you have defined an error type in this +//! module, that will be the error thrown by this function. +//! +//! You can access this feature by omitting the arguments entirely or by passing `_` as the type. +//! +//! ## Example +//! +//! ``` +//! use culpa::throws; +//! +//! // Set the default error type for this module: +//! type Error = std::io::Error; +//! +//! #[throws] +//! fn print() { +//! let file = std::fs::read_to_string("my_file.txt")?; +//! println!("{}", file); +//! } +//! ``` +//! +//! # Throwing as an Option +//! +//! This syntax can also support functions which return an `Option` instead of a `Result`. The +//! way to access this is to pass `as Option` as the argument to `throw`. +//! +//! In functions that return `Option`, you can use the `throw!()` macro without any argument to +//! return `None`. +//! +//! ## Example +//! +//! ``` +//! use culpa::{throw, throws}; +//! +//! #[throws(as Option)] +//! fn example(slice: &[T], needle: &T) -> usize { +//! if !slice.contains(needle) { +//! throw!(); +//! } +//! slice.binary_search(needle).ok()? +//! } +//! ``` +//! +//! # Other `Try` types +//! +//! The `?` syntax in Rust is controlled by a trait called `Try`, which is currently unstable. +//! Because this feature is unstable and I don't want to maintain compatibility if its interface +//! changes, this crate currently only works with two stable `Try` types: Result and Option. +//! However, its designed so that it will hopefully support other `Try` types as well in the +//! future. +//! +//! It's worth noting that `Try` also has some other stable implementations: specifically `Poll`. +//! Because of the somewhat unusual implementation of `Try` for those types, this crate does not +//! support `throws` syntax on functions that return `Poll` (so you can't use this syntax when +//! implementing a Future by hand, for example). I hope to come up with a way to support Poll in +//! the future. + #[doc(inline)] -/// Annotations a function that "throws" a Result. -/// -/// Inside functions tagged with `throws`, you can use `?` and the `throw!` macro to return errors, -/// but you don't need to wrap the successful return values in `Ok`. -/// -/// Using this syntax, you can write fallible functions almost as if they were nonfallible. Every -/// time a function call would return a `Result`, you "re-raise" the error using `?`, and if you -/// wish to raise your own error, you can return it with the `throw!` macro. -/// -/// ## Example -/// ```should_panic -/// use std::io::{self, Read}; -/// -/// use culpa::{throw, throws}; -/// -/// #[throws(io::Error)] -/// fn main() { -/// let mut file = std::fs::File::open("The_House_of_the_Spirits.txt")?; -/// let mut text = String::new(); -/// file.read_to_string(&mut text)?; -/// -/// if !text.starts_with("Barrabas came to us by sea, the child Clara wrote") { -/// throw!(io::Error::from_raw_os_error(22)); -/// } -/// -/// println!("Okay!"); -/// } -/// ``` -/// -/// # Default Error Type -/// -/// This macro supports a "default error type" - if you do not pass a type to the macro, it will -/// use the type named `Error` in this scope. So if you have defined an error type in this -/// module, that will be the error thrown by this function. -/// -/// You can access this feature by omitting the arguments entirely or by passing `_` as the type. -/// -/// ## Example -/// -/// ```should_panic -/// use culpa::throws; -/// -/// // Set the default error type for this module: -/// type Error = std::io::Error; -/// -/// #[throws] -/// fn main() { -/// let file = std::fs::read_to_string("my_file.txt")?; -/// println!("{}", file); -/// } -/// ``` -/// -/// # Throwing as an Option -/// -/// This syntax can also support functions which return an `Option` instead of a `Result`. The -/// way to access this is to pass `as Option` as the argument to `throw`. -/// -/// In functions that return `Option`, you can use the `throw!()` macro without any argument to -/// return `None`. -/// -/// ## Example -/// -/// ``` -/// use culpa::{throw, throws}; -/// -/// #[throws(as Option)] -/// fn example(slice: &[T], needle: &T) -> usize { -/// if !slice.contains(needle) { -/// throw!(); -/// } -/// slice.binary_search(needle).ok()? -/// } -/// ``` -/// -/// # Other `Try` types -/// -/// The `?` syntax in Rust is controlled by a trait called `Try`, which is currently unstable. -/// Because this feature is unstable and I don't want to maintain compatibility if its interface -/// changes, this crate currently only works with two stable `Try` types: Result and Option. -/// However, its designed so that it will hopefully support other `Try` types as well in the -/// future. +/// Annotates a function that "throws" a Result. /// -/// It's worth noting that `Try` also has some other stable implementations: specifically `Poll`. -/// Because of the somewhat unusual implementation of `Try` for those types, this crate does not -/// support `throws` syntax on functions that return `Poll` (so you can't use this syntax when -/// implementing a Future by hand, for example). I hope to come up with a way to support Poll in -/// the future. +/// See the main crate docs for more details. pub use culpa_macros::throws; /// Throw an error.