nombytes/
range_type.rs

1// We need this here because we can't set it on the output of the serde macros
2#![allow(clippy::type_repetition_in_bounds)]
3
4use core::ops::{Range, RangeBounds, RangeFrom, RangeFull, RangeTo};
5use core::slice::SliceIndex;
6
7/// An enum that can hold all the `Range*` types without being generic/trait
8/// based. We need this type because `SliceIndex<T>` is implemented for the
9/// individual `Range*` types rather than for the `RangeBounds<T>` trait that
10/// we could've otherwise used.
11//
12// Because serde doesn't have good support for serializing the `Range*` types,
13// we'll have to do it ourselves. See `RangeTypeSerialized` for implementation.
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[cfg_attr(
16    feature = "serde",
17    serde(
18        into = "range_type_serde::RangeTypeSerialized<T>",
19        from = "range_type_serde::RangeTypeSerialized<T>",
20        bound(
21            serialize = "T: Clone, T: serde::Serialize",
22            deserialize = "T: Clone, T: serde::de::Deserialize<'de>",
23        )
24    )
25)]
26#[derive(Clone, Debug, Eq, PartialEq)]
27pub enum RangeType<T> {
28    /// Holds a [`RangeFull`] value
29    RangeFull(RangeFull),
30    /// Holds a [`RangeTo`] value
31    RangeTo(RangeTo<T>),
32    //RangeToInclusive(RangeToInclusive<T>),
33    /// Holds a [`RangeFrom`] value
34    RangeFrom(RangeFrom<T>),
35    /// Holds a [`Range`] value
36    Range(Range<T>),
37    //RangeInclusive(RangeInclusive<T>),
38}
39
40impl<T: Clone> RangeType<T> {
41    pub(crate) fn slice<'s, U>(&self, t: &'s [U]) -> &'s [U]
42    where
43        RangeTo<T>: SliceIndex<[U], Output = [U]>,
44        //RangeToInclusive<T>: SliceIndex<[U], Output = [U]>,
45        RangeFrom<T>: SliceIndex<[U], Output = [U]>,
46        Range<T>: SliceIndex<[U], Output = [U]>,
47        //RangeInclusive<T>: SliceIndex<[U], Output = [U]>,
48    {
49        match self.clone() {
50            Self::RangeFull(_) => t,
51            Self::RangeTo(r) => &t[r],
52            //Self::RangeToInclusive(r) => &t[r],
53            Self::RangeFrom(r) => &t[r],
54            Self::Range(r) => &t[r],
55            //Self::RangeInclusive(r) => &t[r],
56        }
57    }
58}
59
60impl<T> RangeBounds<T> for RangeType<T> {
61    fn start_bound(&self) -> core::ops::Bound<&T> {
62        match self {
63            RangeType::RangeFull(r) => r.start_bound(),
64            RangeType::RangeTo(r) => r.start_bound(),
65            //RangeType::RangeToInclusive(r) => r.start_bound(),
66            RangeType::RangeFrom(r) => r.start_bound(),
67            RangeType::Range(r) => r.start_bound(),
68            //RangeType::RangeInclusive(r) => r.start_bound(),
69        }
70    }
71
72    fn end_bound(&self) -> core::ops::Bound<&T> {
73        match self {
74            RangeType::RangeFull(r) => r.end_bound(),
75            RangeType::RangeTo(r) => r.end_bound(),
76            //RangeType::RangeToInclusive(r) => r.end_bound(),
77            RangeType::RangeFrom(r) => r.end_bound(),
78            RangeType::Range(r) => r.end_bound(),
79            //RangeType::RangeInclusive(r) => r.end_bound(),
80        }
81    }
82}
83
84macro_rules! range_to_from {
85    ($range:ident) => {
86        impl<T> From<$range<T>> for RangeType<T> {
87            fn from(range: $range<T>) -> Self {
88                Self::$range(range)
89            }
90        }
91    };
92}
93
94impl<T> From<RangeFull> for RangeType<T> {
95    fn from(range: RangeFull) -> Self {
96        Self::RangeFull(range)
97    }
98}
99range_to_from!(RangeTo);
100//range_to_from!(RangeToInclusive);
101range_to_from!(RangeFrom);
102range_to_from!(Range);
103//range_to_from!(RangeInclusive);
104
105#[cfg(feature = "serde")]
106mod range_type_serde {
107    use super::RangeType;
108    use core::ops::{Bound, RangeBounds};
109
110    #[derive(serde::Serialize, serde::Deserialize)]
111    pub(crate) struct RangeTypeSerialized<T> {
112        kind: u8,
113        #[serde(skip_serializing_if = "Option::is_none")]
114        start: Option<T>,
115        #[serde(skip_serializing_if = "Option::is_none")]
116        end: Option<T>,
117    }
118
119    impl<T: Clone> From<RangeType<T>> for RangeTypeSerialized<T> {
120        fn from(r: RangeType<T>) -> Self {
121            let (kind, start, end) = match &r {
122                RangeType::RangeFull(r) => (0, r.start_bound(), r.end_bound()),
123                RangeType::RangeTo(r) => (1, r.start_bound(), r.end_bound()),
124                RangeType::RangeFrom(_) => (3, r.start_bound(), r.end_bound()),
125                RangeType::Range(_) => (4, r.start_bound(), r.end_bound()),
126            };
127            let (start, end) = (bound_to_option(start), bound_to_option(end));
128
129            Self { kind, start, end }
130        }
131    }
132
133    impl<T> From<RangeTypeSerialized<T>> for RangeType<T> {
134        fn from(rs: RangeTypeSerialized<T>) -> Self {
135            let RangeTypeSerialized { kind, start, end } = rs;
136            match kind {
137                0 => RangeType::RangeFull(..),
138                1 => RangeType::RangeTo(..end.unwrap()),
139                3 => RangeType::RangeFrom(start.unwrap()..),
140                4 => RangeType::Range(start.unwrap()..end.unwrap()),
141                _ => unreachable!(),
142            }
143        }
144    }
145
146    #[inline]
147    fn bound_to_option<T: Clone>(b: Bound<&'_ T>) -> Option<T> {
148        match b {
149            Bound::Unbounded => None,
150            Bound::Included(x) | Bound::Excluded(x) => Some(x.clone()),
151        }
152    }
153
154    #[test]
155    fn ensure_roundtrip_works() {
156        #[inline]
157        fn roundtrip(rt: RangeType<usize>) {
158            let rt_serialized = serde_json::to_string(&rt).unwrap();
159            let rt_deserialized = serde_json::from_str(&rt_serialized).unwrap();
160
161            assert_eq!(rt, rt_deserialized);
162        }
163
164        roundtrip(RangeType::RangeFull(..));
165        roundtrip(RangeType::RangeTo(..42));
166        roundtrip(RangeType::RangeFrom(42..));
167        roundtrip(RangeType::Range(42..69));
168    }
169}