throwing 0.1.1

Create explicit errors easily with a handy macro
Documentation
//! This crate implements a [`#[throws(...)]`][throws] macro that allows you to easily
//! declare what errors a function can return.
//! This will allow you to exhaustively match on all possible errors.
//! It is inspired by [declared exceptions][java-throws] in Java.
//! 
//! The [`#[throws(...)]`][throws] macro will automatically generate an enum that can
//! represent all declared errors, generate [`From<T>`] implementations for
//! each variant, and change the return type of the function to
//! an appropriate [`Result<T, E>`].
//! The error type will also have implementations of [`Error`], [`Display`] and [`Debug`].
//! 
//! Additionally, it can generate [`From<T>`] implementation for upcasting errors,
//! that is converting an error of a type with fewer variants to one with more variants.
//! 
//! [java-throws]: https://docs.oracle.com/javase/tutorial/essential/exceptions/declaring.html

#[cfg(doc)]
use std::{error::Error, fmt::Display};

/// Creates a new composite error type with a given name.
///
/// This macro works almost exactly like [`#[throws]`][throws],
/// except that it isn't attached to a function.
///
/// Since there is no way to infer a name for the type,
/// it must be specified explicitly with `type SomeError = ...`.
/// Unlike [`#[throws]`][throws], this macro also accepts a visibility declaration,
/// since it cannot be copied from the function.
///
/// # Examples
///
/// ```
/// # use throwing::define_error;
/// # use std::{io, num::ParseIntError};
/// #
/// # define_error!(type HttpError);
/// # define_error!(type ZipError);
/// #
/// // Defines an error with a single variant
/// // ParseIntListError will implement From<ParseIntError>.
/// define_error!(type ParseIntListError = ParseIntError);
///
/// // Defines an error with a multiple variants
/// define_error!(type DownloadFileError = HttpError | io::Error);
///
/// // Defines an error with a suberror
/// // DownloadDirError will implement From<DownloadFileError>.
/// define_error!(type DownloadDirError = HttpError | io::Error | ZipError | break DownloadFileError);
///
/// // Defines a public error
/// define_error!(pub type PublicError = io::Error);
///
/// // Defines a error crate-wide error
/// define_error!(pub(crate) type CrateWideError = io::Error);
/// ```
/// 
/// ```
/// # use std::{num::ParseIntError, str::FromStr};
/// # use throwing::define_error;
/// pub struct Id(u64);
/// 
/// define_error!(pub type ParseIdError = ParseIntError);
/// 
/// impl FromStr for Id {
///     type Err = ParseIdError;
///     
///     fn from_str(s: &str) -> Result<Self, Self::Err> {
///         let value = s.parse()?;
///         Ok(value)
///     }
/// }
/// ```
pub use throwing_macros::define_error;

