mtorrent-core 0.5.2

Fundamentals for building asynchronous BitTorrent clients
Documentation
use derive_more::{Display, From};
use std::cmp::Ordering;
use std::ops::{Add, AddAssign, Sub, SubAssign};

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Display, From)]
pub struct Seq(u16);

impl Seq {
    pub const ZERO: Self = Seq(0);
    pub const ONE: Self = Seq(1);

    pub fn increment(&mut self) {
        *self += Self::ONE;
    }
}

#[inline]
pub const fn seq(seq_nr: u16) -> Seq {
    Seq(seq_nr)
}

impl From<Seq> for u16 {
    fn from(value: Seq) -> Self {
        value.0
    }
}

impl Add for Seq {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        Seq(self.0.wrapping_add(rhs.0))
    }
}

impl Sub for Seq {
    type Output = Self;

    fn sub(self, rhs: Self) -> Self::Output {
        Seq(self.0.wrapping_sub(rhs.0))
    }
}

impl AddAssign for Seq {
    fn add_assign(&mut self, rhs: Self) {
        self.0 = self.0.wrapping_add(rhs.0);
    }
}

impl SubAssign for Seq {
    fn sub_assign(&mut self, rhs: Self) {
        self.0 = self.0.wrapping_sub(rhs.0);
    }
}

impl PartialOrd for Seq {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        fn first_before_second(first: Seq, second: Seq) -> bool {
            let Seq(distance) = second - first;
            distance <= u16::MAX / 2
        }

        if *self == *other {
            return Some(Ordering::Equal);
        }

        if first_before_second(*self, *other) && !first_before_second(*other, *self) {
            return Some(Ordering::Less);
        }

        if first_before_second(*other, *self) && !first_before_second(*self, *other) {
            return Some(Ordering::Greater);
        }

        None
    }
}

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

    #[test]
    fn test_seq_comparisons() {
        let seq1 = Seq(u16::MAX);
        let seq2 = Seq(0);
        assert!(seq1 < seq2);
        assert!(seq2 > seq1);

        let seq1 = Seq(u16::MAX - 1);
        let seq2 = Seq(u16::MAX);
        assert!(seq1 < seq2);
        assert!(seq2 > seq1);

        let seq1 = Seq(0);
        let seq2 = Seq(u16::MAX / 2);
        assert!(seq1 < seq2);
        assert!(seq2 > seq1);

        let seq1 = Seq(u16::MAX / 2 + 1);
        let seq2 = Seq(0);
        assert_eq!(seq1.partial_cmp(&seq2), None);
        assert_eq!(seq2.partial_cmp(&seq1), None);
    }
}