1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// License: see LICENSE file at root directory of `master` branch

//! # Range

#![deprecated(note = "Beta")]

mod impls;
mod kind;

use {
    core::ops::RangeInclusive,

    crate::Semver,

    self::kind::Kind,
};

/// # Range
///
/// A range can be respresented in string, following these rules:
///
/// - Start and end are placed inside one of `[]`, `[)`..., separated by a comma.
/// - `[` and `]` are inclusive.
/// - `(` and `)` are exclusive.
/// - White spaces can be included. They will be ignored by parser.
/// - Length of the string must be equal to or smaller than 4096 bytes. It's for protection against flood attack.
///
/// ## Notes
///
/// Large ranges, such as `[,]`, `(,)`, [`start,`], [`,end`]... are not supported. Technically it's doable, but using such wild ranges in
/// software development is not recommended.
///
/// ## Examples
///
/// ```
/// use core::str::FromStr;
/// use dia_semver::{Range, Semver};
///
/// // An empty range
/// let range = Range::from(Semver::new(0, 1, 2)..Semver::new(0, 0, 0));
/// assert!(range.is_empty());
///
/// // Only one single semver
/// let range = Range::from(Semver::new(0, 1, 2));
/// assert!(range.contains(&Semver::new(0, 1, 2)));
/// assert!(range.contains(&Semver::new(0, 1, 3)) == false);
///
/// // Inclusive range
/// let range = Range::from_str("[0.1.2, 0.2.0-beta]")?;
/// assert!(range.contains(&Semver::new(0, 1, 3)));
/// assert!(range.contains(&Semver::from_str("0.2.0-alpha")?));
/// assert!(range.contains(&Semver::new(0, 2, 0)) == false);
///
/// // Exclusive range
/// let range = Range::from(Semver::new(0, 1, 2)..Semver::new(0, 2, 0));
/// assert!(range.contains(&Semver::new(0, 2, 0)) == false);
///
/// # dia_semver::Result::Ok(())
/// ```
#[derive(Debug)]
pub struct Range {
    kind: Kind,
}

impl Range {

    /// # Checks if this range is empty
    pub fn is_empty(&self) -> bool {
        match &self.kind {
            Kind::InclusiveInclusive(range) => range.is_empty(),
            Kind::InclusiveExclusive(range) => range.start() >= range.end(),
            Kind::ExclusiveExclusive(range) => range.start() >= range.end(),
            Kind::ExclusiveInclusive(range) => range.start() >= range.end(),
        }
    }

    /// # Checks if this range contains a semver
    pub fn contains(&self, semver: &Semver) -> bool {
        match &self.kind {
            Kind::InclusiveInclusive(range) => range.contains(semver),
            Kind::InclusiveExclusive(range) => semver >= range.start() && semver < range.end(),
            Kind::ExclusiveExclusive(range) => semver > range.start() && semver < range.end(),
            Kind::ExclusiveInclusive(range) => semver > range.start() && semver <= range.end(),
        }
    }

}

impl From<&Semver> for Range {

    fn from(semver: &Semver) -> Self {
        Self {
            kind: Kind::InclusiveInclusive(RangeInclusive::new(semver.clone(), semver.clone())),
        }
    }

}

impl From<Semver> for Range {

    fn from(semver: Semver) -> Self {
        Self::from(&semver)
    }

}

impl From<core::ops::Range<Semver>> for Range {

    fn from(range: core::ops::Range<Semver>) -> Self {
        Self {
            kind: Kind::InclusiveExclusive(RangeInclusive::new(range.start, range.end)),
        }
    }

}

impl From<RangeInclusive<Semver>> for Range {

    fn from(range: RangeInclusive<Semver>) -> Self {
        Self {
            kind: Kind::InclusiveInclusive(range),
        }
    }

}