https://github.com/tqdv/tear
Typed early returns and loop control + Syntax sugar for try!-like error handling
https://github.com/tqdv/tear
early-return error-handling macro syntax-sugar
Last synced: 3 months ago
JSON representation
Typed early returns and loop control + Syntax sugar for try!-like error handling
- Host: GitHub
- URL: https://github.com/tqdv/tear
- Owner: tqdv
- License: apache-2.0
- Created: 2020-05-19T13:08:27.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2021-04-11T19:34:47.000Z (about 5 years ago)
- Last Synced: 2025-11-09T04:08:46.330Z (7 months ago)
- Topics: early-return, error-handling, macro, syntax-sugar
- Language: Rust
- Homepage: https://crates.io/crates/tear
- Size: 136 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE-APACHE
Awesome Lists containing this project
README
# tear
Typed early returns and loop control + Syntax sugar for try!-like error handling
*Works with Rust v1.34+ (released on 11 April 2019)*
## Synopsis
Import the macros into your module:
```rust
use tear::prelude::*;
```
Explicit error-handling syntax with `terror!`:
```rust
let handled = terror! { can_error() => print_error };
let variant = terror! { can_io_error() => CustomError::Io };
// Equivalent using `?`:
let handled = can_error().map_err(print_error)?;
let variant = can_io_error.map_err(CustomError::Io)?;
```
Early loop continue with `twist!`:
```rust
for re in regexes_strings {
// Skip iteration if the regex fails to compile
let re = twist! { Regex::new(re) => |_| next!() }
// Use regex...
```
Keyword-like early returns with `tear_if!`:
```rust
fn divide_i32 (num: i32, denom: i32) -> Option {
// Return early if dividing by 0
tear_if! { denom == 0, None };
// Compute quotient...
```
Typed early returns with `tear!`:
```rust
// Tells the calling function to return early on failure
fn get_value_or_return() -> ValRet { Ret(-1) }
fn status_code() -> i32 {
let v = tear! { get_value_or_return() };
// Process value...
```
See [the documentation](https://docs.rs/tear) for more info.
## Changelog
See [CHANGELOG](CHANGELOG.md).
## Rationale
**I wanted to make early returns more explicit.**
Normally, you need to read until the end of the
`if` body to know if it returns early or not. `tear_if` places that information at
the beginning of the block.
**I wanted typed early returns because it is useful for passing exitcodes up the callchain.**
Having a typed early return allows you to have functions that can force their caller
to return early. It's an action at a distance inspired by how
[Slips](https://docs.raku.org/type/Slip) work in Raku.
**I wanted annotated failure points instead of too many combinators.**
The `?` operator works is essentially a conditional early-return.
To convert the errors you get to the right type, you need to use combinators.
I find it hard to discern that those combinators are meant for error handling.
Something like this:
```rust
let path = find_config_file().ok_or(Error::FindPathF)?
let mut file = get_file_buffer(&path).map_err(Error::GetFileF)?;
```
The `terror!` macro makes the error handling more explicit:
```rust
let path = terror! { find_config_file() => Error::FindPathF };
let mut file = terror! { get_file_buffer(&path) => Error::GetFileF };
```
**Loop control and early returns are similar**
I already implemented typed early return, so why not implement typed loop controls well ?
They're the same kind of useful.
## See also
- [Error Handling in Rust §The real `try!` macro / `?` operator][error-handling try]
- [guard](https://docs.rs/crate/guard), a crate implementing "guard" expressions,
the counterpart to `tear_if!`
[error-handling try]: https://blog.burntsushi.net/rust-error-handling/#the-real-try-macro-operator
## License
Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE)
or [MIT license](LICENSE-MIT) at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion
in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above,
without any additional terms or conditions.