Module tear::overview[][src]

Overview of things in this crate

Importing the symbols

use tear::prelude::*;
use tear::extra::*;

The prelude and extra modules are meant to be used for bulk importing. You generally want to use prelude only and import extra symbols one-by-one. Some symbols in extra might conflict with yours.

All symbols are accessible directly from the crate root as we reexport them all.

Early returns

We represent an early return with ValRet and process it with tear!. The macro accepts any type that knows how to convert to a ValRet using the Return trait.

We use tear! in tear_if! to implement early returns as a syntax.

Mapping syntax

The mapping syntax is one of the following:

tear! { ... => ... }
terror! { ... => ... }
twist! { ... => ... }

When using the mapping syntax, we need to separate the wanted value, from the unwanted value that we pass to the mapping function. This is why arguments must implement the Judge trait that knows how to convert it to either Moral::Good or Moral::Bad.

Error handling

terror! is the error-handling macro. It depends on Judge to decide if the value is usable or not.

A short way of discarding the error value in a function returning Option<T>, is to use the gut function:

fn f () -> Option<i32> {
    terror! { get_value() => tear::gut };

If you need to do some things before returning None, use a block, and return tear::Maru at the end. Maru is the placeholder type used to represent the bad value of Option<T>, or the good and bad values of bool.

Loop control

The twist! macro has many forms (see its documentation), and it only processes Looping types. They represent a control signal: either resume, break, continue or breakval the loop.

Breakval is the special case of a loop-loop that can return with a value:

let x: i32 = loop {
    break 3;
};
assert_eq![ x, 3 ];

In the complex case where you want to breakval from multiple loops with a different type, you can use Box<dyn Any> to hide those type. We provide the anybox! macro to take the concrete type, and wrap it into a Box<dyn Any> object. See twist! documentation for more information.

use tear::prelude::*;

let x: i32 = 'a: loop {
	let y: String = 'b: loop {
		let _ = twist! { -box -val String, -label 'a: i32 |
			Looping::BreakVal { label: Some(0), value: anybox!(3) }
		};
		if false { break "a".to_string() }
	};
};
assert_eq![ x, 3 ];

For simple cases where you only break from one loop (ie. when you don’t use -labels), you can use the last!, next!, and resume! as shortcuts for the right-hand side of twist!:

use tear::extra::*;
loop {
    let v = twist! { Some(2) => |_| resume!(5) };
    twist! { None => |_| last!() };
}

There’s also next_if! and last_if! macros that continue or break the loop based on a condition or a pattern match.

Add functionality to your own types

If you want to enable the mapping syntax for your type.

terror! { $your-type => ... }

or use one of the macros in a function returning your type

fn f () -> $your-type {
	terror! { ... }
}

You only need to implement Judge trait for that type, because Return is automatically implemented for you.

If using the “experimental” crate feature, then you only need to implement the Try trait. The Judge and Return trait will be automatically implemented.