1
use std::borrow::Cow;
2
use std::fmt::Debug;
3
use std::time::{Duration, SystemTime, UNIX_EPOCH};
4

            
5
use ordered_varint::Variable;
6
use serde::{Deserialize, Serialize};
7

            
8
use crate::key::time::limited::{BonsaiEpoch, UnixEpoch};
9
use crate::key::{ByteSource, CompositeKind, Key, KeyEncoding, KeyKind, KeyVisitor};
10

            
11
impl<'k> Key<'k> for Duration {
12
    const CAN_OWN_BYTES: bool = false;
13

            
14
4
    fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
15
4
        let merged = u128::decode_variable(bytes.as_ref()).map_err(|_| TimeError::InvalidValue)?;
16
4
        let seconds = u64::try_from(merged >> 30).map_err(|_| TimeError::DeltaNotRepresentable)?;
17
4
        let nanos = u32::try_from(merged & (2_u128.pow(30) - 1)).unwrap();
18
4
        Ok(Self::new(seconds, nanos))
19
4
    }
20
}
21

            
22
impl KeyEncoding<Self> for Duration {
23
    type Error = TimeError;
24

            
25
    const LENGTH: Option<usize> = None;
26

            
27
    fn describe<Visitor>(visitor: &mut Visitor)
28
    where
29
        Visitor: KeyVisitor,
30
    {
31
        visitor.visit_composite(
32
            CompositeKind::Struct(Cow::Borrowed("std::time::Duration")),
33
            1,
34
        );
35
        visitor.visit_type(KeyKind::Unsigned);
36
    }
37

            
38
4
    fn as_ord_bytes(&self) -> Result<Cow<'_, [u8]>, Self::Error> {
39
4
        let merged = u128::from(self.as_secs()) << 30 | u128::from(self.subsec_nanos());
40
4
        // It's safe to unwrap here, because under the hood ordered-varint can
41
4
        // only raise an error if the top bits are set. Since we only ever add
42
4
        // 94 bits, the top bits will not have any data set.
43
4
        Ok(Cow::Owned(merged.to_variable_vec().unwrap()))
44
4
    }
45
}
46

            
47
1
#[test]
48
1
fn duration_key_tests() {
49
1
    assert_eq!(
50
1
        Duration::ZERO,
51
1
        Duration::from_ord_bytes(ByteSource::Borrowed(
52
1
            &Duration::ZERO.as_ord_bytes().unwrap()
53
1
        ))
54
1
        .unwrap()
55
1
    );
56
1
    assert_eq!(
57
1
        Duration::MAX,
58
1
        Duration::from_ord_bytes(ByteSource::Borrowed(&Duration::MAX.as_ord_bytes().unwrap()))
59
1
            .unwrap()
60
1
    );
61
1
}
62

            
63
impl<'k> Key<'k> for SystemTime {
64
    const CAN_OWN_BYTES: bool = false;
65

            
66
2
    fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
67
2
        let since_epoch = Duration::from_ord_bytes(bytes)?;
68
2
        UNIX_EPOCH
69
2
            .checked_add(since_epoch)
70
2
            .ok_or(TimeError::DeltaNotRepresentable)
71
2
    }
72
}
73

            
74
impl KeyEncoding<Self> for SystemTime {
75
    type Error = TimeError;
76

            
77
    const LENGTH: Option<usize> = None;
78

            
79
    fn describe<Visitor>(visitor: &mut Visitor)
80
    where
81
        Visitor: KeyVisitor,
82
    {
83
        visitor.visit_composite(
84
            CompositeKind::Struct(Cow::Borrowed("std::time::SystemTime")),
85
            1,
86
        );
87
        visitor.visit_type(KeyKind::Unsigned);
88
    }
89

            
90
2
    fn as_ord_bytes(&self) -> Result<Cow<'_, [u8]>, Self::Error> {
91
2
        let since_epoch = self.duration_since(UNIX_EPOCH).unwrap();
92
2
        match since_epoch.as_ord_bytes()? {
93
2
            Cow::Owned(bytes) => Ok(Cow::Owned(bytes)),
94
            Cow::Borrowed(_) => unreachable!(),
95
        }
96
2
    }
97
}
98

            
99
1
#[test]
100
1
fn system_time_tests() {
101
1
    assert_eq!(
102
1
        UNIX_EPOCH,
103
1
        SystemTime::from_ord_bytes(ByteSource::Borrowed(&UNIX_EPOCH.as_ord_bytes().unwrap()))
104
1
            .unwrap()
105
1
    );
106
1
    let now = SystemTime::now();
107
1
    assert_eq!(
108
1
        now,
109
1
        SystemTime::from_ord_bytes(ByteSource::Borrowed(&now.as_ord_bytes().unwrap())).unwrap()
110
1
    );
111
1
}
112

            
113
/// An error that indicates that the stored timestamp is unable to be converted
114
/// to the destination type without losing data.
115
#[derive(thiserror::Error, Debug)]
116
#[error("the stored timestamp is outside the allowed range")]
117
pub struct DeltaNotRepresentable;
118

            
119
/// Errors that can arise from parsing times serialized with [`Key`].
120
#[derive(thiserror::Error, Debug, Clone, Serialize, Deserialize)]
121
pub enum TimeError {
122
    /// An error that indicates that the stored timestamp is unable to be converted
123
    /// to the destination type without losing data.
124
    #[error("the stored timestamp is outside the allowed range")]
125
    DeltaNotRepresentable,
126
    /// The value stored was not encoded correctly.
127
    #[error("invalid value")]
128
    InvalidValue,
129
}
130

            
131
impl From<DeltaNotRepresentable> for TimeError {
132
    fn from(_: DeltaNotRepresentable) -> Self {
133
        Self::DeltaNotRepresentable
134
    }
135
}
136

            
137
impl From<std::io::Error> for TimeError {
138
    fn from(_: std::io::Error) -> Self {
139
        Self::InvalidValue
140
    }
141
}
142

            
143
/// Types for storing limited-precision Durations.
144
pub mod limited {
145
    use std::borrow::Cow;
146
    use std::fmt::{self, Debug, Display, Write};
147
    use std::hash::Hash;
148
    use std::iter;
149
    use std::marker::PhantomData;
150
    use std::str::FromStr;
151
    use std::time::{Duration, SystemTime, UNIX_EPOCH};
152

            
153
    use derive_where::derive_where;
154
    use ordered_varint::Variable;
155
    use serde::{Deserialize, Serialize};
156

            
157
    use crate::key::time::TimeError;
158
    use crate::key::{ByteSource, CompositeKind, Key, KeyEncoding, KeyVisitor};
159

            
160
    /// A [`Duration`] of time stored with a limited `Resolution`. This type may be
161
    /// preferred to [`std::time::Duration`] because `Duration` takes a full 12
162
    /// bytes to achieve its nanosecond resolution.
163
    ///
164
    /// Converting from [`Duration`] truncates the duration and performs no rounding.
165
    ///
166
    /// The `Resolution` type controls the storage size. The resolutions
167
    /// provided by BonsaiDb:
168
    ///
169
    /// - [`Weeks`]
170
    /// - [`Days`]
171
    /// - [`Hours`]
172
    /// - [`Minutes`]
173
    /// - [`Seconds`]
174
    /// - [`Milliseconds`]
175
    /// - [`Microseconds`]
176
    /// - [`Nanoseconds`]
177
    ///
178
    /// Other resolutions can be used by implementing [`TimeResolution`].
179
210
    #[derive_where(Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
180
    pub struct LimitedResolutionDuration<Resolution: TimeResolution> {
181
        representation: Resolution::Representation,
182
        _resolution: PhantomData<Resolution>,
183
    }
184

            
185
    /// A resolution of a time measurement.
186
    pub trait TimeResolution: Debug + Send + Sync {
187
        /// The in-memory and serialized representation for this resolution.
188
        type Representation: Variable
189
            + Serialize
190
            + for<'de> Deserialize<'de>
191
            + for<'k> Key<'k>
192
            + Display
193
            + Hash
194
            + Eq
195
            + PartialEq
196
            + Ord
197
            + PartialOrd
198
            + Clone
199
            + Copy
200
            + Send
201
            + Sync
202
            + Debug
203
            + Default;
204

            
205
        /// The label used when formatting times with this resolution.
206
        const FORMAT_SUFFIX: &'static str;
207

            
208
        /// Converts a [`Self::Representation`] to [`Duration`].
209
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError>;
210

            
211
        /// Converts a [`Duration`] to [`Self::Representation`].
212
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError>;
213
    }
214

            
215
    /// A [`Duration`] that can be either negative or positive.
216
    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
217
    pub enum SignedDuration {
218
        /// A duration representing a positive measurement of time.
219
        Positive(Duration),
220
        /// A duration representing a negative measurement of time.
221
        Negative(Duration),
222
    }
223

            
224
    impl SignedDuration {
225
        /// Adds the two durations, honoring the signs, and returns the result
226
        /// if the duration is representable.
227
        #[must_use]
228
        pub fn checked_add(self, other: Self) -> Option<Self> {
229
9
            match (self, other) {
230
6
                (SignedDuration::Positive(a), SignedDuration::Positive(b)) => {
231
6
                    a.checked_add(b).map(SignedDuration::Positive)
232
                }
233
1
                (SignedDuration::Negative(a), SignedDuration::Negative(b)) => {
234
1
                    a.checked_add(b).map(SignedDuration::Negative)
235
                }
236
1
                (SignedDuration::Positive(a), SignedDuration::Negative(b)) => {
237
1
                    if let Some(result) = a.checked_sub(b) {
238
                        Some(SignedDuration::Positive(result))
239
                    } else {
240
1
                        Some(SignedDuration::Negative(b - a))
241
                    }
242
                }
243
1
                (SignedDuration::Negative(a), SignedDuration::Positive(b)) => {
244
1
                    if let Some(result) = a.checked_sub(b) {
245
1
                        Some(SignedDuration::Negative(result))
246
                    } else {
247
                        Some(SignedDuration::Positive(b - a))
248
                    }
249
                }
250
            }
251
9
        }
252
    }
253

            
254
    impl<Resolution> LimitedResolutionDuration<Resolution>
255
    where
256
        Resolution: TimeResolution,
257
    {
258
        /// Returns a new instance with the `representation` provided, which
259
        /// conceptually is a unit of `Resolution`.
260
22830
        pub const fn new(representation: Resolution::Representation) -> Self {
261
22830
            Self {
262
22830
                representation,
263
22830
                _resolution: PhantomData,
264
22830
            }
265
22830
        }
266

            
267
        /// Returns the internal representation of this duration.
268
6240
        pub const fn representation(&self) -> Resolution::Representation {
269
6240
            self.representation
270
6240
        }
271
    }
272

            
273
    impl<Resolution: TimeResolution> Debug for LimitedResolutionDuration<Resolution> {
274
14
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275
14
            write!(f, "{:?}{}", self.representation, Resolution::FORMAT_SUFFIX)
276
14
        }
277
    }
