continuwuity/src/core/pdu/count.rs
Jason Volk 79c6b51860 renames for core pdu
Signed-off-by: Jason Volk <jason@zemos.net>
2024-11-08 06:09:04 +00:00

174 lines
3.9 KiB
Rust

#![allow(clippy::cast_possible_wrap, clippy::cast_sign_loss, clippy::as_conversions)]
use std::{cmp::Ordering, fmt, fmt::Display, str::FromStr};
use ruma::api::Direction;
use crate::{err, Error, Result};
#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)]
pub enum Count {
Normal(u64),
Backfilled(i64),
}
impl Count {
#[inline]
#[must_use]
pub fn from_unsigned(unsigned: u64) -> Self { Self::from_signed(unsigned as i64) }
#[inline]
#[must_use]
pub fn from_signed(signed: i64) -> Self {
match signed {
i64::MIN..=0 => Self::Backfilled(signed),
_ => Self::Normal(signed as u64),
}
}
#[inline]
#[must_use]
pub fn into_unsigned(self) -> u64 {
self.debug_assert_valid();
match self {
Self::Normal(i) => i,
Self::Backfilled(i) => i as u64,
}
}
#[inline]
#[must_use]
pub fn into_signed(self) -> i64 {
self.debug_assert_valid();
match self {
Self::Normal(i) => i as i64,
Self::Backfilled(i) => i,
}
}
#[inline]
#[must_use]
pub fn into_normal(self) -> Self {
self.debug_assert_valid();
match self {
Self::Normal(i) => Self::Normal(i),
Self::Backfilled(_) => Self::Normal(0),
}
}
#[inline]
pub fn checked_inc(self, dir: Direction) -> Result<Self, Error> {
match dir {
Direction::Forward => self.checked_add(1),
Direction::Backward => self.checked_sub(1),
}
}
#[inline]
pub fn checked_add(self, add: u64) -> Result<Self, Error> {
Ok(match self {
Self::Normal(i) => Self::Normal(
i.checked_add(add)
.ok_or_else(|| err!(Arithmetic("Count::Normal overflow")))?,
),
Self::Backfilled(i) => Self::Backfilled(
i.checked_add(add as i64)
.ok_or_else(|| err!(Arithmetic("Count::Backfilled overflow")))?,
),
})
}
#[inline]
pub fn checked_sub(self, sub: u64) -> Result<Self, Error> {
Ok(match self {
Self::Normal(i) => Self::Normal(
i.checked_sub(sub)
.ok_or_else(|| err!(Arithmetic("Count::Normal underflow")))?,
),
Self::Backfilled(i) => Self::Backfilled(
i.checked_sub(sub as i64)
.ok_or_else(|| err!(Arithmetic("Count::Backfilled underflow")))?,
),
})
}
#[inline]
#[must_use]
pub fn saturating_inc(self, dir: Direction) -> Self {
match dir {
Direction::Forward => self.saturating_add(1),
Direction::Backward => self.saturating_sub(1),
}
}
#[inline]
#[must_use]
pub fn saturating_add(self, add: u64) -> Self {
match self {
Self::Normal(i) => Self::Normal(i.saturating_add(add)),
Self::Backfilled(i) => Self::Backfilled(i.saturating_add(add as i64)),
}
}
#[inline]
#[must_use]
pub fn saturating_sub(self, sub: u64) -> Self {
match self {
Self::Normal(i) => Self::Normal(i.saturating_sub(sub)),
Self::Backfilled(i) => Self::Backfilled(i.saturating_sub(sub as i64)),
}
}
#[inline]
#[must_use]
pub const fn min() -> Self { Self::Backfilled(i64::MIN) }
#[inline]
#[must_use]
pub const fn max() -> Self { Self::Normal(i64::MAX as u64) }
#[inline]
pub(crate) fn debug_assert_valid(&self) {
if let Self::Backfilled(i) = self {
debug_assert!(*i <= 0, "Backfilled sequence must be negative");
}
}
}
impl Display for Count {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
self.debug_assert_valid();
match self {
Self::Normal(i) => write!(f, "{i}"),
Self::Backfilled(i) => write!(f, "{i}"),
}
}
}
impl From<i64> for Count {
#[inline]
fn from(signed: i64) -> Self { Self::from_signed(signed) }
}
impl From<u64> for Count {
#[inline]
fn from(unsigned: u64) -> Self { Self::from_unsigned(unsigned) }
}
impl FromStr for Count {
type Err = Error;
fn from_str(token: &str) -> Result<Self, Self::Err> { Ok(Self::from_signed(token.parse()?)) }
}
impl PartialOrd for Count {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}
impl Ord for Count {
fn cmp(&self, other: &Self) -> Ordering { self.into_signed().cmp(&other.into_signed()) }
}
impl Default for Count {
fn default() -> Self { Self::Normal(0) }
}