1#[macro_use]
2extern crate log;
3
4use std::time::{Duration, Instant};
5
6#[derive(Debug, PartialEq)]
7pub enum Precision {
8 Millisecond,
9 Microsecond,
10 Nanosecond,
11}
12
13#[derive(Debug, PartialEq)]
14pub enum Output {
15 StdOut,
16 Log(log::Level),
17}
18
19#[derive(Debug, PartialEq)]
20pub enum Report {
21 Always,
22 Never,
23 Gt(Duration), Ge(Duration), Lt(Duration), Le(Duration), }
28
29#[derive(Debug)]
30pub struct Tag {
31 pub since_begin: Duration,
32 pub since_prev: Duration,
33 pub tag: String,
34}
35
36#[derive(Debug)]
37pub struct HowMuch {
38 total: Instant,
39 diff: Instant,
40 output: Output,
41 precision: Precision,
42 report: Report,
43 tags: Vec<Tag>,
44}
45
46impl HowMuch {
47 pub fn new() -> HowMuch {
48 let mut hm = HowMuch {
49 total: Instant::now(),
50 diff: Instant::now(),
51 output: Output::StdOut,
52 precision: Precision::Microsecond,
53 report: Report::Always,
54 tags: Vec::new(),
55 };
56 hm.tag("BEGIN");
57 hm
58 }
59
60 pub fn tag(&mut self, tag: &str) {
61 let total = self.total.elapsed();
62 let diff = self.diff.elapsed();
63 self.diff = Instant::now();
64
65 self.tags.push(Tag{
66 since_begin: total,
67 since_prev: diff,
68 tag: tag.to_owned()
69 })
70 }
71
72 pub fn set_output(&mut self, output: Output) {
73 self.output = output;
74 }
75
76 pub fn set_precision(&mut self, precision: Precision) {
77 self.precision = precision;
78 }
79
80 pub fn set_report(&mut self, report: Report) {
81 self.report = report;
82 }
83}
84
85impl Drop for HowMuch {
86 fn drop(&mut self) {
87 self.tag("END");
88
89 let to_precision = |v| {
90 match self.precision {
91 Precision::Millisecond => format!("{:03}", v / 1_000_000),
92 Precision::Microsecond => format!("{:06}", v / 1_000),
93 Precision::Nanosecond => format!("{:09}", v),
94 }
95 };
96
97 let report = || {
98 for tag in &self.tags {
101 let record = format!("{:>4}.{} | {:>4}.{} | {}",
102 tag.since_begin.as_secs(),
103 to_precision(tag.since_begin.subsec_nanos()),
104 tag.since_prev.as_secs(),
105 to_precision(tag.since_prev.subsec_nanos()),
106 tag.tag);
107
108 match self.output {
109 Output::StdOut => println!("{}", &record),
110 Output::Log(ref lvl) => log!(lvl.clone(), "{}", &record),
111 }
112 }
113 };
114
115 let mut total = self.total.elapsed();
116
117 if let Some(tag) = self.tags.last() {
118 total = tag.since_begin.clone();
119 }
120
121 match self.report {
122 Report::Always => report(),
123 Report::Gt(ref v) if &total > v => report(),
124 Report::Ge(ref v) if &total >= v => report(),
125 Report::Lt(ref v) if &total < v => report(),
126 Report::Le(ref v) if &total <= v => report(),
127 _ => {}
128 }
129 }
130}