278

            
279
    impl<Resolution: TimeResolution> Display for LimitedResolutionDuration<Resolution> {
280
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
281
            write!(f, "{}{}", self.representation, Resolution::FORMAT_SUFFIX)
282
        }
283
    }
284

            
285
    impl iter::Sum<SignedDuration> for Option<SignedDuration> {
286
        fn sum<I: Iterator<Item = SignedDuration>>(mut iter: I) -> Self {
287
            let first = iter.next();
288
            iter.fold(first, |sum, duration| {
289
                sum.and_then(|sum| sum.checked_add(duration))
290
            })
291
        }
292
    }
293

            
294
    impl iter::Sum<Self> for SignedDuration {
295
        fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
296
            iter.sum::<Option<Self>>().expect("operation overflowed")
297
        }
298
    }
299

            
300
    impl<'k, Resolution> Key<'k> for LimitedResolutionDuration<Resolution>
301
    where
302
        Resolution: TimeResolution,
303
    {
304
        const CAN_OWN_BYTES: bool = false;
305

            
306
14
        fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
307
14
            let representation =
308
14
                <Resolution::Representation as Variable>::decode_variable(bytes.as_ref())
309
14
                    .map_err(|_| TimeError::InvalidValue)?;
310

            
311
14
            Ok(Self {
312
14
                representation,
313
14
                _resolution: PhantomData,
314
14
            })
315
14
        }
316
    }
317

            
318
    impl<Resolution> KeyEncoding<Self> for LimitedResolutionDuration<Resolution>
319
    where
320
        Resolution: TimeResolution,
321
    {
322
        type Error = TimeError;
323

            
324
        const LENGTH: Option<usize> = None;
325

            
326
        fn describe<Visitor>(visitor: &mut Visitor)
327
        where
328
            Visitor: KeyVisitor,
329
        {
330
            visitor.visit_composite(
331
                CompositeKind::Struct(Cow::Borrowed(
332
                    "bonsaidb::core::key::time::LimitedResolutionDuration",
333
                )),
334
                1,
335
            );
336
            <Resolution::Representation as KeyEncoding>::describe(visitor);
337
        }
338

            
339
14
        fn as_ord_bytes(&self) -> Result<Cow<'_, [u8]>, Self::Error> {
340
14
            self.representation
341
14
                .to_variable_vec()
342
14
                .map(Cow::Owned)
343
14
                .map_err(|_| TimeError::InvalidValue)
344
14
        }
345
    }
346

            
347
    impl<Resolution> Default for LimitedResolutionDuration<Resolution>
348
    where
349
        Resolution: TimeResolution,
350
    {
351
        fn default() -> Self {
352
            Self {
353
                representation: <Resolution::Representation as Default>::default(),
354
                _resolution: PhantomData,
355
            }
356
        }
357
    }
358

            
359
    impl<Resolution> Serialize for LimitedResolutionDuration<Resolution>
360
    where
361
        Resolution: TimeResolution,
362
    {
363
530
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
364
530
        where
365
530
            S: serde::Serializer,
366
530
        {
367
530
            self.representation.serialize(serializer)
368
530
        }
369
    }
370

            
371
    impl<'de, Resolution> Deserialize<'de> for LimitedResolutionDuration<Resolution>
372
    where
373
        Resolution: TimeResolution,
374
    {
375
18522
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
376
18522
        where
377
18522
            D: serde::Deserializer<'de>,
378
18522
        {
379
18522
            <Resolution::Representation as Deserialize<'de>>::deserialize(deserializer)
380
18522
                .map(Self::new)
381
18522
        }
382
    }
383

            
384
    impl<Resolution> TryFrom<SignedDuration> for LimitedResolutionDuration<Resolution>
385
    where
386
        Resolution: TimeResolution,
387
    {
388
        type Error = TimeError;
389

            
390
4587
        fn try_from(duration: SignedDuration) -> Result<Self, Self::Error> {
391
4587
            Resolution::duration_to_repr(duration).map(|representation| Self {
392
4587
                representation,
393
4587
                _resolution: PhantomData,
394
4587
            })
395
4587
        }
396
    }
397

            
398
    impl<Resolution> TryFrom<LimitedResolutionDuration<Resolution>> for SignedDuration
399
    where
400
        Resolution: TimeResolution,
401
    {
402
        type Error = TimeError;
403

            
404
39
        fn try_from(value: LimitedResolutionDuration<Resolution>) -> Result<Self, Self::Error> {
405
39
            Resolution::repr_to_duration(value.representation)
406
39
        }
407
    }
408

            
409
    impl<Resolution> TryFrom<Duration> for LimitedResolutionDuration<Resolution>
410
    where
411
        Resolution: TimeResolution,
412
    {
413
        type Error = TimeError;
414

            
415
21
        fn try_from(duration: Duration) -> Result<Self, Self::Error> {
416
21
            Self::try_from(SignedDuration::Positive(duration))
417
21
        }
418
    }
419

            
420
    impl<Resolution> TryFrom<LimitedResolutionDuration<Resolution>> for Duration
421
    where
422
        Resolution: TimeResolution,
