mod impls;
use {
alloc::borrow::Cow,
core::{
fmt::{self, Display, Formatter},
ops::{Bound, RangeBounds, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
},
crate::Semver,
};
const INCLUSIVE_OPEN: char = '[';
const INCLUSIVE_CLOSE: char = ']';
const EXCLUSIVE_OPEN: char = '(';
const EXCLUSIVE_CLOSE: char = ')';
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub struct Range {
start: Bound<Semver>,
end: Bound<Semver>,
}
impl Range {
pub fn is_empty(&self) -> bool {
match (&self.start, &self.end) {
(Bound::Included(start), Bound::Included(end)) => start > end,
(Bound::Included(start), Bound::Excluded(end)) => start >= end,
(Bound::Included(_), Bound::Unbounded) => false,
(Bound::Excluded(start), Bound::Included(end)) => start >= end,
(Bound::Excluded(start), Bound::Excluded(end)) => start >= end,
(Bound::Excluded(_), Bound::Unbounded) => false,
(Bound::Unbounded, _) => false,
}
}
}
impl From<&Semver> for Range {
fn from(semver: &Semver) -> Self {
Self::from(semver.clone())
}
}
impl From<Semver> for Range {
fn from(semver: Semver) -> Self {
Self {
start: Bound::Included(semver.clone()),
end: Bound::Included(semver),
}
}
}
impl From<core::ops::Range<Semver>> for Range {
fn from(range: core::ops::Range<Semver>) -> Self {
Self {
start: Bound::Included(range.start),
end: Bound::Excluded(range.end),
}
}
}
impl From<RangeInclusive<Semver>> for Range {
fn from(range: RangeInclusive<Semver>) -> Self {
let (start, end) = range.into_inner();
Self {
start: Bound::Included(start),
end: Bound::Included(end),
}
}
}
impl From<RangeFrom<Semver>> for Range {
fn from(range: RangeFrom<Semver>) -> Self {
Self {
start: Bound::Included(range.start),
end: Bound::Unbounded,
}
}
}
impl From<RangeTo<Semver>> for Range {
fn from(range: RangeTo<Semver>) -> Self {
Self {
start: Bound::Unbounded,
end: Bound::Excluded(range.end),
}
}
}
impl From<RangeToInclusive<Semver>> for Range {
fn from(range: RangeToInclusive<Semver>) -> Self {
Self {
start: Bound::Unbounded,
end: Bound::Included(range.end),
}
}
}
impl From<RangeFull> for Range {
fn from(_: RangeFull) -> Self {
Self {
start: Bound::Unbounded,
end: Bound::Unbounded,
}
}
}
impl Display for Range {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
let (open, start) = match &self.start {
Bound::Included(start) => (INCLUSIVE_OPEN, Cow::Owned(start.to_short_format())),
Bound::Excluded(start) => (EXCLUSIVE_OPEN, Cow::Owned(start.to_short_format())),
Bound::Unbounded => (INCLUSIVE_OPEN, Cow::Borrowed(concat!())),
};
let (close, end) = match &self.end {
Bound::Included(end) => (INCLUSIVE_CLOSE, Cow::Owned(end.to_short_format())),
Bound::Excluded(end) => (EXCLUSIVE_CLOSE, Cow::Owned(end.to_short_format())),
Bound::Unbounded => (INCLUSIVE_CLOSE, Cow::Borrowed(concat!())),
};
write!(
f,
concat!("{open}", "{start}", ',', ' ', "{end}", "{close}"),
open=open, start=start, end=end, close=close,
)
}
}
impl RangeBounds<Semver> for Range {
fn start_bound(&self) -> Bound<&Semver> {
match &self.start {
Bound::Included(start) => Bound::Included(start),
Bound::Excluded(start) => Bound::Excluded(start),
Bound::Unbounded => Bound::Unbounded,
}
}
fn end_bound(&self) -> Bound<&Semver> {
match &self.end {
Bound::Included(end) => Bound::Included(end),
Bound::Excluded(end) => Bound::Excluded(end),
Bound::Unbounded => Bound::Unbounded,
}
}
}