Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup README and Docs, and repo in general #8

Merged
merged 6 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ The `error_mancer` crate adds a `#[errors]` attribute that allows you to easily

## Example Usage

For example in the following code the `#[errors]` macro automatically defines a `OpenFileError` based on the macro and substitudes in the error type in the signature.

```rs
use std::io;

Expand All @@ -28,9 +30,10 @@ fn main() {
}
```

The main benefit of this approach is that it moves the error enum definition much closer to the method, making it easier to modify. Additionally, it supports generic error results like `anyhow`. In these cases, the return type is not modified, but the allowed return values are still restricted. This is particularly useful when implementing traits that require an `anyhow::Result`.
The main benefit of this approach is that it moves the error enum definition much closer to the method, making it easier to modify.

## Trait Implementation Example
## `anyhow` support
Additionally, it supports generic error results like `anyhow`. In these cases, the return type is not modified, but the allowed return values are still restricted. This is particularly useful when implementing traits that require an `anyhow::Result`.

```rs
use error_mancer::*;
Expand All @@ -39,8 +42,8 @@ use error_mancer::*;
impl other_crate::Trait for MyStruct {
#[errors]
fn some_method(&self) -> anyhow::Result<()> {
// This would cause a compiler error now!
// std::fs::open("hello.txt")?;
// This is a compiler error now!
std::fs::open("hello.txt")?;
}
}
```
Expand All @@ -49,4 +52,7 @@ impl other_crate::Trait for MyStruct {

- **Simplified Error Wrapper Enums**: This crate aims to make defining trivial error wrapper enums much easier and more convenient.
- **Enforcing Error Restrictions**: It aims to allow you to enforce error restrictions on `anyhow::Result` and similar `Result` types.
- **Compatibility with `thiserror`**: This crate does **not** aim to replace `thiserror` or similar libraries. Instead, it encourages using them in tandem to define errors for use with `error_mancer`.
- **Compatibility with `thiserror`**: This crate does **not** aim to replace `thiserror` or similar libraries. They are designed for public-facing errors where control over details is important. In contrast, this library is focused on minimizing boilerplate as much as possible, providing less control but offering sensible defaults for internal error enums.

In other words, what if `anyhow` was strongly typed on the possible errors?

39 changes: 19 additions & 20 deletions error_mancer/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
//! # `errors` Macro Documentation
//!
//! ## Overview
//!
//! The primary macro in this crate is `errors`, designed to simplify error handling by allowing developers to define and restrict error types directly within functions. This reduces boilerplate code and improves readability.
//!
//! ## Usage
//! # Usage
//!
//! ### Basic Example
//! ## Basic Example
//!
//! Below is a basic example of how to use the `errors` macro:
//!
Expand All @@ -30,6 +26,7 @@
//! This macro automatically generates an enum resembling the following and sets the `Result` error type to it, so developers do not need to manually define it:
//!
//! ```rust,ignore
//! // Auto generated code from `#[errors]`
//! #[derive(Debug)]
//! enum FooError {
//! StdIo(std::io::Error),
Expand All @@ -42,7 +39,7 @@
//!
//! Defining no errors also works, which will generate an enum with no variants, enforcing that no errors are returned. This is useful for functions that are guaranteed not to fail but still require a `Result<...>` return type, such as in trait implementations. It provides extra safety by ensuring that no error paths are possible.
//!
//! ### Usage in `impl` Blocks
//! ## Usage in `impl` Blocks
//!
//! To use the macro within an `impl` block, the block must also be annotated:
//!
Expand All @@ -59,7 +56,7 @@
//! }
//! ```
//!
//! ### Usage with `anyhow::Result`
//! ## Usage with `anyhow::Result`
//!
//! The macro can also be used without overwriting an error type and is fully compatible with `anyhow::Result` and similar types. This is especially useful for developers who prefer using `anyhow` for general error handling but want to benefit from additional error type restrictions when needed, particularly in trait implementations:
//!
Expand All @@ -68,7 +65,8 @@
//!
//! #[errors]
//! fn foo() -> anyhow::Result<()> {
//! // This would cause a compiler error
//! // ❌ Compiler error: `std::fs::File::open(...)` returns `std::io::Error`,
//! // but `#[errors]` enforces that no errors are allowed.
//! std::fs::File::open("hello.txt")?;
//! Ok(())
//! }
Expand Down Expand Up @@ -103,7 +101,7 @@
//!
//! ## Deriving traits for generated enum
//! You can annotate the function with `#[derive]` to derive traits for the generated enum.
//! Note that the `#[derive]` macro must be used after the `errors` macro. (techically in `impl`
//! Note that the `#[derive]` macro must be used after the `errors` macro. (technically in `impl`
//! blocks the order doesnt matter, but we recommend using `#[derive]` after `errors` for consistency.)
//! ```rust
//! # use error_mancer::prelude::*;
Expand All @@ -123,9 +121,9 @@
//! }
//! ```
//!
//! ## Specifics and Implementation Details
//! # Specifics and Implementation Details
//!
//! ### Error Type Overwriting
//! ## Error Type Overwriting
//!
//! The macro looks for a type named `Result` in the root of the return type. If the second generic argument is `_`, it replaces it with the appropriate error type. See the examples below:
//!
Expand All @@ -134,23 +132,23 @@
//! | `Result<T, _>` | `Result<T, FooError>` |
//! | `std::result::Result<T, _>` | `std::result::Result<T, FooError>` |
//! | `anyhow::Result<T>` | `anyhow::Result<T>` |
//! | `Vec<Result<T, _>>` | `Vec<Result<T, _>>`, leading to a compiler error |
//! | `Vec<Result<T, _>>` | ❌ compiler error, nested types arent replaced |
//!
//! ### Enum Visibility
//! ## Enum Visibility
//!
//! The generated enum takes on the visibility of the function. The only exception is when the error type is not replaced, such as with `anyhow::Result`. In this case, the enum is emitted inside the function body, making it inaccessible to the rest of the module.
//!
//! ### Naming Conventions
//! ## Naming Conventions
//!
//! The enum name is derived from the function name, converted to Pascal case using the `case_fold` crate to conform to Rust naming conventions for types and enums. Similarly, variant names are derived from the path segments of the types, with the "Error" suffix removed if present. For example, `std::io::Error` would produce a variant called `StdIo`, while `io::Error` would produce `Io`.
//!
//! ### Display Implementation
//! ## Display Implementation
//!
//! The `Display` implementation simply delegates to each contained error, ensuring consistent and readable error messages.
//!
//! ### `into_super_error`
//! ## `into_super_error`
//! This function uses the `FlattenInto` trait which is automatically implemented by the macro for
//! its errors, for all types which implemnt `From<...>` for each of its variants. i.e a generated
//! its errors, for all target types which implemnt `From<...>` for each of the errors variants. i.e a generated
//! implementation might look like:
//! ```rust
//! # use error_mancer::{FlattenInto, errors};
Expand Down Expand Up @@ -197,12 +195,12 @@ pub trait ErrorMancerFrom<T> {
}

/// This trait allows a error to be flattened into another one and is automatically implemented by
/// the `#[errors]` macro for all super errors that implen `From<...>` for each of its fields.
/// the `#[errors]` macro for all super errors that implement `From<...>` for each of its fields.
pub trait FlattenInto<T> {
fn flatten(self) -> T;
}

/// This trait extends `Result` with a additonal method to upcast a error enum.
/// This trait extends `Result` with an additional method to upcast a error enum.
pub trait ResultExt<T, E> {
/// This will convert from the current `E` into the specified super error.
fn into_super_error<S>(self) -> Result<T, S>
Expand All @@ -211,6 +209,7 @@ pub trait ResultExt<T, E> {
}

impl<T, E> ResultExt<T, E> for Result<T, E> {
#[inline(always)]
fn into_super_error<S>(self) -> Result<T, S>
where
E: FlattenInto<S>,
Expand Down
1 change: 0 additions & 1 deletion error_mancer/tests/ui/missing_return_type.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use anyhow::Result;
use error_mancer::prelude::*;

#[errors]
Expand Down
12 changes: 2 additions & 10 deletions error_mancer/tests/ui/missing_return_type.stderr
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
error: Function must have a return type of Result<Ok, Err>
--> tests/ui/missing_return_type.rs:4:1
--> tests/ui/missing_return_type.rs:3:1
|
4 | #[errors]
3 | #[errors]
| ^^^^^^^^^
|
= note: this error originates in the attribute macro `errors` (in Nightly builds, run with -Z macro-backtrace for more info)

warning: unused import: `anyhow::Result`
--> tests/ui/missing_return_type.rs:1:5
|
1 | use anyhow::Result;
| ^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
2 changes: 1 addition & 1 deletion error_mancer_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ fn create_function(
generate_error_type(attr, signature.ident.to_string(), vis.clone(), derives)?;

let inner_type: syn::ReturnType =
parse_quote!(-> core::result::Result<#ok_return_type, #error_return_type>);
parse_quote!(-> ::core::result::Result<#ok_return_type, #error_return_type>);

let replaced = replace_error_value(&mut signature.output, error_return_type);

Expand Down
96 changes: 0 additions & 96 deletions flake.lock

This file was deleted.

40 changes: 0 additions & 40 deletions flake.nix

This file was deleted.

9 changes: 9 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
test:
cargo nextest run
cargo test --doc

update_ui:
TRYBUILD=overwrite cargo nextest run ui

docs:
cargo doc --open
Loading