423
    {
424
        type Error = TimeError;
425

            
426
        fn try_from(value: LimitedResolutionDuration<Resolution>) -> Result<Self, Self::Error> {
427
7
            match SignedDuration::try_from(value) {
428
7
                Ok(SignedDuration::Positive(value)) => Ok(value),
429
                _ => Err(TimeError::DeltaNotRepresentable),
430
            }
431
7
        }
432
    }
433

            
434
    impl<Resolution> iter::Sum<LimitedResolutionDuration<Resolution>>
435
        for Option<LimitedResolutionDuration<Resolution>>
436
    where
437
        Resolution: TimeResolution,
438
    {
439
7
        fn sum<I: Iterator<Item = LimitedResolutionDuration<Resolution>>>(mut iter: I) -> Self {
440
7
            let first = iter
441
7
                .next()
442
7
                .and_then(|dur| Resolution::repr_to_duration(dur.representation).ok());
443
9
            let duration = iter.fold(first, |sum, dur| {
444
9
                sum.and_then(|sum| {
445
9
                    Resolution::repr_to_duration(dur.representation)
446
9
                        .ok()
447
9
                        .and_then(|dur| sum.checked_add(dur))
448
9
                })
449
9
            });
450
7
            duration.and_then(|dur| {
451
7
                Resolution::duration_to_repr(dur)
452
7
                    .ok()
453
7
                    .map(LimitedResolutionDuration::new)
454
7
            })
455
7
        }
456
    }
457

            
458
    impl<Resolution> iter::Sum<Self> for LimitedResolutionDuration<Resolution>
459
    where
460
        Resolution: TimeResolution,
461
    {
462
1
        fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
463
1
            iter.sum::<Option<Self>>().expect("operation overflowed")
464
1
        }
465
    }
466

            
467
1
    #[test]
468
1
    fn limited_resolution_duration_sum() {
469
1
        use super::Nanoseconds;
470
1
        assert_eq!(
471
1
            [
472
1
                Nanoseconds::new(1),
473
1
                Nanoseconds::new(2),
474
1
                Nanoseconds::new(3),
475
1
            ]
476
1
            .into_iter()
477
1
            .sum::<Nanoseconds>(),
478
1
            Nanoseconds::new(6)
479
1
        );
480
1
        assert_eq!(
481
1
            [
482
1
                Nanoseconds::new(1),
483
1
                Nanoseconds::new(2),
484
1
                Nanoseconds::new(3),
485
1
            ]
486
1
            .into_iter()
487
1
            .sum::<Option<Nanoseconds>>(),
488
1
            Some(Nanoseconds::new(6))
489
1
        );
490

            
491
1
        assert_eq!(
492
1
            [Nanoseconds::new(1), Nanoseconds::new(i64::MAX)]
493
1
                .into_iter()
494
1
                .sum::<Option<Nanoseconds>>(),
495
1
            None
496
1
        );
497

            
498
1
        assert_eq!(
499
1
            [Nanoseconds::new(i64::MAX), Nanoseconds::new(1)]
500
1
                .into_iter()
501
1
                .sum::<Option<Nanoseconds>>(),
502
1
            None
503
1
        );
504

            
505
1
        assert_eq!(
506
1
            [Nanoseconds::new(i64::MIN), Nanoseconds::new(-11)]
507
1
                .into_iter()
508
1
                .sum::<Option<Nanoseconds>>(),
509
1
            None
510
1
        );
511

            
512
1
        assert_eq!(
513
1
            [Nanoseconds::new(1), Nanoseconds::new(i64::MIN)]
514
1
                .into_iter()
515
1
                .sum::<Option<Nanoseconds>>(),
516
1
            Some(Nanoseconds::new(i64::MIN + 1))
517
1
        );
518
1
        assert_eq!(
519
1
            [Nanoseconds::new(i64::MIN), Nanoseconds::new(1)]
520
1
                .into_iter()
521
1
                .sum::<Option<Nanoseconds>>(),
522
1
            Some(Nanoseconds::new(i64::MIN + 1))
523
1
        );
524
1
    }
525

            
526
    /// A [`TimeResolution`] implementation that preserves nanosecond
527
    /// resolution. Internally, the number of microseconds is represented as an
528
    /// `i64`, allowing a range of +/- ~292.5 years.
529
    #[derive(Debug)]
530
    pub enum Nanoseconds {}
531

            
532
    const I64_MIN_ABS_AS_U64: u64 = 9_223_372_036_854_775_808;
533

            
534
    impl TimeResolution for Nanoseconds {
535
        type Representation = i64;
536

            
537
        const FORMAT_SUFFIX: &'static str = "ns";
538

            
539
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
540
4102
            if let Ok(unsigned) = u64::try_from(value) {
541
16
                Ok(SignedDuration::Positive(Duration::from_nanos(unsigned)))
542
            } else {
543
4086
                let positive = value
544
4086
                    .checked_abs()
545
4086
                    .and_then(|value| u64::try_from(value).ok())
546
4086
                    .unwrap_or(I64_MIN_ABS_AS_U64);
547
4086
                Ok(SignedDuration::Negative(Duration::from_nanos(positive)))
548
            }
549
4102
        }
550

            
551
4498
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
552
4498
            match duration {
553
10
                SignedDuration::Positive(duration) => {
554
10
                    i64::try_from(duration.as_nanos()).map_err(|_| TimeError::DeltaNotRepresentable)
555
                }
556
4488
                SignedDuration::Negative(duration) => {
557
4488
                    let nanos = duration.as_nanos();
558
4488
                    if let Ok(nanos) = i64::try_from(nanos) {
559
4487
                        Ok(-nanos)
560
1
                    } else if nanos == u128::from(I64_MIN_ABS_AS_U64) {
561
                        Ok(i64::MIN)
562
                    } else {
563
1
                        Err(TimeError::DeltaNotRepresentable)
564
                    }
565
                }
566
            }
567
4498
        }
568
    }
569

            
570
    /// A [`TimeResolution`] implementation that truncates time measurements to
571
    /// microseconds. Internally, the number of microseconds is represented as
572
    /// an `i64`, allowing a range of +/- ~292,471 years.
573
    #[derive(Debug)]
574
    pub enum Microseconds {}
575

            
576
    impl TimeResolution for Microseconds {
577
        type Representation = i64;
578

            
579
        const FORMAT_SUFFIX: &'static str = "us";
580

            
581
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
582
7
            if let Ok(unsigned) = u64::try_from(value) {
583
4
                Ok(SignedDuration::Positive(Duration::from_micros(unsigned)))
584
            } else {
585
3
                let positive = value
586
3
                    .checked_abs()
587
3
                    .and_then(|value| u64::try_from(value).ok())
588
3
                    .unwrap_or(u64::MAX);
589
3
                Ok(SignedDuration::Negative(Duration::from_micros(positive)))
590
            }
591
7
        }
592

            
593
14
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
594
14
            match duration {
595
7
                SignedDuration::Positive(duration) => i64::try_from(duration.as_micros())
596
7
                    .map_err(|_| TimeError::DeltaNotRepresentable),
597
7
                SignedDuration::Negative(duration) => {
598
7
                    let rounded_up = duration
599
7
                        .checked_add(Duration::from_nanos(999))
600
7
                        .ok_or(TimeError::DeltaNotRepresentable)?;
601
7
                    i64::try_from(rounded_up.as_micros())
602
7
                        .map(|repr| -repr)
603
7
                        .map_err(|_| TimeError::DeltaNotRepresentable)
604
                }
605
            }
606
14
        }
607
    }
608

            
609
    /// A [`TimeResolution`] implementation that truncates time measurements to
610
    /// milliseconds. Internally, the number of milliseconds is represented as
611
    /// an `i64`, allowing a range of +/- ~292.5 million years.
612
    #[derive(Debug)]
613
    pub enum Milliseconds {}
614

            
615
    impl TimeResolution for Milliseconds {
616
        type Representation = i64;
617

            
618
        const FORMAT_SUFFIX: &'static str = "ms";
619

            
620
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
621
7
            if let Ok(unsigned) = u64::try_from(value) {
622
4
                Ok(SignedDuration::Positive(Duration::from_millis(unsigned)))
623
            } else {
624
3
                let positive = value
625
3
                    .checked_abs()
626
3
                    .and_then(|value| u64::try_from(value).ok())
627
3
                    .unwrap_or(u64::MAX);
628
3
                Ok(SignedDuration::Negative(Duration::from_millis(positive)))
629
            }
630
7
        }
