/ src / create_type.rs
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  }