use derive_more::From;
use derive_more::Into;
use num_traits::AsPrimitive;
use std::num::Wrapping;
#[derive(
Debug,
Clone,
Copy,
serde::Serialize,
serde::Deserialize,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
From,
Into,
derive_more::AsRef,
derive_more::Deref,
derive_more::Display,
)]
pub struct DhtLocation(pub Wrapping<u32>);
impl DhtLocation {
pub const MIN: Self = Self(Wrapping(u32::MIN));
pub const MAX: Self = Self(Wrapping(u32::MAX));
pub fn new(loc: u32) -> Self {
Self(Wrapping(loc))
}
pub fn as_u32(&self) -> u32 {
self.0 .0
}
pub fn as_i64(&self) -> i64 {
self.0 .0 as i64
}
#[cfg(any(test, feature = "test_utils"))]
pub fn as_i32(&self) -> i32 {
self.0 .0 as i32
}
}
#[cfg(any(test, feature = "test_utils"))]
impl From<i32> for DhtLocation {
fn from(i: i32) -> Self {
(i as u32).into()
}
}
#[cfg(any(feature = "sqlite", feature = "sqlite-encrypted"))]
impl rusqlite::ToSql for DhtLocation {
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput> {
Ok(rusqlite::types::ToSqlOutput::Owned(self.0 .0.into()))
}
}
pub const MAX_HALF_LENGTH: u32 = (u32::MAX / 2) + 1 + 1;
pub(crate) const U32_LEN: u64 = u32::MAX as u64 + 1;
impl From<u32> for DhtLocation {
fn from(a: u32) -> Self {
Self(Wrapping(a))
}
}
impl AsPrimitive<u32> for DhtLocation {
fn as_(self) -> u32 {
self.as_u32()
}
}
impl num_traits::Num for DhtLocation {
type FromStrRadixErr = <u32 as num_traits::Num>::FromStrRadixErr;
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
u32::from_str_radix(str, radix).map(Self::new)
}
}
impl std::ops::Add for DhtLocation {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl std::ops::Sub for DhtLocation {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0)
}
}
impl std::ops::Mul for DhtLocation {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self(self.0 * rhs.0)
}
}
impl std::ops::Div for DhtLocation {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
Self(self.0 / rhs.0)
}
}
impl std::ops::Rem for DhtLocation {
type Output = Self;
fn rem(self, rhs: Self) -> Self::Output {
Self(self.0 % rhs.0)
}
}
impl num_traits::Zero for DhtLocation {
fn zero() -> Self {
Self::new(0)
}
fn is_zero(&self) -> bool {
self.0 .0 == 0
}
}
impl num_traits::One for DhtLocation {
fn one() -> Self {
Self::new(1)
}
}
impl interval::ops::Width for DhtLocation {
type Output = u32;
fn max_value() -> Self {
u32::max_value().into()
}
fn min_value() -> Self {
u32::min_value().into()
}
fn width(lower: &Self, upper: &Self) -> Self::Output {
u32::width(&lower.0 .0, &upper.0 .0)
}
}
impl From<DhtLocation> for u32 {
fn from(l: DhtLocation) -> Self {
(l.0).0
}
}
pub(crate) fn loc_upscale(len: usize, v: i32) -> u32 {
let max = crate::FULL_LEN_F;
let lenf = len as f64;
let vf = v as f64;
(max / lenf * vf) as i64 as u32
}
pub(crate) fn loc_downscale(len: usize, d: DhtLocation) -> usize {
let max = crate::FULL_LEN_F;
let lenf = len as f64;
((lenf / max * (d.as_u32() as f64)) as usize) % len
}
#[test]
fn test_loc_upscale() {
let m = crate::FULL_LEN_F;
assert_eq!(loc_upscale(8, 0), DhtLocation::from(0).as_u32());
assert_eq!(
loc_upscale(8, 1),
DhtLocation::from((m / 8.0) as u32).as_u32()
);
assert_eq!(
loc_upscale(3, 1),
DhtLocation::from((m / 3.0) as u32).as_u32()
);
}