631

            
632
14
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
633
14
            match duration {
634
7
                SignedDuration::Positive(duration) => i64::try_from(duration.as_millis())
635
7
                    .map_err(|_| TimeError::DeltaNotRepresentable),
636
7
                SignedDuration::Negative(duration) => {
637
7
                    let rounded_up = duration
638
7
                        .checked_add(Duration::from_nanos(999_999))
639
7
                        .ok_or(TimeError::DeltaNotRepresentable)?;
640
7
                    i64::try_from(rounded_up.as_millis())
641
7
                        .map(|repr| -repr)
642
7
                        .map_err(|_| TimeError::DeltaNotRepresentable)
643
                }
644
            }
645
14
        }
646
    }
647

            
648
    /// A [`TimeResolution`] implementation that truncates time measurements to
649
    /// seconds. Internally, the number of seconds is represented as an `i64`,
650
    /// allowing a range of +/- ~21 times the age of the universe.
651
    #[derive(Debug)]
652
    pub enum Seconds {}
653

            
654
    impl TimeResolution for Seconds {
655
        type Representation = i64;
656

            
657
        const FORMAT_SUFFIX: &'static str = "s";
658

            
659
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
660
7
            if let Ok(unsigned) = u64::try_from(value) {
661
4
                Ok(SignedDuration::Positive(Duration::from_secs(unsigned)))
662
            } else {
663
3
                let positive = value
664
3
                    .checked_abs()
665
3
                    .and_then(|value| u64::try_from(value).ok())
666
3
                    .unwrap_or(u64::MAX);
667
3
                Ok(SignedDuration::Negative(Duration::from_secs(positive)))
668
            }
669
7
        }
670

            
671
14
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
672
14
            match duration {
673
7
                SignedDuration::Positive(duration) => {
674
7
                    i64::try_from(duration.as_secs()).map_err(|_| TimeError::DeltaNotRepresentable)
675
                }
676
7
                SignedDuration::Negative(duration) => {
677
7
                    let rounded_up = duration
678
7
                        .checked_add(Duration::from_nanos(999_999_999))
679
7
                        .ok_or(TimeError::DeltaNotRepresentable)?;
680
7
                    i64::try_from(rounded_up.as_secs())
681
7
                        .map(|repr| -repr)
682
7
                        .map_err(|_| TimeError::DeltaNotRepresentable)
683
                }
684
            }
685
14
        }
686
    }
687

            
688
    /// A [`TimeResolution`] implementation that truncates time measurements to
689
    /// minutes. Internally, the number of minutes is represented as an `i32`,
690
    /// allowing a range of +/- ~4,086 years.
691
    #[derive(Debug)]
692
    pub enum Minutes {}
693

            
694
    impl TimeResolution for Minutes {
695
        type Representation = i32;
696

            
697
        const FORMAT_SUFFIX: &'static str = "m";
698

            
699
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
700
7
            if let Ok(unsigned) = u64::try_from(value) {
701
4
                Ok(SignedDuration::Positive(Duration::from_secs(unsigned * 60)))
702
            } else {
703
3
                let positive = u64::try_from(i64::from(value).abs()).unwrap();
704
3
                Ok(SignedDuration::Negative(Duration::from_secs(positive * 60)))
705
            }
706
7
        }
707

            
708
14
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
709
14
            match duration {
710
7
                SignedDuration::Positive(duration) => i32::try_from(duration.as_secs() / 60)
711
7
                    .map_err(|_| TimeError::DeltaNotRepresentable),
712
7
                SignedDuration::Negative(duration) => i32::try_from((duration.as_secs() + 59) / 60)
713
7
                    .map(|repr| -repr)
714
7
                    .map_err(|_| TimeError::DeltaNotRepresentable),
715
            }
716
14
        }
717
    }
718

            
719
    /// A [`TimeResolution`] implementation that truncates time measurements to
720
    /// hours. Internally, the number of hours is represented as an `i32`,
721
    /// allowing a range of +/- ~245,147 years.
722
    #[derive(Debug)]
723
    pub enum Hours {}
724

            
725
    impl TimeResolution for Hours {
726
        type Representation = i32;
727

            
728
        const FORMAT_SUFFIX: &'static str = "h";
729

            
730
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
731
6
            if let Ok(unsigned) = u64::try_from(value) {
732
4
                Ok(SignedDuration::Positive(Duration::from_secs(
733
4
                    unsigned * 60 * 60,
734
4
                )))
735
            } else {
736
2
                let positive = u64::try_from(i64::from(value).abs()).unwrap();
737
2
                Ok(SignedDuration::Negative(Duration::from_secs(
738
2
                    positive * 60 * 60,
739
2
                )))
740
            }
741
6
        }
742

            
743
12
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
744
12
            const FACTOR: u64 = 60 * 60;
745
12
            match duration {
746
7
                SignedDuration::Positive(duration) => i32::try_from(duration.as_secs() / FACTOR)
747
7
                    .map_err(|_| TimeError::DeltaNotRepresentable),
748
5
                SignedDuration::Negative(duration) => {
749
5
                    i32::try_from((duration.as_secs() + FACTOR - 1) / FACTOR)
750
5
                        .map(|repr| -repr)
751
5
                        .map_err(|_| TimeError::DeltaNotRepresentable)
752
                }
753
            }
754
12
        }
755
    }
756

            
757
    /// A [`TimeResolution`] implementation that truncates time measurements to
758
    /// days. Internally, the number of days is represented as an `i32`,
759
    /// allowing a range of +/- ~5.88 million years.
760
    #[derive(Debug)]
761
    pub enum Days {}
762

            
763
    impl TimeResolution for Days {
764
        type Representation = i32;
765

            
766
        const FORMAT_SUFFIX: &'static str = "d";
767

            
768
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
769
7
            if let Ok(unsigned) = u64::try_from(value) {
770
4
                Ok(SignedDuration::Positive(Duration::from_secs(
771
4
                    unsigned * 24 * 60 * 60,
772
4
                )))
773
            } else {
774
3
                let positive = u64::try_from(i64::from(value).abs()).unwrap();
775
3
                Ok(SignedDuration::Negative(Duration::from_secs(
776
3
                    positive * 24 * 60 * 60,
777
3
                )))
778
            }
779
7
        }
780

            
781
14
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
782
14
            const FACTOR: u64 = 24 * 60 * 60;
783
14
            match duration {
784
7
                SignedDuration::Positive(duration) => i32::try_from(duration.as_secs() / FACTOR)
785
7
                    .map_err(|_| TimeError::DeltaNotRepresentable),
786
7
                SignedDuration::Negative(duration) => {
787
7
                    Ok(i32::try_from((duration.as_secs() + FACTOR - 1) / FACTOR)
788
7
                        .map_or(i32::MIN, |repr| -repr))
789
                }
790
            }
791
14
        }
792
    }
793

            
794
    /// A [`TimeResolution`] implementation that truncates time measurements to
795
    /// weeks. Internally, the number of weeks is represented as an `i32`,
796
    /// allowing a range of +/- ~41.18 million years.
797
    #[derive(Debug)]
798
    pub enum Weeks {}
799

            
800
    impl TimeResolution for Weeks {
801
        type Representation = i32;
802

            
803
        const FORMAT_SUFFIX: &'static str = "w";
804

            
805
        fn repr_to_duration(value: Self::Representation) -> Result<SignedDuration, TimeError> {
806
7
            if let Ok(unsigned) = u64::try_from(value) {
807
4
                Ok(SignedDuration::Positive(Duration::from_secs(
808
4
                    unsigned * 7 * 24 * 60 * 60,
809
4
                )))
810
            } else {
811
3
                let positive = u64::try_from(i64::from(value).abs()).unwrap();
812
3
                Ok(SignedDuration::Negative(Duration::from_secs(
813
3
                    positive * 7 * 24 * 60 * 60,
814
3
                )))
815
            }
816
7
        }
817

            
818
14
        fn duration_to_repr(duration: SignedDuration) -> Result<Self::Representation, TimeError> {
819
14
            const FACTOR: u64 = 7 * 24 * 60 * 60;
820
14
            match duration {
821
7
                SignedDuration::Positive(duration) => i32::try_from(duration.as_secs() / FACTOR)
822
7
                    .map_err(|_| TimeError::DeltaNotRepresentable),
823
7
                SignedDuration::Negative(duration) => {
824
7
                    i32::try_from((duration.as_secs() + FACTOR - 1) / FACTOR)
825
7
                        .map(|repr| -repr)
826
7
                        .map_err(|_| TimeError::DeltaNotRepresentable)
827
                }
828
            }
829
14
        }
830
    }
