1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*! 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:
```text
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:
```
# use tear::prelude::*;
# fn get_value () -> Option<i32> { None }
fn f () -> Option<i32> {
terror! { get_value() => tear::gut };
# Some(1)
# }
```
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.
```text
terror! { $your-type => ... }
```
or use one of the macros in a function returning your type
```text
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.
*/
use *; // Brings symbols into scope for rustdoc links