irox_units/units/
datasize.rs1use crate::units::Unit;
9use core::fmt::{Display, Formatter};
10
11use super::FromUnits;
12
13#[allow(clippy::cast_possible_truncation)]
16#[allow(clippy::integer_division)]
17#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
18pub enum DataSizeUnits {
19 #[default]
21 Bytes,
22 Kilobytes,
24 Megabytes,
26 Gigabytes,
28 Terabytes,
30 Petabytes,
32}
33
34macro_rules! from_units_datasize {
35 ($type:ident) => {
36 #[allow(clippy::integer_division)]
37 impl crate::units::FromUnits<$type> for DataSizeUnits {
38 fn from(&self, value: $type, units: Self) -> $type {
39 match self {
40 DataSizeUnits::Bytes => match units {
41 DataSizeUnits::Bytes => value,
42 DataSizeUnits::Kilobytes => value * KB_TO_BYTES as $type,
43 DataSizeUnits::Megabytes => value * MB_TO_BYTES as $type,
44 DataSizeUnits::Gigabytes => value * GB_TO_BYTES as $type,
45 DataSizeUnits::Terabytes => value * TB_TO_BYTES as $type,
46 DataSizeUnits::Petabytes => value * PB_TO_BYTES as $type,
47 },
48 DataSizeUnits::Kilobytes => match units {
49 DataSizeUnits::Bytes => value / KB_TO_BYTES as $type,
50 DataSizeUnits::Kilobytes => value,
51 DataSizeUnits::Megabytes => value * KB_TO_BYTES as $type,
52 DataSizeUnits::Gigabytes => value * MB_TO_BYTES as $type,
53 DataSizeUnits::Terabytes => value * GB_TO_BYTES as $type,
54 DataSizeUnits::Petabytes => value * TB_TO_BYTES as $type,
55 },
56 DataSizeUnits::Megabytes => match units {
57 DataSizeUnits::Bytes => value / MB_TO_BYTES as $type,
58 DataSizeUnits::Kilobytes => value / KB_TO_BYTES as $type,
59 DataSizeUnits::Megabytes => value,
60 DataSizeUnits::Gigabytes => value * KB_TO_BYTES as $type,
61 DataSizeUnits::Terabytes => value * MB_TO_BYTES as $type,
62 DataSizeUnits::Petabytes => value * GB_TO_BYTES as $type,
63 },
64 DataSizeUnits::Gigabytes => match units {
65 DataSizeUnits::Bytes => value / GB_TO_BYTES as $type,
66 DataSizeUnits::Kilobytes => value / MB_TO_BYTES as $type,
67 DataSizeUnits::Megabytes => value / KB_TO_BYTES as $type,
68 DataSizeUnits::Gigabytes => value,
69 DataSizeUnits::Terabytes => value * KB_TO_BYTES as $type,
70 DataSizeUnits::Petabytes => value * MB_TO_BYTES as $type,
71 },
72 DataSizeUnits::Terabytes => match units {
73 DataSizeUnits::Bytes => value / TB_TO_BYTES as $type,
74 DataSizeUnits::Kilobytes => value / GB_TO_BYTES as $type,
75 DataSizeUnits::Megabytes => value / MB_TO_BYTES as $type,
76 DataSizeUnits::Gigabytes => value / KB_TO_BYTES as $type,
77 DataSizeUnits::Terabytes => value,
78 DataSizeUnits::Petabytes => value * KB_TO_BYTES as $type,
79 },
80 DataSizeUnits::Petabytes => match units {
81 DataSizeUnits::Bytes => value / PB_TO_BYTES as $type,
82 DataSizeUnits::Kilobytes => value / TB_TO_BYTES as $type,
83 DataSizeUnits::Megabytes => value / GB_TO_BYTES as $type,
84 DataSizeUnits::Gigabytes => value / MB_TO_BYTES as $type,
85 DataSizeUnits::Terabytes => value / KB_TO_BYTES as $type,
86 DataSizeUnits::Petabytes => value,
87 },
88 }
89 }
90 }
91 };
92}
93
94from_units_datasize!(f32);
95from_units_datasize!(f64);
96from_units_datasize!(i64);
97from_units_datasize!(u64);
98from_units_datasize!(usize);
99
100basic_unit!(DataSize, DataSizeUnits, Bytes);
101
102impl DataSize {
103 #[must_use]
105 pub fn new_bytes(&self, value: u64) -> DataSize {
106 Self::new(value as f64, DataSizeUnits::Bytes)
107 }
108
109 #[must_use]
110 pub fn as_bytes(&self) -> u64 {
111 match self.units {
112 DataSizeUnits::Bytes => self.value as u64,
113 DataSizeUnits::Kilobytes => (self.value * KB_TO_BYTES as f64) as u64,
114 DataSizeUnits::Megabytes => (self.value * MB_TO_BYTES as f64) as u64,
115 DataSizeUnits::Gigabytes => (self.value * GB_TO_BYTES as f64) as u64,
116 DataSizeUnits::Terabytes => (self.value * TB_TO_BYTES as f64) as u64,
117 DataSizeUnits::Petabytes => (self.value * PB_TO_BYTES as f64) as u64,
118 }
119 }
120}
121
122impl Display for DataSize {
123 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
124 let bytes = self.as_bytes();
125 let frac = f.precision().unwrap_or(3);
126 if bytes < KB_TO_BYTES {
127 return write!(f, "{bytes} bytes");
128 } else if bytes < MB_TO_BYTES {
129 let val = bytes as f64 / KB_TO_BYTES as f64;
130 return write!(f, "{val:.frac$} KB");
131 } else if bytes < GB_TO_BYTES {
132 let val = bytes as f64 / MB_TO_BYTES as f64;
133 return write!(f, "{val:.frac$} MB");
134 } else if bytes < TB_TO_BYTES {
135 let val = bytes as f64 / GB_TO_BYTES as f64;
136 return write!(f, "{val:.frac$} GB");
137 } else if bytes < PB_TO_BYTES {
138 let val = bytes as f64 / TB_TO_BYTES as f64;
139 return write!(f, "{val:.frac$} TB");
140 }
141 let val = bytes as f64 / PB_TO_BYTES as f64;
142 write!(f, "{val:.frac$} PB")
143 }
144}
145
146pub const KB_TO_BYTES: u64 = 1000;
148pub const MB_TO_BYTES: u64 = KB_TO_BYTES * 1000;
150pub const GB_TO_BYTES: u64 = MB_TO_BYTES * 1000;
152pub const TB_TO_BYTES: u64 = GB_TO_BYTES * 1000;
154pub const PB_TO_BYTES: u64 = TB_TO_BYTES * 1000;