831

            
832
1
    #[test]
833
1
    fn limited_resolution_duration_tests() {
834
14
        fn test_limited<Resolution: TimeResolution>(
835
14
            duration: Duration,
836
14
            expected_step: Resolution::Representation,
837
14
        ) {
838
14
            let limited = LimitedResolutionDuration::<Resolution>::try_from(duration).unwrap();
839
14
            assert_eq!(limited.representation, expected_step);
840
14
            let encoded = limited.as_ord_bytes().unwrap();
841
14
            println!("Encoded {limited:?} to {} bytes", encoded.len());
842
14
            let decoded =
843
14
                LimitedResolutionDuration::from_ord_bytes(ByteSource::Borrowed(&encoded)).unwrap();
844
14
            assert_eq!(limited, decoded);
845
14
        }
846
1

            
847
7
        fn test_eq_limited<Resolution: TimeResolution>(
848
7
            duration: Duration,
849
7
            expected_step: Resolution::Representation,
850
7
        ) {
851
7
            test_limited::<Resolution>(duration, expected_step);
852
7
            let limited = LimitedResolutionDuration::<Resolution>::try_from(duration).unwrap();
853
7
            assert_eq!(duration, Duration::try_from(limited).unwrap());
854
7
        }
855
1

            
856
1
        let truncating_seconds = 7 * 24 * 60 * 60 + 24 * 60 * 60 + 60 * 60 + 60 + 1;
857
1
        let truncating = Duration::new(u64::try_from(truncating_seconds).unwrap(), 987_654_321);
858
1
        test_limited::<Weeks>(truncating, 1);
859
1
        test_limited::<Days>(truncating, 8);
860
1
        test_limited::<Hours>(truncating, 8 * 24 + 1);
861
1
        test_limited::<Minutes>(truncating, 8 * 24 * 60 + 60 + 1);
862
1
        test_limited::<Seconds>(truncating, 8 * 24 * 60 * 60 + 60 * 60 + 60 + 1);
863
1
        test_limited::<Milliseconds>(truncating, truncating_seconds * 1_000 + 987);
864
1
        test_limited::<Microseconds>(truncating, truncating_seconds * 1_000_000 + 987_654);
865
1

            
866
1
        let forty_two_days = Duration::from_secs(42 * 24 * 60 * 60);
867
1
        test_eq_limited::<Weeks>(forty_two_days, 6);
868
1
        test_eq_limited::<Days>(forty_two_days, 42);
869
1
        test_eq_limited::<Hours>(forty_two_days, 42 * 24);
870
1
        test_eq_limited::<Minutes>(forty_two_days, 42 * 24 * 60);
871
1
        test_eq_limited::<Seconds>(forty_two_days, 42 * 24 * 60 * 60);
872
1
        test_eq_limited::<Milliseconds>(forty_two_days, 42 * 24 * 60 * 60 * 1_000);
873
1
        test_eq_limited::<Microseconds>(forty_two_days, 42 * 24 * 60 * 60 * 1_000_000);
874
1
    }
875

            
876
    /// A timestamp (moment in time) stored with a limited `Resolution`. This
877
    /// type may be preferred to [`std::time::SystemTime`] because `SystemTime`
878
    /// serializes with nanosecond resolution. Often this level of precision is
879
    /// not needed and less storage and memory can be used.
880
    ///
881
    /// This type stores the representation of the timestamp as a
882
    /// [`LimitedResolutionDuration`] relative to `Epoch`.
883
    ///
884
    /// The `Resolution` type controls the storage size. The resolutions
885
    /// provided by BonsaiDb:
886
    ///
887
    /// - [`Weeks`]
888
    /// - [`Days`]
889
    /// - [`Hours`]
890
    /// - [`Minutes`]
891
    /// - [`Seconds`]
892
    /// - [`Milliseconds`]
893
    /// - [`Microseconds`]
894
    /// - [`Nanoseconds`]
895
    ///
896
    /// Other resolutions can be used by implementing [`TimeResolution`].
897
    /// BonsaiDb provides two [`TimeEpoch`] implementations:
898
    ///
899
    /// - [`UnixEpoch`]
900
    /// - [`BonsaiEpoch`]
901
192
    #[derive_where(Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
902
    pub struct LimitedResolutionTimestamp<Resolution: TimeResolution, Epoch: TimeEpoch>(
903
        LimitedResolutionDuration<Resolution>,
904
        PhantomData<Epoch>,
905
    );
906

            
907
    impl<Resolution, Epoch> Default for LimitedResolutionTimestamp<Resolution, Epoch>
908
    where
909
        Resolution: TimeResolution,
910
        Epoch: TimeEpoch,
911
    {
912
        fn default() -> Self {
913
            Self(LimitedResolutionDuration::default(), PhantomData)
914
        }
915
    }
916

            
917
    impl<Resolution, Epoch> Serialize for LimitedResolutionTimestamp<Resolution, Epoch>
918
    where
919
        Resolution: TimeResolution,
920
        Epoch: TimeEpoch,
921
    {
922
530
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
923
530
        where
924
530
            S: serde::Serializer,
925
530
        {
926
530
            self.0.serialize(serializer)
927
530
        }
928
    }
929

            
930
    impl<'de, Resolution, Epoch> Deserialize<'de> for LimitedResolutionTimestamp<Resolution, Epoch>
931
    where
932
        Resolution: TimeResolution,
933
        Epoch: TimeEpoch,
934
    {
935
18522
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
936
18522
        where
937
18522
            D: serde::Deserializer<'de>,
938
18522
        {
939
18522
            LimitedResolutionDuration::deserialize(deserializer)
940
18522
                .map(|duration| Self(duration, PhantomData))
941
18522
        }
942
    }
943

            
944
    /// An epoch for [`LimitedResolutionTimestamp`].
945
    pub trait TimeEpoch: Sized + Send + Sync {
946
        /// The name of this epoch, used in [`KeyEncoding::describe`] to
947
        /// disambiguate timestamps with different epochs.
948
        fn name() -> &'static str;
949

            
950
        /// The offset from [`UNIX_EPOCH`] for this epoch.
951
        fn epoch_offset() -> Duration;
952
    }
953

            
954
    impl<Resolution, Epoch> LimitedResolutionTimestamp<Resolution, Epoch>
955
    where
956
        Resolution: TimeResolution,
957
        Epoch: TimeEpoch,
