- Inside the bin folder, create a new file called errors.rs.
- Add the following code and run it with cargo run --bin errors:
1 extern crate futures; 2 3 use futures::prelude::*; 4 use futures::executor::block_on; 5 use futures::stream; 6 use futures::task::Context; 7 use futures::future::{FutureResult, err};
- After that, let's add our structures and implementations:
9 struct MyFuture {} 10 impl MyFuture { 11 fn new() -> Self { 12 MyFuture {} 13 } 14 } 15 16 fn map_error_example() -> FutureResult<(), &'static str> { 17 err::<(), &'static str>("map_error has occurred") 18 } 19 20 fn err_into_example() -> FutureResult<(), u8> { 21 err::<(), u8>(1) 22 } 23 24 fn or_else_example() -> FutureResult<(), &'static str> { 25 err::<(), &'static str>("or_else error has occurred") 26 } 27 28 impl Future for MyFuture { 29 type Item = (); 30 type Error = &'static str; 31 32 fn poll(&mut self, _cx: &mut Context) -> Poll<Self::Item, Self::Error> { 33 Err("A generic error goes here") 34 } 35 } 36 37 struct FuturePanic {} 38 39 impl Future for FuturePanic { 40 type Item = (); 41 type Error = (); 42 43 fn poll(&mut self, _cx: &mut Context) -> Poll<Self::Item,
Self::Error> { 44 panic!("It seems like there was a major issue with
catch_unwind_example") 45 } 46 }
- After that, let's add our generic error handling functions/examples:
48 fn using_recover() { 49 let f = MyFuture::new(); 50 51 let f_recover = f.recover::<Never, _>(|err| { 52 println!("An error has occurred: {}", err); 53 () 54 }); 55 56 block_on(f_recover).unwrap(); 57 } 58 59 fn map_error() { 60 let map_fn = |err| format!("map_error_example: {}", err); 61 62 if let Err(e) = block_on(map_error_example().map_err(map_fn))
{ 63 println!("block_on error: {}", e) 64 } 65 } 66 67 fn err_into() { 68 if let Err(e) = block_on(err_into_example().err_into::()) { 69 println!("block_on error code: {:?}", e) 70 } 71 } 72 73 fn or_else() { 74 if let Err(e) = block_on(or_else_example() 75 .or_else(|_| Err("changed or_else's error message"))) { 76 println!("block_on error: {}", e) 77 } 78 }
- And now for our panic functions:
80 fn catch_unwind() { 81 let f = FuturePanic {}; 82 83 if let Err(e) = block_on(f.catch_unwind()) { 84 let err = e.downcast::<&'static str>().unwrap(); 85 println!("block_on error: {:?}", err) 86 } 87 } 88 89 fn stream_panics() { 90 let stream_ok = stream::iter_ok::<_, bool>(vec![Some(1),
Some(7), None, Some(20)]); 91 // We panic on "None" values in order to simulate a stream
that panics 92 let stream_map = stream_ok.map(|o| o.unwrap()); 93 94 // We can use catch_unwind() for catching panics 95 let stream = stream_map.catch_unwind().then(|r| Ok::<_, ()>
(r)); 96 let stream_results: Vec<_> =
block_on(stream.collect()).unwrap(); 97 98 // Here we can use the partition() function to separate the Ok
and Err values 99 let (oks, errs): (Vec<_>, Vec<_>) =
stream_results.into_iter().partition(Result::is_ok); 100 let ok_values: Vec<_> =
oks.into_iter().map(Result::unwrap).collect(); 101 let err_values: Vec<_> =
errs.into_iter().map(Result::unwrap_err).collect(); 102 103 println!("Panic's Ok values: {:?}", ok_values); 104 println!("Panic's Err values: {:?}", err_values); 105 }
- And finally, our main function:
107 fn main() { 108 println!("using_recover():"); 109 using_recover(); 110 111 println!(" map_error():"); 112 map_error(); 113 114 println!(" err_into():"); 115 err_into(); 116 117 println!(" or_else():"); 118 or_else(); 119 120 println!(" catch_unwind():"); 121 catch_unwind(); 122 123 println!(" stream_panics():"); 124 stream_panics(); 125 }