/// Creates a new composite error type for a function to return.
///
/// This macro can be attached to a function to declare what types
/// of errors it can return.
/// It accepts a list of types, delimited with `|` characters, for example
/// `#[throws(FooError | BarError)]`.
///
/// It will create a custom error enum with a variant for each listed error type.
/// It will also change the function signature to a [`Result`]
/// with said enum as its error type.
/// The [`define_error!()`] macro works the same, except it isn't attached to a function.
///
/// For example, this code:
///
/// ```no_run
/// # use throwing::{throws, define_error};
/// # define_error!(type FooError);
/// # define_error!(type BarError);
/// #
/// #[throws(FooError | BarError)]
/// fn do_something() {
///     Ok(())
/// }
/// ```
///
/// Will translate roughly to this:
///
/// ```no_run
/// # struct FooError;
/// # struct BarError;
/// #
/// enum DoSomethingError {
///     FooError(FooError),
///     BarError(BarError),
/// }
///
/// fn do_something() -> Result<(), DoSomethingError> {
///     Ok(())
/// }
/// ```
///
/// The error enum will implement [`From<T>`] for each of its error type variants,
/// allowing the use of the `?` operator inside the function.
///
/// Additionally, it is possible to add "suberror" types prefixed with the `break` keyword.
/// It must be used with a error type that implements the [`SubError`] trait,
/// which all error types generated by this crate do.
/// Doing so will generate a [`From<T>`] implementation that upcasts the suberror
/// into the error type returned by the function.
/// (Hence "breaking" its variants apart.)
/// To do this, it's variants have to be a subset of the errors the function
/// can return.
///
/// Suppose you have two functions:
///
/// ```no_run
/// # use throwing::{throws, define_error};
/// # define_error!(type FooError);
/// # define_error!(type BarError);
/// # define_error!(type BazError);
/// #
/// #[throws(FooError | BarError)]
/// fn first() {
///     unimplemented!("Some complicated implementation...")
/// }
///
/// #[throws(FooError | BarError | BazError | break FirstError)]
/// fn second() {
///     first()?;
///     Ok(())
/// }
/// ```
///
/// If the `first()` function returns `FirstError::FooError`,
/// the `second()` function will return `SecondError::FooError`.
/// Similarly, `FirstError::BarError` will map to `SecondError::BarError`.
/// `SecondError::BazError` can never be returned.
///
/// The enum will also have a [`Display`] implementation that simply forwards
/// to the [`Display`] implementation of each variant.
/// It will also implement [`Error`] and provide the [`Error::source()`] method.
///
/// # Syntax
///
/// The main body of the macro arguments consists of a list of types,
/// separated by `|` characters.
/// They can either be variants, which are written as just a type name,
/// or suberrors, which are prefixed with the `break` keyword.
/// For example, `#[throws(FooError | break BarError)]` declares a variant `FooError`
/// and a suberror `BarError`.
///
/// The name of a variant can be generated automatically if the type is a simple path.
/// The generated name will consist of the entire path converted to camel case.
/// For example, `io:Error` will become `IoError` and `ParseIntError` will remain `ParseIntError`.
/// The name can be specified explicitly with the `as` keyword, for example `io::Error as InputError`.
///
/// The name of the error type can be generated automatically as well.
/// It will be generated by converting the function name to camel case and appending "`Error`".
/// For example, `fn upload_image()` will return a `UploadImageError`.
/// The name can also be specified explicitly using `type SomeError = ...`.
/// For example, to name your error type `SubmitError`, you should use
/// `#[throws(type SubmitError = FooError | BarError)].`
///
/// # Examples
///
/// ```no_run
/// # use throwing::throws;
/// # use std::{
/// #     io::{self, stdin, stdout, BufRead, Write},
/// #     num::ParseIntError,
/// # };
/// #[throws(ParseIntError | io::Error)]
/// fn main() {
///     let mut sum = 0u64;
///
///     for line in stdin().lock().lines() {
///         let value: u64 = line?.parse()?;
///         sum += value;
///     }
///
///     writeln!(stdout(), "{sum}")?;
///     Ok(())
/// }
/// ```
///
/// ```
/// # use throwing::throws;
/// # use std::{io, fs, path::Path, num::ParseIntError};
/// #[throws(type ParseListError = ParseIntError as ParseElementError)]
/// fn parse(s: &str) -> Vec<u64> {
///     let mut result = Vec::new();
///
///     for line in s.split('\n') {
///         result.push(line.parse()?);
///     }
///
///     Ok(result)
/// }
///
/// #[throws(io::Error | ParseIntError | break ParseListError)]
/// pub fn load_int_list(path: &Path) -> Vec<u64> {
///     let content = fs::read_to_string(path)?;
///     Ok(parse(&content)?)
/// }
///
/// # fn main() {
/// #     assert_eq!(parse("12\n34").unwrap(), vec![12, 34]);
/// # }
/// ```
pub use throwing_macros::throws;

/// Represents an error that can be upcasted to a different error type.
/// 
/// If type `A` implements `SubError<B>`, that means that `B` contains all
/// variants that `A` has, and as such `A` can be converted to `B`.
/// 
/// This trait powers the [`#[throws]`][throws] and [`define_error!()`] macros.
/// It's implemented by all error types they generate and required for suberrors
/// declared with the `break` keyword.
pub trait SubError<T> {
    /// Upcasts this error to a super type.
    fn to_super_error(self) -> T;
}