Skip to content

Commit

Permalink
Merge pull request #7 from Nemo157/nightly-fix
Browse files Browse the repository at this point in the history
Fix nightly, improve docs
  • Loading branch information
Nemo157 authored Sep 21, 2023
2 parents 9ae83c7 + e2c105f commit 8a90f93
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 90 deletions.
13 changes: 9 additions & 4 deletions macros/src/throws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down
177 changes: 91 additions & 86 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -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<T: Eq + Ord>(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<T: Eq + Ord>(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.
Expand Down

0 comments on commit 8a90f93

Please sign in to comment.