1 module logdefer.timer;
2 
3 
4 import std.typecons : RefCounted;
5 
6 import logdefer.time.duration : Nanos;
7 import logdefer.time.utils : toDuration;
8 
9 import unixtime : ClockType, UnixTimeHiRes;
10 
11 @safe
12 class Timer
13 {   
14     public:
15 
16         // This is what triggers the timer to stop when it goes out of scope
17         private struct Trigger
18         {
19             public:
20                 @disable this();
21 
22                 this(Timer timer)
23                 {
24                     timer_ = timer;
25                 }
26 
27                 ~this()
28                 {
29                   timer_.stop();
30                 }
31 
32             private:
33               Timer timer_;
34         }
35         
36         this(string timerName, const UnixTimeHiRes startTime)
37         {   
38             startTime_ = startTime;
39             timerName_ = timerName;
40         }
41 
42         // Starts timer and returns struct which when destroyed will
43         // stop timer
44         auto startTimer()
45         {
46             startOffset_ = toDuration!Nanos(startTime_, UnixTimeHiRes.now!(ClockType.MONOTONIC)());
47             return Trigger(this);
48         }
49 
50         @property
51         string name() const
52         {
53             return timerName_;
54         }
55 
56         @property
57         Nanos start() const
58         {
59             return startOffset_;
60         }
61 
62         @property
63         Nanos end() const
64         {
65             return endOffset_;
66         }
67 
68     private:
69         const UnixTimeHiRes startTime_;
70 
71         Nanos startOffset_;
72         Nanos endOffset_;
73 
74         Trigger* trigger_;
75 
76         immutable string timerName_;
77 
78         void stop()
79         {
80             endOffset_ = toDuration!Nanos(startTime_, UnixTimeHiRes.now!(ClockType.MONOTONIC)());
81         }
82 }
83 
84 version (unittest)
85 {
86     import core.thread;
87     import std.stdio;
88 
89     import logdefer.time.duration : Millis;
90 }
91 
92 unittest
93 {
94     writeln("[UnitTest Timer] - aprox duration");
95 
96     auto now = UnixTimeHiRes.now!(ClockType.MONOTONIC)();
97     auto timer1 = new Timer("test1", now);
98     auto timer2 = new Timer("test2", now);
99 
100     {
101         auto scope1 = timer1.startTimer();
102         {
103             auto scope2 = timer2.startTimer();
104             Thread.sleep(dur!"msecs"(250));
105         }
106         Thread.sleep(dur!"msecs"(250));
107     }
108 
109     assert(timer1.name == "test1");
110     assert(timer1.start > 0);
111     assert(timer1.end > Millis(450));
112     assert(timer1.end < Millis(600));
113 
114     assert(timer2.name == "test2");
115     assert(timer2.start > 0);
116     assert(timer2.end > Millis(200));
117     assert(timer2.end < Millis(400));
118 }