• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geo-engine / geoengine / 4056270646

pending completion
4056270646

push

github

GitHub
Merge #706

108 of 108 new or added lines in 5 files covered. (100.0%)

87598 of 99672 relevant lines covered (87.89%)

77046.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.35
/datatypes/src/primitives/time_instance.rs
1
use super::datetime::DateTimeError;
2
use super::{DateTime, Duration};
3
use crate::primitives::error;
4
use crate::util::Result;
5
#[cfg(feature = "postgres")]
6
use postgres_types::private::BytesMut;
7
#[cfg(feature = "postgres")]
8
use postgres_types::{FromSql, IsNull, ToSql, Type};
9
use serde::{Deserialize, Serialize};
10
use snafu::ensure;
11
#[cfg(feature = "postgres")]
12
use snafu::Error;
13
use std::ops::AddAssign;
14
use std::{
15
    convert::TryFrom,
16
    fmt::Formatter,
17
    ops::{Add, Sub},
18
    str::FromStr,
19
};
20

21
#[derive(Clone, Copy, Serialize, PartialEq, Eq, PartialOrd, Ord, Debug)]
104,812✔
22
#[repr(C)]
23
pub struct TimeInstance(i64);
24

25
impl TimeInstance {
26
    pub fn from_millis(millis: i64) -> Result<Self> {
1,982✔
27
        ensure!(
1,982✔
28
            Self::MIN.inner() <= millis && millis <= Self::MAX.inner(),
1,982✔
29
            error::InvalidTimeInstance {
×
30
                min: Self::MIN,
×
31
                max: Self::MAX,
×
32
                is: millis
×
33
            }
×
34
        );
35

36
        Ok(TimeInstance(millis))
1,982✔
37
    }
1,982✔
38

39
    pub const fn from_millis_unchecked(millis: i64) -> Self {
2,278✔
40
        TimeInstance(millis)
2,278✔
41
    }
2,278✔
42

43
    pub fn as_datetime_string(self) -> String {
92✔
44
        let instance = self.clamp(TimeInstance::MIN, TimeInstance::MAX);
92✔
45

92✔
46
        instance
92✔
47
            .as_date_time()
92✔
48
            .expect("TimeInstance is not valid")
92✔
49
            .to_datetime_string()
92✔
50
    }
92✔
51

52
    pub fn as_datetime_string_with_millis(self) -> String {
159✔
53
        let instance = self.clamp(TimeInstance::MIN, TimeInstance::MAX);
159✔
54

159✔
55
        instance
159✔
56
            .as_date_time()
159✔
57
            .expect("TimeInstance is not valid")
159✔
58
            .to_datetime_string_with_millis()
159✔
59
    }
159✔
60

61
    pub const fn inner(self) -> i64 {
94,849✔
62
        self.0
94,849✔
63
    }
94,849✔
64

65
    pub fn now() -> Self {
46✔
66
        Self::from(DateTime::now())
46✔
67
    }
46✔
68

69
    /// Converts a `TimeInstance` to a `DateTime`.
70
    /// If this would overflow the range of `DateTime`, the result is `None`.
71
    pub fn as_date_time(self) -> Option<DateTime> {
1,921✔
72
        DateTime::try_from(self).ok()
1,921✔
73
    }
1,921✔
74

75
    /// Returns true if this instance equals `Self::MIN`, i.e., represents the start of time.
76
    #[inline]
77
    pub fn is_min(self) -> bool {
1,033✔
78
        self == Self::MIN
1,033✔
79
    }
1,033✔
80

81
    /// Returns true if this instance equals `Self::MAX`, i.e., represents the end of time.
82
    #[inline]
83
    pub fn is_max(self) -> bool {
791✔
84
        self == Self::MAX
791✔
85
    }
791✔
86

87
    pub const MIN: Self = TimeInstance::from_millis_unchecked(-8_334_632_851_200_001 + 1);
88
    pub const MAX: Self = TimeInstance::from_millis_unchecked(8_210_298_412_800_000 - 1);
89

90
    pub const EPOCH_START: Self = TimeInstance::from_millis_unchecked(0);
91
}
92

93
impl std::fmt::Display for TimeInstance {
94
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
2✔
95
        let instance = self.clamp(&TimeInstance::MIN, &TimeInstance::MAX);
2✔
96
        let datetime = instance
2✔
97
            .as_date_time()
2✔
98
            .expect("time instance was clamped into valid range");
2✔
99
        write!(f, "{datetime}")
2✔
100
    }
2✔
101
}
102

103
impl TryFrom<i64> for TimeInstance {
104
    type Error = crate::error::Error;
105

106
    fn try_from(milliseconds: i64) -> Result<Self> {
1,864✔
107
        TimeInstance::from_millis(milliseconds)
1,864✔
108
    }
1,864✔
109
}
110

111
impl From<TimeInstance> for i64 {
112
    fn from(time_instance: TimeInstance) -> Self {
81,270✔
113
        time_instance.inner()
81,270✔
114
    }
81,270✔
115
}
116

