@@ -130,7 +130,7 @@ In this module, we define in order
130
130
pub mod overview; // For documentation
131
131
pub mod prelude;
132
132
pub mod extra;
133
- pub mod trait_impl; // Move the trait implementions as they are quite noisy
133
+ pub mod trait_impl; // Move the trait implementations as they are quite noisy
134
134
pub mod twist_impl; // Currently only for `twist!`
135
135
#[ macro_use] pub mod util; // Utility macros that aren't the main focus. To reduce file size.
136
136
@@ -147,13 +147,14 @@ use ValRet::*;
147
147
use Moral :: * ;
148
148
#[ cfg( feature = "combinators" ) ] use either:: Either :: { self , * } ;
149
149
150
- /** Represents a usable value or an early return. Use with `tear!`
150
+ /** Represents a usable value or an early return. Use with [ `tear!`]
151
151
152
152
# Description
153
153
154
154
The idea is to type an early return. The early return either evaluates to something (Val) or
155
155
returns early (Ret).
156
156
*/
157
+ #[ must_use = "Suggestion: use tear! to handle it" ]
157
158
#[ derive( PartialEq , Debug , Clone ) ]
158
159
pub enum ValRet < V , R > {
159
160
/// The usable value
@@ -164,7 +165,7 @@ pub enum ValRet<V, R> {
164
165
165
166
/**
166
167
**NB**: Other combinators such as `and`, `and_then`, `or`, `map_val`
167
- aren't implemented because I didn't need them and not because they aren't useful.
168
+ aren't implemented because I didn't need them, not because they aren't useful.
168
169
169
170
Examples will all use the following two variables
170
171
```
@@ -182,7 +183,7 @@ impl<V, R> ValRet<V, R> {
182
183
pub fn ret ( self ) -> Option < R > { maybe_match ! { self , Ret ( r) => r } }
183
184
}
184
185
185
- /// Convert into ValRet
186
+ /// Convert into [` ValRet`]
186
187
pub trait Return where Self : Sized {
187
188
/// The Val in ValRet
188
189
type Value ;
@@ -193,7 +194,7 @@ pub trait Return where Self :Sized {
193
194
fn into_valret ( self ) -> ValRet < Self :: Value , Self :: Returned > ;
194
195
}
195
196
196
- /// A notion of good and bad for the `terror!` macro
197
+ /// A notion of good and bad for the [ `terror!`] macro
197
198
#[ derive( PartialEq , Debug , Clone ) ]
198
199
pub enum Moral < Y , N > {
199
200
/// The good
@@ -248,11 +249,11 @@ impl<Y, N> Moral<Y, N> {
248
249
249
250
/* Special conversions */
250
251
251
- /** (dev) Convert to a `Looping` by mapping Good to Resume, and Bad through a function
252
+ /** (dev) Convert to a [ `Looping`] by mapping Good to Resume, and Bad through a function
252
253
253
254
The function `f` takes the bad value and maps it to a `Looping` value.
254
255
255
- Used in the `twist!` macro with the mapping (`=>`) syntax. See `twist!` documentation.
256
+ Used in the `twist!` macro with the mapping (`=>`) syntax. See [ `twist!`] documentation.
256
257
*/
257
258
pub fn resume_or_else < B > ( self , f : impl FnOnce ( N ) -> Looping < Y , B > ) -> Looping < Y , B > {
258
259
match self {
@@ -262,9 +263,9 @@ impl<Y, N> Moral<Y, N> {
262
263
}
263
264
}
264
265
265
- /** Convert from and to Moral. Used for the macro map syntax.
266
+ /** Convert from and to [` Moral`] . Used for the macro map syntax.
266
267
267
- This mirrors the `std:: ops::Try` trait.
268
+ This mirrors the [`ops::Try`](`core:: ops::Try`) trait.
268
269
269
270
It is used for the `=>` mapping syntax of macros, to differentiate the value we want to keep from
270
271
the value we want to map through the function.
@@ -304,9 +305,9 @@ pub trait Judge :Sized {
304
305
}
305
306
}
306
307
307
- /** Turns a `ValRet` into a value or an early return
308
+ /** Turns a [ `ValRet`] into a value or an early return
308
309
309
- It also coerces its argument to a ValRet ( Return trait).
310
+ It also coerces its argument to a ` ValRet` ([` Return`] trait).
310
311
311
312
# Description
312
313
@@ -326,6 +327,10 @@ let x = tear! { $e => $f }
326
327
Same as the previous form, but the return value `r` is first mapped through $f before returning.
327
328
In short, we return `$f(r)`.
328
329
330
+ Additionally, both forms make use of the [`convert::From`](`core::convert::From`) trait to automatically convert
331
+ the value when returning it. This behaviour is the same as the try operator `?`.
332
+ You may need to be more specific with type annotations so that the compiler can infer the right types.
333
+
329
334
# Examples
330
335
331
336
tear! with Val and Ret.
@@ -335,7 +340,7 @@ tear! with Val and Ret.
335
340
# use tear::prelude::*;
336
341
#
337
342
// "Ian" is assigned to name
338
- let name = tear! { Val("Ian") };
343
+ let name = tear! { Val::<_, ()> ("Ian") };
339
344
# assert_eq![ name, "Ian" ];
340
345
341
346
# fn func () -> i32 {
@@ -379,6 +384,23 @@ fn string_id(s: OsString) -> String {
379
384
# assert_eq![ string_id(OsString::from("ROOT")), "4" ];
380
385
```
381
386
387
+ Automatic conversion with `convert::From`
388
+
389
+ ```rust
390
+ # use tear::prelude::*;
391
+ #[derive(Debug, PartialEq, Eq)]
392
+ struct MyInt(u8);
393
+ impl std::convert::From<u8> for MyInt {
394
+ fn from(x :u8) -> Self { Self(x) }
395
+ }
396
+
397
+ fn five_as_myint() -> MyInt {
398
+ tear! { Ret(5) }
399
+ }
400
+
401
+ assert_eq![ five_as_myint(), MyInt(5) ];
402
+ ```
403
+
382
404
# Naming
383
405
384
406
The name "tear" comes from the image of tearing apart the the usable value from the early return.
@@ -390,7 +412,7 @@ macro_rules! tear {
390
412
( $e: expr ) => {
391
413
match $crate:: Return :: into_valret( $e) {
392
414
$crate:: ValRet :: Val ( v) => v,
393
- $crate:: ValRet :: Ret ( r) => return r ,
415
+ $crate:: ValRet :: Ret ( r) => return $crate :: From :: from ( r ) ,
394
416
}
395
417
} ;
396
418
// With a mapping function eg. `tear! { $e => |v| v }` or `tear! { $e => func }`
@@ -435,7 +457,7 @@ Early return a value: recursively computing the length of a slice.
435
457
# #[macro_use] extern crate tear;
436
458
fn len (v: &[i32]) -> usize {
437
459
// Base case
438
- tear_if! { v.is_empty(), 0 }
460
+ tear_if! { v.is_empty(), 0 as usize }
439
461
440
462
// Recursion
441
463
1 + len(&v[1..])
@@ -495,10 +517,10 @@ macro_rules! tear_if {
495
517
} ;
496
518
}
497
519
498
- /** `try!`-like error-handling macro
520
+ /** [ `try!`] -like error-handling macro
499
521
500
522
`terror!` is like `tear!`, but stronger and more righteous.
501
- It automatically converts the Bad value to the return type Bad value (Judge trait).
523
+ It automatically converts the Bad value to the return type Bad value ([` Judge`] trait).
502
524
503
525
# Description
504
526
@@ -516,6 +538,9 @@ let x = terror! { $e => $f };
516
538
Same as the previous form, but the bad `value` is first mapped through $f before returning.
517
539
In short, we return `from_bad($f(value))`.
518
540
541
+ Both forms make use of the [`convert::From`](`core::convert::From`) trait to convert the bad value,
542
+ making it fully compatible with `try!` and the `?` operator.
543
+
519
544
# Explanation using examples
520
545
521
546
The description is especially terse on purpose: it is really hard to explain what `terror!` does without using examples.
@@ -641,6 +666,46 @@ To do so, we extract the `ParseIntError`, and wrap it into our custom error with
641
666
That is the role of the function following the `=>` arrow: it converts the error type of
642
667
the left statement, into the function return error type.
643
668
669
+ ### Automatic conversion just like `?`
670
+
671
+ Since `terror!` mimics `?`, it also supports autoconversion using the `convert::From` trait.
672
+
673
+ ```rust
674
+ # use tear::prelude::*;
675
+ # use std::io;
676
+ # macro_rules! assert_match {
677
+ # ( $e:expr, $($p:pat)|+ ) => {
678
+ # match $e {
679
+ # $($p)|+ => (),
680
+ # ref e => panic!("assertion failed: `{:?}` does not match `{}`", e, stringify!($($p)|+)),
681
+ # }
682
+ # }
683
+ # }
684
+ # #[derive(Debug)]
685
+ enum CustomError {
686
+ IOError(io::Error),
687
+ OtherError,
688
+ }
689
+
690
+ impl std::convert::From<io::Error> for CustomError {
691
+ fn from(x :io::Error) -> Self {
692
+ Self::IOError(x)
693
+ }
694
+ }
695
+
696
+ # fn fail_with_io_error() -> io::Result<()> {
697
+ # Err(io::Error::new(io::ErrorKind::Other, "oh no!"))
698
+ # }
699
+ #
700
+ fn auto_convert() -> Result<bool, CustomError> {
701
+ terror! { fail_with_io_error() };
702
+ Ok(false)
703
+ }
704
+
705
+ assert_match![ auto_convert(), Err(CustomError::IOError(_)) ];
706
+ ```
707
+
708
+
644
709
# `terror!` vs. `?` when moving into closures
645
710
646
711
The only difference between `terror!` and `?` is that since `terror!` is a macro,
0 commit comments