mirror of
https://github.com/kristoferssolo/traxor.git
synced 2025-10-21 20:10:35 +00:00
refactor(utils): use macros
This commit is contained in:
parent
9baf60c98b
commit
cad0ac00e2
@ -1,47 +1,29 @@
|
|||||||
|
use super::unit::{Unit, UnitError};
|
||||||
|
use crate::app::utils::unit::UnitDisplay;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
#[derive(Error, Debug, PartialEq)]
|
|
||||||
pub enum FileSizeError {
|
|
||||||
#[error("File size cannot be negative: {value}")]
|
|
||||||
NegativeSize { value: i64 },
|
|
||||||
#[error("File size value is too large: {value}")]
|
|
||||||
ValueTooLarge { value: f64 },
|
|
||||||
#[error("File size value is invalid: {reason}")]
|
|
||||||
InvalidValue { reason: String },
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||||
pub struct FileSize(u64);
|
pub struct FileSize(Unit);
|
||||||
|
|
||||||
impl FileSize {
|
impl FileSize {
|
||||||
pub const fn new(bytes: u64) -> Self {
|
pub fn new(bytes: u64) -> Self {
|
||||||
Self(bytes)
|
Self(Unit::new(bytes))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn bytes(&self) -> u64 {
|
impl Display for FileSize {
|
||||||
self.0
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
}
|
const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB", "PB"];
|
||||||
|
write!(f, "{}", UnitDisplay::new(&self.0, UNITS))
|
||||||
pub const fn kilobytes(kb: u64) -> Self {
|
|
||||||
Self(kb * 1024)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn megabytes(mb: u64) -> Self {
|
|
||||||
Self(mb * 1024 * 1024)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn gigabytes(gb: u64) -> Self {
|
|
||||||
Self(gb * 1024 * 1024 * 1024)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_from_unsigned {
|
macro_rules! impl_from_unsigned {
|
||||||
($($t:ty),*) => {
|
($type:ty, $($t:ty), *) => {
|
||||||
$(
|
$(
|
||||||
impl From<$t> for FileSize {
|
impl From<$t> for $type {
|
||||||
fn from(value: $t) -> Self {
|
fn from(value: $t) -> Self {
|
||||||
Self(value as u64)
|
Self(Unit::from(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
@ -49,61 +31,21 @@ macro_rules! impl_from_unsigned {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_try_from_signed {
|
macro_rules! impl_try_from_signed {
|
||||||
($($t:ty),*) => {
|
($type:ty, $error:ty, $($t:ty), *) => {
|
||||||
$(
|
$(
|
||||||
impl TryFrom<$t> for FileSize {
|
impl TryFrom<$t> for $type {
|
||||||
type Error = FileSizeError;
|
type Error = $error;
|
||||||
|
|
||||||
fn try_from(value: $t) -> Result<Self, Self::Error> {
|
fn try_from(value: $t) -> Result<Self, Self::Error> {
|
||||||
if value < 0 {
|
if value < 0 {
|
||||||
Err(FileSizeError::NegativeSize { value: value as i64 })
|
return Err(UnitError::NegativeValue { value: value as i64 });
|
||||||
} else {
|
|
||||||
Ok(Self(value as u64))
|
|
||||||
}
|
}
|
||||||
|
Ok(Self(Unit::try_from(value)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_from_unsigned!(u8, u16, u32, u64, usize);
|
impl_from_unsigned!(FileSize, u8, u16, u32, u64, usize);
|
||||||
impl_try_from_signed!(i8, i16, i32, i64, isize);
|
impl_try_from_signed!(FileSize, UnitError, i8, i16, i32, i64, isize);
|
||||||
|
|
||||||
impl Display for FileSize {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB", "PB"];
|
|
||||||
const THREASHOLD: f64 = 1024.0;
|
|
||||||
|
|
||||||
let bytes = self.0 as f64;
|
|
||||||
|
|
||||||
if bytes < THREASHOLD {
|
|
||||||
return write!(f, "{} {}", self.0, UNITS[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut size = bytes;
|
|
||||||
let mut unit_index = 0;
|
|
||||||
|
|
||||||
while size >= THREASHOLD && unit_index < UNITS.len() - 1 {
|
|
||||||
size /= THREASHOLD;
|
|
||||||
unit_index += 1;
|
|
||||||
}
|
|
||||||
if unit_index == 0 {
|
|
||||||
return write!(f, "{} {}", size as u64, UNITS[unit_index]);
|
|
||||||
}
|
|
||||||
write!(f, "{:.2} {}", size, UNITS[unit_index])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_file_size_display() {
|
|
||||||
assert_eq!(FileSize::new(512).to_string(), "512 B");
|
|
||||||
assert_eq!(FileSize::new(1536).to_string(), "1.50 KB");
|
|
||||||
assert_eq!(FileSize::new(1048576).to_string(), "1.00 MB");
|
|
||||||
assert_eq!(FileSize::new(1073741824).to_string(), "1.00 GB");
|
|
||||||
assert_eq!(FileSize::new(1099511627776).to_string(), "1.00 TB");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
pub mod filesize;
|
pub mod filesize;
|
||||||
pub mod netspeed;
|
pub mod netspeed;
|
||||||
|
pub mod unit;
|
||||||
|
|
||||||
use filesize::FileSize;
|
use filesize::FileSize;
|
||||||
use netspeed::NetSpeed;
|
use netspeed::NetSpeed;
|
||||||
@ -121,7 +122,9 @@ impl Wrapper for TorrentGetField {
|
|||||||
.map(|v| format!("{:?}", v))
|
.map(|v| format!("{:?}", v))
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
Self::Comment => torrent.comment.clone().unwrap_or_default(),
|
Self::Comment => torrent.comment.clone().unwrap_or_default(),
|
||||||
Self::CorruptEver => FileSize::from(torrent.corrupt_ever.unwrap_or(0)).to_string(),
|
Self::CorruptEver => FileSize::try_from(torrent.corrupt_ever.unwrap_or(0))
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string(),
|
||||||
Self::Creator => torrent.creator.clone().unwrap_or_default(),
|
Self::Creator => torrent.creator.clone().unwrap_or_default(),
|
||||||
Self::DateCreated => torrent
|
Self::DateCreated => torrent
|
||||||
.date_created
|
.date_created
|
||||||
@ -179,7 +182,7 @@ impl Wrapper for TorrentGetField {
|
|||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
Self::Group => torrent.group.clone().unwrap_or_default(),
|
Self::Group => torrent.group.clone().unwrap_or_default(),
|
||||||
Self::HashString => torrent.hash_string.clone().unwrap_or_default(),
|
Self::HashString => torrent.hash_string.clone().unwrap_or_default(),
|
||||||
Self::HaveUnchecked => todo!(),
|
Self::HaveUnchecked => FileSize::from(torrent.have_unchecked.unwrap_or(0)).to_string(),
|
||||||
Self::HaveValid => FileSize::from(torrent.have_valid.unwrap_or(0)).to_string(),
|
Self::HaveValid => FileSize::from(torrent.have_valid.unwrap_or(0)).to_string(),
|
||||||
Self::HonorsSessionLimits => torrent
|
Self::HonorsSessionLimits => torrent
|
||||||
.honors_session_limits
|
.honors_session_limits
|
||||||
@ -199,7 +202,9 @@ impl Wrapper for TorrentGetField {
|
|||||||
.map(|v| v.to_string())
|
.map(|v| v.to_string())
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
Self::Labels => torrent.labels.clone().unwrap_or_default().join(", "),
|
Self::Labels => torrent.labels.clone().unwrap_or_default().join(", "),
|
||||||
Self::LeftUntilDone => todo!(),
|
Self::LeftUntilDone => FileSize::try_from(torrent.left_until_done.unwrap_or(0))
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string(),
|
||||||
Self::MagnetLink => torrent.magnet_link.clone().unwrap_or_default(),
|
Self::MagnetLink => torrent.magnet_link.clone().unwrap_or_default(),
|
||||||
Self::ManualAnnounceTime => torrent
|
Self::ManualAnnounceTime => torrent
|
||||||
.manual_announce_time
|
.manual_announce_time
|
||||||
|
|||||||
@ -1,67 +1,29 @@
|
|||||||
|
use super::unit::{Unit, UnitError};
|
||||||
|
use crate::app::utils::unit::UnitDisplay;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
#[derive(Error, Debug, PartialEq)]
|
|
||||||
pub enum NetSpeedError {
|
|
||||||
#[error("Network speed cannot be negative: {value}")]
|
|
||||||
NegativeSpeed { value: i64 },
|
|
||||||
#[error("Network speed value is too large: {value}")]
|
|
||||||
ValueTooLarge { value: f64 },
|
|
||||||
#[error("Network speed value is invalid: {reason}")]
|
|
||||||
InvalidValue { reason: String },
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||||
pub struct NetSpeed(u64);
|
pub struct NetSpeed(Unit);
|
||||||
|
|
||||||
impl NetSpeed {
|
impl NetSpeed {
|
||||||
pub const fn new(bytes_per_second: u64) -> Self {
|
pub fn new(bytes_per_second: u64) -> Self {
|
||||||
Self(bytes_per_second)
|
Self(Unit::new(bytes_per_second))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn bytes_per_second(&self) -> u64 {
|
impl Display for NetSpeed {
|
||||||
self.0
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
}
|
const UNITS: &[&str] = &["B/s", "KB/s", "MB/s", "GB/s", "TB/s", "PB/s"];
|
||||||
|
write!(f, "{}", UnitDisplay::new(&self.0, UNITS))
|
||||||
pub const fn kilobytes_per_second(kb: u64) -> Self {
|
|
||||||
Self(kb * 1024)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn megabytes_per_second(mb: u64) -> Self {
|
|
||||||
Self(mb * 1024 * 1024)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn gigabytes_per_second(gb: u64) -> Self {
|
|
||||||
Self(gb * 1024 * 1024 * 1024)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn from_bits_per_second(bps: u64) -> Self {
|
|
||||||
NetSpeed(bps / 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn to_bits_per_second(&self) -> u64 {
|
|
||||||
self.0 * 8
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn from_kilobits_per_second(kbps: u64) -> Self {
|
|
||||||
NetSpeed(kbps * 1000 / 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn from_megabits_per_second(mbps: u64) -> Self {
|
|
||||||
NetSpeed(mbps * 1_000_000 / 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const fn from_gigabits_per_second(gbps: u64) -> Self {
|
|
||||||
NetSpeed(gbps * 1_000_000_000 / 8)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_from_unsigned {
|
macro_rules! impl_from_unsigned {
|
||||||
($($t:ty),*) => {
|
($type:ty, $($t:ty), *) => {
|
||||||
$(
|
$(
|
||||||
impl From<$t> for NetSpeed {
|
impl From<$t> for $type {
|
||||||
fn from(value: $t) -> Self {
|
fn from(value: $t) -> Self {
|
||||||
Self(value as u64)
|
Self(Unit::from(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
@ -69,91 +31,21 @@ macro_rules! impl_from_unsigned {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_try_from_signed {
|
macro_rules! impl_try_from_signed {
|
||||||
($($t:ty),*) => {
|
($type:ty, $error:ty, $($t:ty), *) => {
|
||||||
$(
|
$(
|
||||||
impl TryFrom<$t> for NetSpeed {
|
impl TryFrom<$t> for $type {
|
||||||
type Error = NetSpeedError;
|
type Error = $error;
|
||||||
|
|
||||||
fn try_from(value: $t) -> Result<Self, Self::Error> {
|
fn try_from(value: $t) -> Result<Self, Self::Error> {
|
||||||
if value < 0 {
|
if value < 0 {
|
||||||
Err(NetSpeedError::NegativeSpeed { value: value as i64 })
|
return Err(UnitError::NegativeValue { value: value as i64 });
|
||||||
} else {
|
|
||||||
Ok(Self(value as u64))
|
|
||||||
}
|
}
|
||||||
|
Ok(Self(Unit::try_from(value)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_from_unsigned!(u8, u16, u32, u64, usize);
|
impl_from_unsigned!(NetSpeed, u8, u16, u32, u64, usize);
|
||||||
impl_try_from_signed!(i8, i16, i32, i64, isize);
|
impl_try_from_signed!(NetSpeed, UnitError, i8, i16, i32, i64, isize);
|
||||||
|
|
||||||
impl Display for NetSpeed {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
const UNITS: &[&str] = &["B/s", "KB/s", "MB/s", "GB/s", "TB/s", "PB/s"];
|
|
||||||
const THREASHOLD: f64 = 1024.0;
|
|
||||||
|
|
||||||
let bytes_per_second = self.0 as f64;
|
|
||||||
|
|
||||||
if bytes_per_second < THREASHOLD {
|
|
||||||
return write!(f, "{} {}", self.0, UNITS[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut size = bytes_per_second;
|
|
||||||
let mut unit_index = 0;
|
|
||||||
|
|
||||||
while size >= THREASHOLD && unit_index < UNITS.len() - 1 {
|
|
||||||
size /= THREASHOLD;
|
|
||||||
unit_index += 1;
|
|
||||||
}
|
|
||||||
if unit_index == 0 {
|
|
||||||
return write!(f, "{} {}", size as u64, UNITS[unit_index]);
|
|
||||||
}
|
|
||||||
write!(f, "{:.2} {}", size, UNITS[unit_index])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_net_speed_display() {
|
|
||||||
assert_eq!(NetSpeed::new(512).to_string(), "512 B/s");
|
|
||||||
assert_eq!(NetSpeed::new(1536).to_string(), "1.50 KB/s");
|
|
||||||
assert_eq!(NetSpeed::new(1048576).to_string(), "1.00 MB/s");
|
|
||||||
assert_eq!(NetSpeed::new(1073741824).to_string(), "1.00 GB/s");
|
|
||||||
assert_eq!(NetSpeed::new(1099511627776).to_string(), "1.00 TB/s");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_bits_conversion() {
|
|
||||||
let speed = NetSpeed::from_bits_per_second(8000);
|
|
||||||
assert_eq!(speed.bytes_per_second(), 1000);
|
|
||||||
assert_eq!(speed.to_bits_per_second(), 8000);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_network_units() {
|
|
||||||
// 1 Mbps = 125,000 bytes per second
|
|
||||||
let speed = NetSpeed::from_megabits_per_second(1);
|
|
||||||
assert_eq!(speed.bytes_per_second(), 125_000);
|
|
||||||
|
|
||||||
// 1 Gbps = 125,000,000 bytes per second
|
|
||||||
let speed = NetSpeed::from_gigabits_per_second(1);
|
|
||||||
assert_eq!(speed.bytes_per_second(), 125_000_000);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_try_from_i64() {
|
|
||||||
assert_eq!(
|
|
||||||
NetSpeed::try_from(1000i64).unwrap().bytes_per_second(),
|
|
||||||
1000
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
NetSpeed::try_from(-100i64),
|
|
||||||
Err(NetSpeedError::NegativeSpeed { value: -100 })
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
89
src/app/utils/unit.rs
Normal file
89
src/app/utils/unit.rs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
use std::fmt::Display;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug, PartialEq)]
|
||||||
|
pub enum UnitError {
|
||||||
|
#[error("Value cannot be negative: {value}")]
|
||||||
|
NegativeValue { value: i64 },
|
||||||
|
#[error("Value is too large: {value}")]
|
||||||
|
ValueTooLarge { value: f64 },
|
||||||
|
#[error("Value is invalid: {reason}")]
|
||||||
|
InvalidValue { reason: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||||
|
pub struct Unit(u64);
|
||||||
|
|
||||||
|
impl Unit {
|
||||||
|
pub const fn new(value: u64) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn value(&self) -> u64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UnitDisplay<'a> {
|
||||||
|
unit: &'a Unit,
|
||||||
|
units: &'a [&'a str],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> UnitDisplay<'a> {
|
||||||
|
pub fn new(unit: &'a Unit, units: &'a [&'a str]) -> Self {
|
||||||
|
Self { unit, units }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Display for UnitDisplay<'a> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
const THREASHOLD: f64 = 1024.0;
|
||||||
|
|
||||||
|
let value = self.unit.0 as f64;
|
||||||
|
|
||||||
|
if value < THREASHOLD {
|
||||||
|
return write!(f, "{} {}", self.unit.0, self.units[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut size = value;
|
||||||
|
let mut unit_index = 0;
|
||||||
|
|
||||||
|
while size >= THREASHOLD && unit_index < self.units.len() - 1 {
|
||||||
|
size /= THREASHOLD;
|
||||||
|
unit_index += 1;
|
||||||
|
}
|
||||||
|
write!(f, "{:.2} {}", size, self.units[unit_index])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_from_unsigned {
|
||||||
|
($type:ty, $($t:ty), *) => {
|
||||||
|
$(
|
||||||
|
impl From<$t> for $type {
|
||||||
|
fn from(value: $t) -> Self {
|
||||||
|
Self(value as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_try_from_signed {
|
||||||
|
($type:ty, $error:ty, $($t:ty), *) => {
|
||||||
|
$(
|
||||||
|
impl TryFrom<$t> for $type {
|
||||||
|
type Error = $error;
|
||||||
|
|
||||||
|
fn try_from(value: $t) -> Result<Self, Self::Error> {
|
||||||
|
if value < 0 {
|
||||||
|
return Err(UnitError::NegativeValue { value: value as i64 });
|
||||||
|
}
|
||||||
|
Ok(Self(value as u64))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_from_unsigned!(Unit, u8, u16, u32, u64, usize);
|
||||||
|
impl_try_from_signed!(Unit, UnitError, i8, i16, i32, i64, isize);
|
||||||
Loading…
Reference in New Issue
Block a user