create_type.rs
1 //! Bench various ways of constructing a value of each library's "dyn Error"-holding type, as 2 //! similarly as possible, like a user would use via their high-level. 3 4 use super::*; 5 6 module_group! { 7 name = "Create-Type"; 8 benches = empty_msg, lit_msg, fmt_msg, auto_return, chain 9 } 10 11 12 fn empty_msg(c: &mut Criterion) 13 { 14 bench_group! { (c) name = "Empty-Message"; } 15 16 fn anyhow() 17 { 18 // `anyhow!` has a disadvantage in that it boxes (moves to a new heap allocation) the 19 // message value as the error value. 20 let e: anyhow::Error = anyhow!(""); 21 bb(e); 22 } 23 24 fn snafu() 25 { 26 // This `format!("")` creates an empty `String` and that doesn't allocate. 27 #[allow(clippy::useless_format)] 28 let e: MyWhatever = snafu::FromString::without_source(format!("")); 29 bb(e); 30 } 31 } 32 33 34 fn lit_msg(c: &mut Criterion) 35 { 36 bench_group! { (c) name = "Literal-Message"; } 37 38 fn anyhow() 39 { 40 // `anyhow!` has an advantage in that it can avoid allocating a `String` for a literal 41 // message that doesn't need formatting. But it has a disadvantage in that it boxes 42 // (moves to a new heap allocation) the message value as the error value. 43 let e: anyhow::Error = anyhow!("blah"); 44 bb(e); 45 } 46 47 fn snafu() 48 { 49 // This `format!` does allocate a non-empty `String`. 50 #[allow(clippy::useless_format)] 51 let e: MyWhatever = snafu::FromString::without_source(format!("blah")); 52 bb(e); 53 } 54 } 55 56 57 fn fmt_msg(c: &mut Criterion) 58 { 59 bench_group_named! { (c) name = "Format-Message"; (group) log-scale = true; } 60 61 let powers = (0 ..= 9).step_by(9); 62 let powers_of_ten = powers.map(|p| 10_u32.checked_pow(p).unwrap()); 63 64 fn anyhow(i: &u32) 65 { 66 let e: anyhow::Error = anyhow!("i: {}", i); 67 bb(e); 68 } 69 70 fn snafu(i: &u32) 71 { 72 let e: MyWhatever = snafu::FromString::without_source(format!("i: {}", i)); 73 bb(e); 74 } 75 76 #[allow(clippy::unit_arg)] 77 for i in powers_of_ten { 78 group.bench_with_input(BenchmarkId::new("Anyhow", i), &i, |b, i| b.iter(|| anyhow(i))); 79 group.bench_with_input(BenchmarkId::new("Snafu", i), &i, |b, i| b.iter(|| snafu(i))); 80 } 81 } 82 83 84 fn auto_return(c: &mut Criterion) 85 { 86 bench_group! { (c) name = "Automatic-Return"; 87 routines = ["Anyhow" = || drop(bb(anyhow())), "Snafu" = || drop(bb(snafu()))]; 88 } 89 90 fn anyhow() -> Result<(), anyhow::Error> 91 { 92 anyhow::bail!("blah"); 93 } 94 95 fn snafu() -> Result<(), MyWhatever> 96 { 97 snafu::whatever!("blah"); 98 } 99 } 100 101 102 fn chain(c: &mut Criterion) 103 { 104 bench_group! { (c) name = "Chain"; } 105 106 #[derive(Debug)] 107 struct MyError(#[allow(dead_code)] i32); 108 impl_StdError! { MyError } 109 110 const E: Result<(), MyError> = Err(MyError(123)); 111 112 fn anyhow() 113 { 114 use anyhow::Context as _; 115 116 let e: Result<(), anyhow::Error> = E.context("blah"); 117 let _ = bb(e); 118 } 119 120 fn snafu() 121 { 122 use snafu::ResultExt as _; 123 124 let e: Result<(), MyWhatever> = E.whatever_context("blah"); 125 let _ = bb(e); 126 } 127 }