958
    {
959
        /// Returns [`SystemTime::now()`] limited to `Resolution`. The timestamp
960
        /// will be truncated, not rounded.
961
        ///
962
        /// # Panics
963
        ///
964
        /// This function will panic [`SystemTime::now()`] is unable to be
965
        /// represented by `Resolution` and `Epoch`.
966
        #[must_use]
967
4511
        pub fn now() -> Self {
968
4511
            Self::try_from(SystemTime::now()).expect("now should always be representable")
969
4511
        }
970

            
971
        /// Returns the duration since another timestamp. This returns None if
972
        /// `other` is before `self`,
973
        pub fn duration_since(
974
            &self,
975
            other: &impl AnyTimestamp,
976
        ) -> Result<Option<Duration>, TimeError> {
977
            let self_delta = self.duration_since_unix_epoch()?;
978
            let other_delta = other.duration_since_unix_epoch()?;
979
            Ok(self_delta.checked_sub(other_delta))
980
        }
981

            
982
        /// Returns the absolute duration between `self` and `other`.
983
296
        pub fn duration_between(&self, other: &impl AnyTimestamp) -> Result<Duration, TimeError> {
984
296
            let self_delta = self.duration_since_unix_epoch()?;
985
296
            let other_delta = other.duration_since_unix_epoch()?;
986
296
            if self_delta < other_delta {
987
296
                Ok(other_delta - self_delta)
988
            } else {
989
                Ok(self_delta - other_delta)
990
            }
991
296
        }
992

            
993
        /// Returns the internal representation of this timestamp, which is a
994
        /// unit of `Resolution`.
995
6240
        pub const fn representation(&self) -> Resolution::Representation {
996
6240
            self.0.representation()
997
6240
        }
998

            
999
        /// Returns a new timestamp using the `representation` provided.
119
        pub fn from_representation(representation: Resolution::Representation) -> Self {
119
            Self::from(LimitedResolutionDuration::new(representation))
119
        }

            
        /// Converts this value to a a decimal string containing the number of
        /// seconds since the unix epoch (January 1, 1970 00:00:00 UTC).
        ///
        /// The resulting string can be parsed as well.
        ///
        /// ```rust
        /// use bonsaidb_core::key::time::limited::{
        ///     BonsaiEpoch, LimitedResolutionTimestamp, Milliseconds,
        /// };
        ///
        /// let now = LimitedResolutionTimestamp::<Milliseconds, BonsaiEpoch>::now();
        /// let timestamp = now.to_timestamp_string().unwrap();
        /// let parsed = timestamp.parse().unwrap();
        /// assert_eq!(now, parsed);
        /// ```
        ///
        /// The difference between this function and `to_string()`] is that
        /// `to_string()` will revert to using the underlying
        /// [`LimitedResolutionDuration`]'s `to_string()` if a value is unable
        /// to be converted to a value relative to the unix epoch.
        pub fn to_timestamp_string(&self) -> Result<String, TimeError> {
            let mut string = String::new();
            self.display(&mut string).map(|_| string)
        }

            
2815
        fn display(&self, f: &mut impl Write) -> Result<(), TimeError> {
2815
            let since_epoch = self.duration_since_unix_epoch()?;
2815
            write!(f, "{}", since_epoch.as_secs()).map_err(|_| TimeError::InvalidValue)?;
2815
            if since_epoch.subsec_nanos() > 0 {
2803
                if since_epoch.subsec_nanos() % 1_000_000 == 0 {
                    // Rendering any precision beyond milliseconds will yield 0s
1
                    write!(f, ".{:03}", since_epoch.subsec_millis())
1
                        .map_err(|_| TimeError::InvalidValue)
2802
                } else if since_epoch.subsec_nanos() % 1_000 == 0 {
1
                    write!(f, ".{:06}", since_epoch.subsec_micros())
1
                        .map_err(|_| TimeError::InvalidValue)
                } else {
2801
                    write!(f, ".{:09}", since_epoch.subsec_nanos())
2801
                        .map_err(|_| TimeError::InvalidValue)
                }
            } else {
                // No subsecond
12
                Ok(())
            }
2815
        }
    }

            
    /// A timestamp that can report it sduration since the Unix Epoch.
    pub trait AnyTimestamp {
        /// Returns the [`Duration`] since January 1, 1970 00:00:00 UTC for this
        /// timestamp.
        fn duration_since_unix_epoch(&self) -> Result<Duration, TimeError>;
    }

            
    impl AnyTimestamp for SystemTime {
        fn duration_since_unix_epoch(&self) -> Result<Duration, TimeError> {
            Ok(self.duration_since(UNIX_EPOCH).unwrap())
        }
    }

            
    impl<Resolution, Epoch> AnyTimestamp for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
4095
        fn duration_since_unix_epoch(&self) -> Result<Duration, TimeError> {
4095
            let relative_offset = Resolution::repr_to_duration(self.0.representation)?;
4095
            match relative_offset {
8
                SignedDuration::Positive(offset) => Epoch::epoch_offset()
8
                    .checked_add(offset)
8
                    .ok_or(TimeError::DeltaNotRepresentable),
4087
                SignedDuration::Negative(offset) => Epoch::epoch_offset()
4087
                    .checked_sub(offset)
4087
                    .ok_or(TimeError::DeltaNotRepresentable),
            }
4095
        }
    }

            
    impl<Resolution, Epoch> Debug for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
240
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240
            write!(f, "LimitedResolutionTimestamp({self})")
240
        }
    }

            
    impl<Resolution, Epoch> Display for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
2815
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2815
            self.display(f).or_else(|_| Display::fmt(&self.0, f))
2815
        }
    }

            
    impl<Resolution, Epoch> FromStr for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        type Err = TimeError;

            
7
        fn from_str(s: &str) -> Result<Self, Self::Err> {
7
            let mut parts = s.split('.');
7
            let seconds = parts.next().ok_or(TimeError::InvalidValue)?;
7
            let seconds = seconds
7
                .parse::<u64>()
7
                .map_err(|_| TimeError::InvalidValue)?;

            
7
            let duration = if let Some(subseconds_str) = parts.next() {
3
                if subseconds_str.len() > 9 || parts.next().is_some() {
                    return Err(TimeError::InvalidValue);
3
                }
3
                let subseconds = subseconds_str
3
                    .parse::<u32>()
3
                    .map_err(|_| TimeError::InvalidValue)?;

            
3
                let nanos =
3
                    subseconds * 10_u32.pow(u32::try_from(9 - subseconds_str.len()).unwrap());
3
                Duration::new(seconds, nanos)
            } else {
4
                Duration::from_secs(seconds)
            };

            
7
            let epoch = Epoch::epoch_offset();
7
            let duration = if duration < epoch {
7
                SignedDuration::Negative(epoch - duration)
            } else {
                SignedDuration::Positive(duration - epoch)
            };
            Ok(Self::from(
7
                LimitedResolutionDuration::<Resolution>::try_from(duration)?,
            ))
7
        }
    }

            
1
    #[test]
1
    fn timestamp_parse_tests() {
7
        fn test_roundtrip_parsing<Resolution: TimeResolution>() {
7
            let original = LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::now();
7
            let unix_timestamp = original.to_string();
7
            let parsed = unix_timestamp.parse().unwrap();
7
            assert_eq!(
1
                original, parsed,
1
                "{original} produced {unix_timestamp}, but parsed {parsed}"
1
            );
7
        }
1

            
1
        test_roundtrip_parsing::<Weeks>();
1
        test_roundtrip_parsing::<Days>();
1
        test_roundtrip_parsing::<Minutes>();
1
        test_roundtrip_parsing::<Seconds>();
1
        test_roundtrip_parsing::<Milliseconds>();
1
        test_roundtrip_parsing::<Microseconds>();
1
        test_roundtrip_parsing::<Nanoseconds>();
1
    }

            
    impl<'k, Resolution, Epoch> Key<'k> for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        const CAN_OWN_BYTES: bool = false;

            
        fn from_ord_bytes<'e>(bytes: ByteSource<'k, 'e>) -> Result<Self, Self::Error> {
            let duration = LimitedResolutionDuration::<Resolution>::from_ord_bytes(bytes)?;
            Ok(Self::from(duration))
        }
    }

            
    impl<Resolution, Epoch> KeyEncoding<Self> for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        type Error = TimeError;

            
        const LENGTH: Option<usize> = None;

            
1
        fn describe<Visitor>(visitor: &mut Visitor)
1
        where
1
            Visitor: KeyVisitor,
1
        {
1
            visitor.visit_composite(
1
                CompositeKind::Struct(Cow::Borrowed(
1
                    "bonsaidb::core::key::time::LimitedResolutionTimestamp",
1
                )),
1
                1,
1
            );
1
            visitor.visit_composite_attribute("epoch", Epoch::epoch_offset().as_nanos());
1
            <Resolution::Representation as KeyEncoding>::describe(visitor);
1
        }

            
        fn as_ord_bytes(&self) -> Result<Cow<'_, [u8]>, Self::Error> {
            self.0.as_ord_bytes()
        }
    }

            
    impl<Resolution, Epoch> From<LimitedResolutionDuration<Resolution>>
        for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
