Skip to main content

irox_units/units/
datasize.rs

1// SPDX-License-Identifier: MIT
2// Copyright 2023 IROX Contributors
3
4//!
5//! Contains [`DataSize`] and [`DataSizeUnits`] - Physical Quantities of computer binary storage
6//!
7
8use crate::units::Unit;
9use core::fmt::{Display, Formatter};
10
11use super::FromUnits;
12
13///
14/// Physical unit of computer storage, a Byte is eight Bits.
15#[allow(clippy::cast_possible_truncation)]
16#[allow(clippy::integer_division)]
17#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
18pub enum DataSizeUnits {
19    /// Eight Bits
20    #[default]
21    Bytes,
22    /// 1000 Bytes
23    Kilobytes,
24    /// 1000 Kilobytes
25    Megabytes,
26    /// 1000 Megabytes
27    Gigabytes,
28    /// 1000 Gigabytes
29    Terabytes,
30    /// 1000 Terabytes
31    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    /// Creates a new DataSize quanitty
104    #[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
146/// Kilobyte to Byte factor
147pub const KB_TO_BYTES: u64 = 1000;
148/// Megabyte to Byte factor
149pub const MB_TO_BYTES: u64 = KB_TO_BYTES * 1000;
150/// Gigabyte to Byte factor
151pub const GB_TO_BYTES: u64 = MB_TO_BYTES * 1000;
152/// Terabyte to Byte factor
153pub const TB_TO_BYTES: u64 = GB_TO_BYTES * 1000;
154/// Petabyte to Byte factor
155pub const PB_TO_BYTES: u64 = TB_TO_BYTES * 1000;