-
-
Notifications
You must be signed in to change notification settings - Fork 607
/
lib.rs
147 lines (134 loc) · 4.59 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Copyright 2018 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).
#![deny(warnings)]
// Enable all clippy lints except for many of the pedantic ones. It's a shame this needs to be copied and pasted across crates, but there doesn't appear to be a way to include inner attributes from a common source.
#![deny(
clippy::all,
clippy::default_trait_access,
clippy::expl_impl_clone_on_copy,
clippy::if_not_else,
clippy::needless_continue,
clippy::unseparated_literal_suffix,
// TODO: Falsely triggers for async/await:
// see https://github.com/rust-lang/rust-clippy/issues/5360
// clippy::used_underscore_binding
)]
// It is often more clear to show that nothing is being moved.
#![allow(clippy::match_ref_pats)]
// Subjective style.
#![allow(
clippy::len_without_is_empty,
clippy::redundant_field_names,
clippy::too_many_arguments
)]
// Default isn't as big a deal as people seem to think it is.
#![allow(clippy::new_without_default, clippy::new_ret_no_self)]
// Arc<Mutex> can be more clear than needing to grok Orderings:
#![allow(clippy::mutex_atomic)]
use serde_derive::Serialize;
/// A concrete data representation of a duration.
/// Unlike std::time::Duration, it doesn't hide how the time is stored as the purpose of this
/// `struct` is to expose it.
///
/// This type can be serialized with serde.
///
/// This type can be converted from and into a `std::time::Duration` as this should be the goto
/// data representation for a `Duration` when one isn't concerned about serialization.
///
/// It can be used to represent a timestamp (as a duration since the unix epoch) or simply a
/// duration between two arbitrary timestamps.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
pub struct Duration {
/// How many seconds did this `Duration` last?
pub secs: u64,
/// How many sub-second nanoseconds did this `Duration` last?
pub nanos: u32,
}
impl Duration {
/// Construct a new duration with `secs` seconds and `nanos` nanoseconds
pub fn new(secs: u64, nanos: u32) -> Self {
Self { secs, nanos }
}
}
impl From<std::time::Duration> for Duration {
fn from(duration: std::time::Duration) -> Self {
Self {
secs: duration.as_secs(),
nanos: duration.subsec_nanos(),
}
}
}
impl Into<std::time::Duration> for Duration {
fn into(self) -> std::time::Duration {
std::time::Duration::new(self.secs, self.nanos)
}
}
/// A timespan
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
pub struct TimeSpan {
/// Duration since the UNIX_EPOCH
pub start: Duration,
/// Duration since `start`
pub duration: Duration,
}
impl TimeSpan {
fn since_epoch(time: &std::time::SystemTime) -> std::time::Duration {
time
.duration_since(std::time::UNIX_EPOCH)
.expect("Surely you're not before the unix epoch?")
}
/// Construct a TimeSpan that started at `start` and ends now.
pub fn since(start: &std::time::SystemTime) -> TimeSpan {
let start = Self::since_epoch(start);
let duration = Self::since_epoch(&std::time::SystemTime::now()) - start;
TimeSpan {
start: start.into(),
duration: duration.into(),
}
}
/// Construct a TimeSpan that started at `start` and ends at `end`.
pub fn from_start_and_end_systemtime(
start: &std::time::SystemTime,
end: &std::time::SystemTime,
) -> TimeSpan {
let start = Self::since_epoch(start);
let end = Self::since_epoch(end);
let duration = match end.checked_sub(start) {
Some(d) => d,
None => {
log::warn!("Invalid TimeSpan - start: {:?}, end: {:?}", start, end);
std::time::Duration::new(0, 0)
}
};
TimeSpan {
start: start.into(),
duration: duration.into(),
}
}
fn std_duration_from_protobuf_timestamp(
t: &protobuf::well_known_types::Timestamp,
) -> std::time::Duration {
std::time::Duration::new(t.seconds as u64, t.nanos as u32)
}
/// Construct a `TimeSpan` given a start and an end `Timestamp` from protobuf
pub fn from_start_and_end(
start: &protobuf::well_known_types::Timestamp,
end: &protobuf::well_known_types::Timestamp,
time_span_description: &str,
) -> Result<Self, String> {
let start = Self::std_duration_from_protobuf_timestamp(start);
let end = Self::std_duration_from_protobuf_timestamp(end);
let time_span = end.checked_sub(start).map(|duration| TimeSpan {
start: start.into(),
duration: duration.into(),
});
time_span.ok_or_else(|| {
format!(
"Got negative {} time: {:?} - {:?}",
time_span_description, end, start
)
})
}
}
#[cfg(test)]
mod tests;