howmuch/
lib.rs

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), // total time >  durtaion
24    Ge(Duration), // total time >= durtaion
25    Lt(Duration), // total time <  durtaion
26    Le(Duration), // total time <= durtaion
27}
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            // FIXME: ugly formating
99
100            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}