risingwave_common/
range.rs

1// Copyright 2025 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
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
15use std::ops::{Add, Bound, RangeBounds, Sub};
16
17mod private {
18
19    pub trait ZeroOne {
20        fn zero() -> Self;
21        fn one() -> Self;
22    }
23
24    macro_rules! impl_one {
25        ($($t:ty),*) => {
26            $(
27                impl ZeroOne for $t {
28                    fn zero() -> Self {
29                        0 as $t
30                    }
31
32                    fn one() -> Self {
33                        1 as $t
34                    }
35                }
36            )*
37        };
38    }
39
40    macro_rules! for_all_num_type {
41        ($macro:ident) => {
42            $macro! { u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64 }
43        };
44    }
45
46    for_all_num_type! { impl_one }
47}
48
49use private::ZeroOne;
50
51pub trait Idx = PartialOrd<Self>
52    + Add<Output = Self>
53    + Sub<Output = Self>
54    + Clone
55    + Copy
56    + Send
57    + Sync
58    + 'static
59    + ZeroOne;
60
61pub trait RangeBoundsExt<T: Idx>: RangeBounds<T> {
62    fn start(&self) -> Option<T> {
63        match self.start_bound() {
64            Bound::Included(v) => Some(*v),
65            Bound::Excluded(v) => Some(*v + ZeroOne::one()),
66            Bound::Unbounded => None,
67        }
68    }
69
70    fn end(&self) -> Option<T> {
71        match self.end_bound() {
72            Bound::Included(v) => Some(*v + ZeroOne::one()),
73            Bound::Excluded(v) => Some(*v),
74            Bound::Unbounded => None,
75        }
76    }
77
78    fn len(&self) -> Option<T> {
79        let start = self.start()?;
80        let end = self.end()?;
81        Some(end - start)
82    }
83
84    fn is_empty(&self) -> bool {
85        match self.len() {
86            Some(len) => len == ZeroOne::zero(),
87            None => false,
88        }
89    }
90
91    fn is_full(&self) -> bool {
92        self.start_bound() == Bound::Unbounded && self.end_bound() == Bound::Unbounded
93    }
94
95    fn map<F, R>(&self, f: F) -> (Bound<R>, Bound<R>)
96    where
97        F: Fn(&T) -> R,
98    {
99        (self.start_bound().map(&f), self.end_bound().map(&f))
100    }
101}
102
103impl<T: Idx, RB: RangeBounds<T>> RangeBoundsExt<T> for RB {}