9326
        fn from(duration: LimitedResolutionDuration<Resolution>) -> Self {
9326
            Self(duration, PhantomData)
9326
        }
    }

            
    impl<Resolution, Epoch> From<LimitedResolutionTimestamp<Resolution, Epoch>>
        for LimitedResolutionDuration<Resolution>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        fn from(time: LimitedResolutionTimestamp<Resolution, Epoch>) -> Self {
            time.0
        }
    }

            
    impl<Resolution, Epoch> TryFrom<SystemTime> for LimitedResolutionTimestamp<Resolution, Epoch>
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        type Error = TimeError;

            
4559
        fn try_from(time: SystemTime) -> Result<Self, TimeError> {
4559
            let epoch = UNIX_EPOCH
4559
                .checked_add(Epoch::epoch_offset())
4559
                .ok_or(TimeError::DeltaNotRepresentable)?;
4559
            match time.duration_since(epoch) {
34
                Ok(duration) => {
34
                    LimitedResolutionDuration::try_from(SignedDuration::Positive(duration))
34
                        .map(Self::from)
                }
4525
                Err(_) => match epoch.duration_since(time) {
4525
                    Ok(duration) => {
4525
                        LimitedResolutionDuration::try_from(SignedDuration::Negative(duration))
4525
                            .map(Self::from)
                    }
                    Err(_) => Err(TimeError::DeltaNotRepresentable),
                },
            }
4559
        }
    }

            
    impl<Resolution, Epoch> TryFrom<LimitedResolutionTimestamp<Resolution, Epoch>> for SystemTime
    where
        Resolution: TimeResolution,
        Epoch: TimeEpoch,
    {
        type Error = TimeError;

            
32
        fn try_from(
32
            time: LimitedResolutionTimestamp<Resolution, Epoch>,
32
        ) -> Result<Self, TimeError> {
32
            let since_epoch = SignedDuration::try_from(time.0)?;
32
            let epoch = UNIX_EPOCH
32
                .checked_add(Epoch::epoch_offset())
32
                .ok_or(TimeError::DeltaNotRepresentable)?;
32
            let time = match since_epoch {
17
                SignedDuration::Positive(since_epoch) => epoch.checked_add(since_epoch),
15
                SignedDuration::Negative(since_epoch) => epoch.checked_sub(since_epoch),
            };

            
32
            time.ok_or(TimeError::DeltaNotRepresentable)
32
        }
    }

            
    /// A [`TimeEpoch`] implementation that allows storing
    /// [`LimitedResolutionTimestamp`] relative to the "unix epoch": January 1,
    /// 1970 00:00:00 UTC.
    pub struct UnixEpoch;

            
    impl TimeEpoch for UnixEpoch {
        fn name() -> &'static str {
            "Unix"
        }

            
24
        fn epoch_offset() -> Duration {
24
            Duration::ZERO
24
        }
    }

            
    /// A [`TimeEpoch`] implementation that allows storing
    /// [`LimitedResolutionTimestamp`] relative to the 10-year anniversary of
    /// BonsaiDb: March 20, 2031 04:31:47 UTC.
    ///
    /// ## Why use [`BonsaiEpoch`] instead of [`UnixEpoch`]?
    ///
    /// [`LimitedResolutionTimestamp`] uses [`ordered-varint::Variable`] to
    /// implement [`Key`], which encodes the underlying value in as few bytes as
    /// possible while still preserving the ordering required by [`Key`].
    ///
    /// Many applications are not storing timestamps that predate the
    /// application being developed. When there is a likelihood that timestamps
    /// are closer to "now" than they are to the unix timestamp (January 1, 1970
    /// 00:00:00 UTC), the [`BonsaiEpoch`] will consistently encode the
    /// underlying representation in fewer bytes than when using [`UnixEpoch`].
    ///
    /// We hope BonsaiDb is a viable database option for many years. By setting
    /// this epoch 10 years from the start of BonsaiDb, it allows the internal
    /// representation of timestamps to slowly decrease in size until the
    /// 10-year anniversary. Over the following 10 years, the size will grow
    /// back to the same size it was at its conception, and then slowly grow as
    /// needed from that point on.
    pub struct BonsaiEpoch;

            
    impl BonsaiEpoch {
        const EPOCH: Duration = Duration::new(1_931_747_507, 0);
    }

            
    impl TimeEpoch for BonsaiEpoch {
        fn name() -> &'static str {
            "BonsaiDb"
        }

            
8671
        fn epoch_offset() -> Duration {
8671
            Self::EPOCH
8671
        }
    }

            
1
    #[test]
1
    fn limited_resolution_timestamp_tests() {
8
        fn test_resolution<Resolution: TimeResolution>(resolution: Duration) {
8
            let now_in_seconds = LimitedResolutionTimestamp::<Resolution, UnixEpoch>::now();
8
            let as_system = SystemTime::try_from(now_in_seconds).unwrap();
8
            let as_limited =
8
                LimitedResolutionTimestamp::<Resolution, UnixEpoch>::try_from(as_system).unwrap();
8
            assert_eq!(as_limited, now_in_seconds);
1

            
8
            let now_in_seconds = LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::now();
8
            let as_system = SystemTime::try_from(now_in_seconds).unwrap();
8
            let as_limited =
8
                LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::try_from(as_system).unwrap();
8
            assert_eq!(as_limited, now_in_seconds);
1

            
8
            let slightly_before_epoch = UNIX_EPOCH + BonsaiEpoch::EPOCH
8
                - Duration::from_nanos(u64::try_from(resolution.as_nanos() / 2).unwrap());
8
            let unix_epoch_in_recent =
8
                LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::try_from(
8
                    slightly_before_epoch,
8
                )
8
                .unwrap();
8
            let as_system = SystemTime::try_from(unix_epoch_in_recent).unwrap();
8
            let as_limited =
8
                LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::try_from(as_system).unwrap();
8
            assert!(
8
                slightly_before_epoch
8
                    .duration_since(as_system)
8
                    .expect("timestamp should have been trunctated towards MIN")
8
                    < resolution
8
            );
8
            assert_eq!(as_limited, unix_epoch_in_recent);
1

            
8
            let slightly_after_epoch = UNIX_EPOCH
8
                + BonsaiEpoch::EPOCH
8
                + Duration::from_nanos(u64::try_from(resolution.as_nanos() / 2).unwrap());
8
            let unix_epoch_in_recent =
8
                LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::try_from(
8
                    slightly_after_epoch,
8
                )
8
                .unwrap();
8
            let as_system = SystemTime::try_from(unix_epoch_in_recent).unwrap();
8
            println!("{slightly_after_epoch:?} converted to {unix_epoch_in_recent} and back as {as_system:?}");
8
            let as_limited =
8
                LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::try_from(as_system).unwrap();
8
            assert!(
8
                slightly_after_epoch
8
                    .duration_since(as_system)
8
                    .expect("timestamp should have been truncated towards 0")
8
                    < resolution
8
            );
8
            assert_eq!(as_limited, unix_epoch_in_recent);
8
        }
1

            
1
        test_resolution::<Weeks>(Duration::from_secs(7 * 24 * 60 * 60));
1
        test_resolution::<Days>(Duration::from_secs(24 * 60 * 60));
1
        test_resolution::<Hours>(Duration::from_secs(60 * 60));
1
        test_resolution::<Minutes>(Duration::from_secs(60));
1
        test_resolution::<Seconds>(Duration::from_secs(1));
1
        test_resolution::<Milliseconds>(Duration::from_millis(1));
1
        test_resolution::<Microseconds>(Duration::from_micros(1));
1
        test_resolution::<Nanoseconds>(Duration::from_nanos(1));
1
    }

            
1
    #[test]
