1mod impls;
30
31use {
32 alloc::borrow::Cow,
33 core::{
34 fmt::{self, Display, Formatter},
35 ops::{Bound, RangeBounds, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
36 },
37 crate::Semver,
38};
39
40const INCLUSIVE_OPEN: char = '[';
41const INCLUSIVE_CLOSE: char = ']';
42const EXCLUSIVE_OPEN: char = '(';
43const EXCLUSIVE_CLOSE: char = ')';
44
45#[derive(Debug, Eq, PartialEq, Hash, Clone)]
94pub struct Range {
95 start: Bound<Semver>,
96 end: Bound<Semver>,
97}
98
99impl Range {
100
101 pub fn is_empty(&self) -> bool {
103 match (&self.start, &self.end) {
104 (Bound::Included(start), Bound::Included(end)) => start > end,
105 (Bound::Included(start), Bound::Excluded(end)) => start >= end,
106 (Bound::Included(_), Bound::Unbounded) => false,
107
108 (Bound::Excluded(start), Bound::Included(end)) => start >= end,
109 (Bound::Excluded(start), Bound::Excluded(end)) => start >= end,
110 (Bound::Excluded(_), Bound::Unbounded) => false,
111
112 (Bound::Unbounded, _) => false,
113 }
114 }
115
116}
117
118impl From<&Semver> for Range {
119
120 fn from(semver: &Semver) -> Self {
121 Self::from(semver.clone())
122 }
123
124}
125
126impl From<Semver> for Range {
127
128 fn from(semver: Semver) -> Self {
129 Self {
130 start: Bound::Included(semver.clone()),
131 end: Bound::Included(semver),
132 }
133 }
134
135}
136
137impl From<core::ops::Range<Semver>> for Range {
138
139 fn from(range: core::ops::Range<Semver>) -> Self {
140 Self {
141 start: Bound::Included(range.start),
142 end: Bound::Excluded(range.end),
143 }
144 }
145
146}
147
148impl From<RangeInclusive<Semver>> for Range {
149
150 fn from(range: RangeInclusive<Semver>) -> Self {
151 let (start, end) = range.into_inner();
152 Self {
153 start: Bound::Included(start),
154 end: Bound::Included(end),
155 }
156 }
157
158}
159
160impl From<RangeFrom<Semver>> for Range {
161
162 fn from(range: RangeFrom<Semver>) -> Self {
163 Self {
164 start: Bound::Included(range.start),
165 end: Bound::Unbounded,
166 }
167 }
168
169}
170
171impl From<RangeTo<Semver>> for Range {
172
173 fn from(range: RangeTo<Semver>) -> Self {
174 Self {
175 start: Bound::Unbounded,
176 end: Bound::Excluded(range.end),
177 }
178 }
179
180}
181
182impl From<RangeToInclusive<Semver>> for Range {
183
184 fn from(range: RangeToInclusive<Semver>) -> Self {
185 Self {
186 start: Bound::Unbounded,
187 end: Bound::Included(range.end),
188 }
189 }
190
191}
192
193impl From<RangeFull> for Range {
194
195 fn from(_: RangeFull) -> Self {
196 Self {
197 start: Bound::Unbounded,
198 end: Bound::Unbounded,
199 }
200 }
201
202}
203
204impl Display for Range {
205
206 fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
207 let (open, start) = match &self.start {
208 Bound::Included(start) => (INCLUSIVE_OPEN, Cow::Owned(start.to_short_format())),
209 Bound::Excluded(start) => (EXCLUSIVE_OPEN, Cow::Owned(start.to_short_format())),
210 Bound::Unbounded => (INCLUSIVE_OPEN, Cow::Borrowed(concat!())),
211 };
212 let (close, end) = match &self.end {
213 Bound::Included(end) => (INCLUSIVE_CLOSE, Cow::Owned(end.to_short_format())),
214 Bound::Excluded(end) => (EXCLUSIVE_CLOSE, Cow::Owned(end.to_short_format())),
215 Bound::Unbounded => (INCLUSIVE_CLOSE, Cow::Borrowed(concat!())),
216 };
217 write!(
218 f,
219 concat!("{open}", "{start}", ',', ' ', "{end}", "{close}"),
220 open=open, start=start, end=end, close=close,
221 )
222 }
223
224}
225
226impl RangeBounds<Semver> for Range {
227
228 fn start_bound(&self) -> Bound<&Semver> {
229 match &self.start {
231 Bound::Included(start) => Bound::Included(start),
232 Bound::Excluded(start) => Bound::Excluded(start),
233 Bound::Unbounded => Bound::Unbounded,
234 }
235 }
236
237 fn end_bound(&self) -> Bound<&Semver> {
238 match &self.end {
240 Bound::Included(end) => Bound::Included(end),
241 Bound::Excluded(end) => Bound::Excluded(end),
242 Bound::Unbounded => Bound::Unbounded,
243 }
244 }
245
246}