1#![allow(clippy::type_repetition_in_bounds)]
3
4use core::ops::{Range, RangeBounds, RangeFrom, RangeFull, RangeTo};
5use core::slice::SliceIndex;
6
7#[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 RangeFull(RangeFull),
30 RangeTo(RangeTo<T>),
32 RangeFrom(RangeFrom<T>),
35 Range(Range<T>),
37 }
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 RangeFrom<T>: SliceIndex<[U], Output = [U]>,
46 Range<T>: SliceIndex<[U], Output = [U]>,
47 {
49 match self.clone() {
50 Self::RangeFull(_) => t,
51 Self::RangeTo(r) => &t[r],
52 Self::RangeFrom(r) => &t[r],
54 Self::Range(r) => &t[r],
55 }
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::RangeFrom(r) => r.start_bound(),
67 RangeType::Range(r) => r.start_bound(),
68 }
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::RangeFrom(r) => r.end_bound(),
78 RangeType::Range(r) => r.end_bound(),
79 }
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);
100range_to_from!(RangeFrom);
102range_to_from!(Range);
103#[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}