1
    fn serialization_tests() {
8
        fn test_serialization<Resolution: TimeResolution>() {
8
            let original = LimitedResolutionTimestamp::<Resolution, BonsaiEpoch>::now();
8
            let serialized = pot::to_vec(&original).unwrap();
8
            let deserialized = pot::from_slice(&serialized).unwrap();
8
            assert_eq!(original, deserialized);
8
        }
1

            
1
        test_serialization::<Weeks>();
1
        test_serialization::<Days>();
1
        test_serialization::<Hours>();
1
        test_serialization::<Minutes>();
1
        test_serialization::<Seconds>();
1
        test_serialization::<Milliseconds>();
1
        test_serialization::<Microseconds>();
1
        test_serialization::<Nanoseconds>();
1
    }
}

            
/// A signed duration of time represented in weeks (604,800 seconds).
/// Internally, the number of weeks is represented as an `i32`,
/// allowing a range of +/- ~41.18 million years.
pub type Weeks = limited::LimitedResolutionDuration<limited::Weeks>;

            
/// A signed duration of time represented in days (86,400 seconds). Internally,
/// the number of days is represented as an `i32`, allowing a range of +/- ~5.88
/// million years.
pub type Days = limited::LimitedResolutionDuration<limited::Days>;

            
/// A signed duration of time represented in hours (3,600 seconds). Internally,
/// the number of hours is represented as an `i32`, allowing a range of +/-
/// ~245,147 years.
pub type Hours = limited::LimitedResolutionDuration<limited::Hours>;

            
/// A signed duration of time represented in minutes (60 seconds). Internally,
/// the number of minutes is represented as an `i32`,
/// allowing a range of +/- ~4,086 years.
pub type Minutes = limited::LimitedResolutionDuration<limited::Minutes>;

            
/// A signed duration of time represented in seconds (with no partial
/// subseconds). Internally, the number of seconds is represented as an `i64`,
/// allowing a range of +/- ~21 times the age of the universe.
pub type Seconds = limited::LimitedResolutionDuration<limited::Seconds>;

            
/// A signed duration of time represented in milliseconds (1/1,000th of a
/// second). Internally, the number of milliseconds is represented as an `i64`,
/// allowing a range of +/- ~292.5 million years.
pub type Milliseconds = limited::LimitedResolutionDuration<limited::Milliseconds>;

            
/// A signed duration of time represented in microseconds (1/1,000,000th of a
/// second). Internally, the number of microseconds is represented as an `i64`,
/// allowing a range of +/- ~292,471 years.
pub type Microseconds = limited::LimitedResolutionDuration<limited::Microseconds>;

            
/// A signed duration of time represented in nanoseconds (1/1,000,000,000th of a
/// second). Internally, the number of microseconds is represented as an `i64`,
/// allowing a range of +/- ~292.5 years.
pub type Nanoseconds = limited::LimitedResolutionDuration<limited::Nanoseconds>;

            
/// A timestamp stored as the number of weeks (604,800 seconds) relative to
/// [`UnixEpoch`]. Internally, the number of weeks is represented as an `i32`,
/// allowing a range of +/- ~41.18 million years.
pub type WeeksSinceUnixEpoch = limited::LimitedResolutionTimestamp<limited::Weeks, UnixEpoch>;

            
/// A timestamp stored as the number of days (86,400 seconds) relative to
/// [`UnixEpoch`]. Internally, the number of days is represented as an `i32`,
/// allowing a range of +/- ~5.88 million years.
pub type DaysSinceUnixEpoch = limited::LimitedResolutionTimestamp<limited::Days, UnixEpoch>;

            
/// A timestamp stored as the number of hours (3,600 seconds) relative to
/// [`UnixEpoch`]. Internally, the number of hours is represented as an `i32`,
/// allowing a range of +/- ~245,147 years.
pub type HoursSinceUnixEpoch = limited::LimitedResolutionTimestamp<limited::Hours, UnixEpoch>;

            
/// A timestamp stored as the number of minutes (60 seconds) relative to
/// [`UnixEpoch`]. Internally, the number of minutes is represented as an `i32`,
/// allowing a range of +/- ~4,086 years.
pub type MinutesSinceUnixEpoch = limited::LimitedResolutionTimestamp<limited::Minutes, UnixEpoch>;

            
/// A timestamp stored as the number of seconds (with no partial subseconds)
/// relative to [`UnixEpoch`]. Internally, the number of seconds is represented
/// as an `i64`, allowing a range of +/- ~21 times the age of the universe.
pub type SecondsSinceUnixEpoch = limited::LimitedResolutionTimestamp<limited::Seconds, UnixEpoch>;

            
/// A timestamp stored as the number of milliseconds (1/1,000th of a second)
/// relative to [`UnixEpoch`]. Internally, the number of milliseconds is
/// represented as an `i64`, allowing a range of +/- ~292.5 million years.
pub type MillisecondsSinceUnixEpoch =
    limited::LimitedResolutionTimestamp<limited::Milliseconds, UnixEpoch>;

            
/// A timestamp stored as the number of microseconds (1/1,000,000th of a second)
/// relative to [`UnixEpoch`]. Internally, the number of microseconds is
/// represented as an `i64`, allowing a range of +/- ~292,471 years.
pub type MicrosecondsSinceUnixEpoch =
    limited::LimitedResolutionTimestamp<limited::Microseconds, UnixEpoch>;

            
/// A timestamp stored as the number of nanoseconds (1/1,000,000,000th of a
/// second) relative to [`UnixEpoch`]. Internally, the number of microseconds is
/// represented as an `i64`, allowing a range of +/- ~292.5 years.
pub type NanosecondsSinceUnixEpoch =
    limited::LimitedResolutionTimestamp<limited::Nanoseconds, UnixEpoch>;

            
/// A timestamp stored as the number of weeks (604,800 seconds) relative to
/// [`BonsaiEpoch`]. Internally, the number of weeks is represented as an `i32`,
/// allowing a range of +/- ~41.18 million years.
pub type TimestampAsWeeks = limited::LimitedResolutionTimestamp<limited::Weeks, BonsaiEpoch>;

            
/// A timestamp stored as the number of days (86,400 seconds) relative to
/// [`BonsaiEpoch`]. Internally, the number of days is represented as an `i32`,
/// allowing a range of +/- ~5.88 million years.
pub type TimestampAsDays = limited::LimitedResolutionTimestamp<limited::Days, BonsaiEpoch>;

            
/// A timestamp stored as the number of hours (3,600 seconds) relative to
/// [`BonsaiEpoch`]. Internally, the number of hours is represented as an `i32`,
/// allowing a range of +/- ~245,147 years.
pub type TimestampAsHours = limited::LimitedResolutionTimestamp<limited::Hours, BonsaiEpoch>;

            
/// A timestamp stored as the number of minutes (60 seconds) relative to
/// [`BonsaiEpoch`]. Internally, the number of minutes is represented as an `i32`,
/// allowing a range of +/- ~4,086 years.
pub type TimestampAsMinutes = limited::LimitedResolutionTimestamp<limited::Minutes, BonsaiEpoch>;

            
/// A timestamp stored as the number of seconds (with no partial subseconds)
/// relative to [`BonsaiEpoch`]. Internally, the number of seconds is represented
/// as an `i64`, allowing a range of +/- ~21 times the age of the universe.
pub type TimestampAsSeconds = limited::LimitedResolutionTimestamp<limited::Seconds, BonsaiEpoch>;

            
/// A timestamp stored as the number of milliseconds (1/1,000th of a second)
/// relative to [`BonsaiEpoch`]. Internally, the number of milliseconds is
/// represented as an `i64`, allowing a range of +/- ~292.5 million years.
pub type TimestampAsMilliseconds =
    limited::LimitedResolutionTimestamp<limited::Milliseconds, BonsaiEpoch>;

            
/// A timestamp stored as the number of microseconds (1/1,000,000th of a second)
/// relative to [`BonsaiEpoch`]. Internally, the number of microseconds is
/// represented as an `i64`, allowing a range of +/- ~292,471 years.
pub type TimestampAsMicroseconds =
    limited::LimitedResolutionTimestamp<limited::Microseconds, BonsaiEpoch>;

            
/// A timestamp stored as the number of nanoseconds (1/1,000,000,000th of a
/// second) relative to [`BonsaiEpoch`]. Internally, the number of microseconds is
/// represented as an `i64`, allowing a range of +/- ~292.5 years.
pub type TimestampAsNanoseconds =
    limited::LimitedResolutionTimestamp<limited::Nanoseconds, BonsaiEpoch>;