[][src]Crate tear

Typed early returns and syntax sugar macros for try!-like error handling

Works with Rust v1.34+

Description

This crate exports the tear! and rip! macros.

tear! is used with ValRet for typed early returns. rip! is syntax-sugar for try! or the ? operator.

Usage

// Add this in your crate entrypoint (main.rs or lib.rs)
#[macro_use] extern crate tear;

// Import symbols for this example, generally not needed
use tear::prelude::*;

// Error handling. Turn this…
let x = can_error().map_err(rescue_error)?;
// …into this
let x = rip! { can_error() => rescue_error };

// Early return
fn divide(a: i32, b: i32) -> Option<f32> {
    tear_if! { b == 0, None };
    
    let quotient = (a as f32) / (b as f32);
    Some(quotient)
}

// This function tells the calling function to return early
fn return_from_function() -> ValRet<String, i32> { Ret(-1) }

// Action at a distance
fn status_code() -> i32 {
    tear! { return_from_function() }; // returns
    0
}

See the documentation for tear! and rip! for more examples.

Rationale

I wanted to make early returns more explicit.

if $cond {
    $statements;
    return $ret;
}

Normally, you can't tell from the outside if a code block will return early or not. To bring the return statement out of the block requires a way to signal that we want to return early and something to catch that signal. ValRet represents the signal and tear! returns early if needed.

Having a typed early return allows you to have functions that can force the caller function to return early. Action at a distance inspired by how Slips work in Raku.

After reading up on how the ? operator works, I thought of leveraging this typed early return for an explicit error handling syntax. I wanted to annotate each potential failure point with a symbol and associate that symbol to an error handler. Something like this:

let path = find_config_file().mark(A)
let mut file = get_file_bufwriter(&path).mark(B)

// Error handlers
[A]: .ok_or(Error::FindPathF)?;
[B]: .map_err(Error::GetFileF)?;

Turns out this is already possible, but noisy, so the rip! macro makes a bit more explicit:

This example is not tested
let path = find_config_file().ok_or(Error::FindPathF)?;
let path = rip! { find_config_file() => Error::FindPathF };

See also

Modules

prelude

Crate prelude when implementing traits

Macros

fear

(Legacy) Alias for tear! that only allows the mapping syntax

rip

try!-like error-handling macro

tear

Turns a ValRet into a value or an early return

tear_if

Explicit if statement with early return

terror

(Legacy) Alias for rip! that only allows the mapping syntax

Enums

Moral

A notion of good and bad for the rip! macro

ValRet

Represents a usable value or an early return. Use with tear!

Traits

Judge

Convert from and to Moral. Used in the rip! macro.

Return

The ability to coerce to a ValRet and be used with the tear! macro