Skip to main content

nautilus_core/
interval.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Closed interval types shared across request planning and persistence coverage.
17
18/// A closed nanosecond interval, inclusive at both ends.
19#[derive(Clone, Copy, Debug, Eq, PartialEq)]
20pub struct ClosedInterval {
21    /// Inclusive start in nanoseconds since the Unix epoch.
22    pub start: u64,
23    /// Inclusive end in nanoseconds since the Unix epoch.
24    pub end: u64,
25}
26
27impl ClosedInterval {
28    /// Creates a closed interval if `start <= end`.
29    #[must_use]
30    pub const fn new(start: u64, end: u64) -> Option<Self> {
31        if start <= end {
32            Some(Self { start, end })
33        } else {
34            None
35        }
36    }
37}
38
39impl From<ClosedInterval> for (u64, u64) {
40    fn from(interval: ClosedInterval) -> Self {
41        (interval.start, interval.end)
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use rstest::rstest;
48
49    use super::*;
50
51    #[rstest]
52    #[case(0, 0, true)]
53    #[case(0, 1, true)]
54    #[case(2, 1, false)]
55    fn test_new_validates_order(#[case] start: u64, #[case] end: u64, #[case] expected: bool) {
56        assert_eq!(ClosedInterval::new(start, end).is_some(), expected);
57    }
58
59    #[rstest]
60    fn test_new_stores_bounds() {
61        let interval = ClosedInterval::new(3, 7).unwrap();
62        assert_eq!((interval.start, interval.end), (3, 7));
63    }
64
65    #[rstest]
66    fn test_into_tuple() {
67        let interval = ClosedInterval::new(3, 7).unwrap();
68        let pair: (u64, u64) = interval.into();
69        assert_eq!(pair, (3, 7));
70    }
71}