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
use std::cmp;

/// Number of bytes of interest.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub enum ByteCount {
    Finite(u64),
    Infinite,
    Unknown,
}
impl ByteCount {
    /// Returns `true` if this is `ByteCount::Finite(_)`, otherwise `false`.
    pub fn is_finite(&self) -> bool {
        if let ByteCount::Finite(_) = *self {
            true
        } else {
            false
        }
    }

    /// Returns `true` if this is `ByteCount::Infinite`, otherwise `false`.
    pub fn is_infinite(&self) -> bool {
        *self == ByteCount::Infinite
    }

    /// Returns `true` if this is `ByteCount::Unknown`, otherwise `false`.
    pub fn is_unknow(&self) -> bool {
        *self == ByteCount::Unknown
    }

    /// Tries to convert this `ByteCount` to an `u64` value.
    ///
    /// If it is not a `ByteCount::Finite(_)`,`None` will be returned.
    pub fn to_u64(&self) -> Option<u64> {
        if let ByteCount::Finite(n) = *self {
            Some(n)
        } else {
            None
        }
    }

    /// Adds two `ByteCount` instances for decoding (i.e., `Decode::requiring_bytes` method).
    ///
    /// # Rule
    ///
    /// ```text
    /// Finite(a) + Finite(b) = Finite(a + b)
    /// Infinite  + _         = Infinite
    /// _         + Infinite  = Infinite
    /// Unknown   + Unknown   = Unknown
    /// Finite(0) + Unknown   = Unknown
    /// Unknown   + Finite(0) = Unknown
    /// Finite(a) + Unknown   = Finite(a)
    /// Unknown   + Finite(b) = Finite(b)
    /// ```
    pub fn add_for_decoding(self, other: Self) -> Self {
        match (self, other) {
            (ByteCount::Finite(a), ByteCount::Finite(b)) => ByteCount::Finite(a + b),
            (ByteCount::Infinite, _) => ByteCount::Infinite,
            (_, ByteCount::Infinite) => ByteCount::Infinite,
            (ByteCount::Unknown, ByteCount::Unknown) => ByteCount::Unknown,
            (ByteCount::Finite(0), ByteCount::Unknown) => ByteCount::Unknown,
            (ByteCount::Unknown, ByteCount::Finite(0)) => ByteCount::Unknown,
            (ByteCount::Finite(a), ByteCount::Unknown) => ByteCount::Finite(a),
            (ByteCount::Unknown, ByteCount::Finite(b)) => ByteCount::Finite(b),
        }
    }

    /// Adds two `ByteCount` instances for encoding (i.e., `Encode::requiring_bytes` method).
    ///
    /// # Rule
    ///
    /// ```text
    /// Finite(a) + Finite(b) = Finite(a + b)
    /// Infinite  + _         = Infinite
    /// _         + Infinite  = Infinite
    /// Unknown   + _         = Unknown
    /// _         + Unknown   = Unknown
    /// ```
    pub fn add_for_encoding(self, other: Self) -> Self {
        match (self, other) {
            (ByteCount::Finite(a), ByteCount::Finite(b)) => ByteCount::Finite(a + b),
            (ByteCount::Infinite, _) => ByteCount::Infinite,
            (_, ByteCount::Infinite) => ByteCount::Infinite,
            (_, ByteCount::Unknown) => ByteCount::Unknown,
            (ByteCount::Unknown, _) => ByteCount::Unknown,
        }
    }
}
impl PartialOrd for ByteCount {
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        match (*self, *other) {
            (ByteCount::Finite(l), ByteCount::Finite(r)) => Some(l.cmp(&r)),
            (ByteCount::Unknown, _) | (_, ByteCount::Unknown) => None,
            (ByteCount::Infinite, ByteCount::Infinite) => Some(cmp::Ordering::Equal),
            (ByteCount::Infinite, _) => Some(cmp::Ordering::Greater),
            (_, ByteCount::Infinite) => Some(cmp::Ordering::Less),
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn it_works() {
        assert!(ByteCount::Finite(0).is_finite());
        assert!(ByteCount::Infinite.is_infinite());
        assert!(ByteCount::Unknown.is_unknow());

        assert_eq!(ByteCount::Finite(3).to_u64(), Some(3));
        assert_eq!(ByteCount::Infinite.to_u64(), None);
        assert_eq!(ByteCount::Unknown.to_u64(), None);

        assert!(ByteCount::Finite(1) < ByteCount::Finite(2));
        assert!(ByteCount::Finite(9) < ByteCount::Infinite);
        assert!(!(ByteCount::Infinite < ByteCount::Unknown));
        assert!(!(ByteCount::Unknown < ByteCount::Infinite));
        assert!(!(ByteCount::Unknown < ByteCount::Unknown));
        assert!(!(ByteCount::Unknown < ByteCount::Unknown));
    }
}