Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/modprog/manyhow
https://github.com/modprog/manyhow
Last synced: 2 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/modprog/manyhow
- Owner: ModProg
- License: apache-2.0
- Created: 2023-04-03T16:45:16.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2024-08-31T10:59:07.000Z (4 months ago)
- Last Synced: 2024-09-26T14:36:26.777Z (4 months ago)
- Language: Rust
- Size: 163 KB
- Stars: 6
- Watchers: 2
- Forks: 2
- Open Issues: 12
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE-APACHE
Awesome Lists containing this project
README
# manyhow
## anyhow for proc macros
[![CI Status](https://github.com/ModProg/manyhow/actions/workflows/test.yaml/badge.svg)](https://github.com/ModProg/manyhow/actions/workflows/test.yaml)
[![Crates.io](https://img.shields.io/crates/v/manyhow)](https://crates.io/crates/manyhow)
[![Docs.rs](https://img.shields.io/crates/v/template?color=informational&label=docs.rs)](https://docs.rs/manyhow)
[![Documentation for `main`](https://img.shields.io/badge/docs-main-informational)](https://modprog.github.io/manyhow/manyhow/)Proc **m**acro **anyhow**, a combination of ideas from
[`anyhow`](https://docs.rs/anyhow) and
[`proc-macro-error`](https://docs.rs/proc-macro-error) to improve proc macro
development, especially focused on the error handling.## Motivation
Error handling in proc-macros is unideal, as the top level functions of proc
macros can only return `TokenStreams` both in success and failure case. This
means that I often write code like this, moving the actual implementation in
a separate function to be able to use the ergonomic rust error handling with
e.g., `?`.
```rust
use proc_macro2::TokenStream as TokenStream2;
#[proc_macro]
pub fn my_macro(input: TokenStream) -> TokenStream {
match actual_implementation(input.into()) {
Ok(output) => output,
Err(error) => error.into_compile_error(),
}
.into()
}
fn actual_implementation(input: TokenStream2) -> syn::Result {
// ..
}
```## Using the `#[manyhow]` macro
To activate the error handling, just add `#[manyhow]` above any
proc macro implementation, reducing the above example to:```rust
use manyhow::manyhow;
use proc_macro2::TokenStream as TokenStream2;
#[manyhow]
#[proc_macro]
fn my_macro(input: TokenStream2) -> syn::Result {
// ..
}
```See [Without macros](#without-macros) to see what this expands to under the
hood.A proc macro function marked as `#[manyhow]` can take and return any
`TokenStream` and can also return `Result` where `E` implements `ToTokensError`. As additional parameters a
[dummy](#dummy-mut-tokenstream) and/or [emitter](#emitter-mut-emitter) can
be specified.The `manyhow` attribute takes one optional flag when used for `proc_macro`
and `proc_macro_attribute`. `#[manyhow(input_as_dummy)]` will take the input
of a function like `proc_macro` to initialize the [dummy `&mut
TokenStream`](#dummy-mut-tokenstream) while `#[manyhow(item_as_dummy)]` on
`proc_macro_attribute` will initialize the dummy with the annotated item.## Without macros
`manyhow` can be used without proc macros, and they can be disabled by
adding `manyhow` with `default-features=false`.The usage is more or less the same, though with some added boilerplate from
needing to invoke one of `function`, `attribute` or `derive`
directly.While the examples use closures, functions can be passed in as well. The
above example would then change to:
```rust
use proc_macro2::TokenStream as TokenStream2;
#[proc_macro]
pub fn my_macro(input: TokenStream) -> TokenStream {
manyhow::function(
input,
false,
|input: TokenStream2| -> syn::Result {
// ..
},
)
}
```
[`Emitter`](#emitter-mut-emitter) and [dummy
`TokenStream`](#dummy-mut-tokenstream) can also be used. `function` and
`attribute` take an additional boolean parameter controlling whether the
input/item will be used as initial dummy.## `emitter: &mut Emitter`
`MacroHandler`s (the trait defining what closures/functions can be used
with `manyhow`) can take a mutable reference to an `Emitter`. This
allows to collect errors, but not fail immediately.`Emitter::into_result` can be used to return if an `Emitter` contains
any values.```rust
use manyhow::{manyhow, Emitter, ErrorMessage};
use proc_macro2::TokenStream as TokenStream2;
#[manyhow]
#[proc_macro]
fn my_macro(input: TokenStream2, emitter: &mut Emitter) -> manyhow::Result {
// ..
emitter.emit(ErrorMessage::call_site("A fun error!"));
emitter.into_result()?;
// ..
}
```## `dummy: &mut TokenStream`
`MacroHandler`s also take a mutable reference to a `TokenStream`, to
enable emitting some dummy code to be used in case the macro errors.This allows either appending tokens e.g., with `ToTokens::to_tokens` or
directly setting the dummy code e.g., `*dummy = quote!{some tokens}`.