117
#[cfg(feature = "postgres")]
118
impl ToSql for TimeInstance {
119
    fn to_sql(&self, ty: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>>
56✔
120
    where
56✔
121
        Self: Sized,
56✔
122
    {
56✔
123
        self.as_date_time().to_sql(ty, out)
56✔
124
    }
56✔
125

126
    fn accepts(ty: &Type) -> bool
56✔
127
    where
56✔
128
        Self: Sized,
56✔
129
    {
56✔
130
        <DateTime as ToSql>::accepts(ty)
56✔
131
    }
56✔
132

133
    fn to_sql_checked(
×
134
        &self,
×
135
        ty: &Type,
×
136
        out: &mut BytesMut,
×
137
    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
×
138
        self.as_date_time().to_sql_checked(ty, out)
×
139
    }
×
140
}
141

142
#[cfg(feature = "postgres")]
143
impl<'a> FromSql<'a> for TimeInstance {
144
    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
20✔
145
        DateTime::from_sql(ty, raw).map(Into::into)
20✔
146
    }
20✔
147

148
    fn accepts(ty: &Type) -> bool {
34✔
149
        <DateTime as FromSql>::accepts(ty)
34✔
150
    }
34✔
151
}
152

153
impl Add<i64> for TimeInstance {
154
    type Output = Self;
155

156
    fn add(self, rhs: i64) -> Self::Output {
33✔
157
        if self.is_min() || self.is_max() {
33✔
158
            // begin and end of time are special values, we don't want to do arithmetics on them
159
            return self;
3✔
160
        }
30✔
161
        TimeInstance::from_millis_unchecked(self.0 + rhs)
30✔
162
    }
33✔
163
}
164

165
impl AddAssign<i64> for TimeInstance {
166
    fn add_assign(&mut self, rhs: i64) {
4✔
167
        *self = *self + rhs;
4✔
168
    }
4✔
169
}
170

171
impl Sub<i64> for TimeInstance {
172
    type Output = Self;
173

174
    fn sub(self, rhs: i64) -> Self::Output {
5✔
175
        if self.is_min() || self.is_max() {
5✔
176
            // begin and end of time are special values, we don't want to do arithmetics on them
177
            return self;
3✔
178
        }
2✔
179
        TimeInstance::from_millis_unchecked(self.0 - rhs)
2✔
180
    }
5✔
181
}
182

183
impl Add<Duration> for TimeInstance {
184
    type Output = Self;
185

186
    fn add(self, rhs: Duration) -> Self::Output {
3✔
187
        if self.is_min() || self.is_max() {
3✔
188
            // begin and end of time are special values, we don't want to do arithmetics on them
189
            return self;
×
190
        }
3✔
191
        TimeInstance::from_millis_unchecked(self.0 + rhs.num_milliseconds())
3✔
192
    }
3✔
193
}
194

195
impl Sub<Duration> for TimeInstance {
196
    type Output = Self;
197

198
    fn sub(self, rhs: Duration) -> Self::Output {
×
199
        if self.is_min() || self.is_max() {
×
200
            // begin and end of time are special values, we don't want to do arithmetics on them
201
            return self;
×
202
        }
×
203
        TimeInstance::from_millis_unchecked(self.0 - rhs.num_milliseconds())
×
204
    }
×
205
}
206

207
impl Sub<TimeInstance> for TimeInstance {
208
    type Output = Duration;
209

210
    fn sub(self, rhs: Self) -> Self::Output {
283✔
211
        Duration::milliseconds(self.0 - rhs.0)
283✔
212
    }
283✔
213
}
214

215
impl FromStr for TimeInstance {
216
    type Err = DateTimeError;
217

218
    fn from_str(s: &str) -> Result<Self, Self::Err> {
304✔
219
        let date_time = DateTime::from_str(s)?;
304✔
220
        Ok(date_time.into())
304✔
221
    }
304✔
222
}
223

224
impl<'de> Deserialize<'de> for TimeInstance {
225
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
46✔
226
    where
46✔
227
        D: serde::Deserializer<'de>,
46✔
228
    {
46✔
229
        struct IsoStringOrUnixTimestamp;
46✔
230

46✔
231
        impl<'de> serde::de::Visitor<'de> for IsoStringOrUnixTimestamp {
46✔
232
            type Value = TimeInstance;
46✔
233

46✔
234
            fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
46✔
235
                formatter.write_str("RFC 3339 timestamp string or Unix timestamp integer")
×
236
            }
×
237

46✔
238
            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
46✔
239
            where
6✔
240
                E: serde::de::Error,
6✔
241
            {
6✔
242
                TimeInstance::from_str(value).map_err(E::custom)
6✔
243
            }
6✔
244

46✔
245
            fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
46✔
246
            where
40✔
247
                E: serde::de::Error,
40✔
248
            {
40✔
249
                TimeInstance::from_millis(v).map_err(E::custom)
40✔
250
            }
40✔
251

46✔
252
            fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
46✔
253
            where
34✔
254
                E: serde::de::Error,
34✔
255
            {
34✔
256
                Self::visit_i64(self, v as i64)
34✔
257
            }
34✔
258
        }
46✔
259

46✔
260
        deserializer.deserialize_any(IsoStringOrUnixTimestamp)
46✔
261
    }
46✔
262
}
263

264
#[cfg(test)]
265
mod tests {
266
    use super::*;
267

268
    #[test]
1✔
269
    fn bounds_wrt_chrono() {
1✔
270
        assert_eq!(TimeInstance::MIN, TimeInstance::from(DateTime::MIN));
1✔
271
        assert_eq!(TimeInstance::MAX, TimeInstance::from(DateTime::MAX));
1✔
272
    }
1✔
273

274
    #[test]
1✔
275
    fn time_limits() {
1✔
276
        assert_eq!(TimeInstance::MIN + 1, TimeInstance::MIN);
1✔
277
        assert_eq!(TimeInstance::MIN - 1, TimeInstance::MIN);
1✔
278
        assert_eq!(TimeInstance::MAX + 1, TimeInstance::MAX);
1✔
279
        assert_eq!(TimeInstance::MAX - 1, TimeInstance::MAX);
1✔
280
    }
1✔
281
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc