bevy_utils/memory_size.rs
1//! Types for representing the size of objects in memory.
2
3use core::fmt::Display;
4
5/// The size of an object in memory, in bytes.
6///
7/// The helper methods on this type use powers of 2 for conversions between units,
8/// consistent with the standards for memory reporting.
9///
10/// While it would technically be more correct to use e.g.
11/// "kibibytes" instead of "kilobytes", "mebibytes" instead of "megabytes", etc.,
12/// the more common terms are used here for familiarity and discoverability.
13#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
14#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
15pub struct MemorySize(pub u64);
16
17impl MemorySize {
18 /// Creates a new [`MemorySize`] from the given number of bytes.
19 ///
20 /// This method is provided for convenience,
21 /// as many other APIs in Rust use `usize` for sizes and counts.
22 /// To initialize this type with a `u64`, just call `MemorySize(bytes)` directly.
23 pub fn new(bytes: usize) -> Self {
24 MemorySize(bytes as u64)
25 }
26
27 /// Returns the size in bytes, as a `usize`.
28 ///
29 /// This method is provided for convenience,
30 /// as many other APIs in Rust use `usize` for sizes and counts.
31 /// To access the value as a `u64`, just use the `.0` field directly.
32 ///
33 /// 1 byte = 8 bits.
34 pub fn as_bytes(&self) -> usize {
35 self.0 as usize
36 }
37
38 /// Returns the size in kilobytes.
39 ///
40 /// 1 kilobyte = 1024 bytes.
41 pub fn as_kilobytes(&self) -> f64 {
42 self.0 as f64 / 1024.0
43 }
44
45 /// Returns the size in megabytes.
46 ///
47 /// 1 megabyte = 1024 kilobytes.
48 pub fn as_megabytes(&self) -> f64 {
49 self.0 as f64 / (1024.0 * 1024.0)
50 }
51
52 /// Returns the size in gigabytes.
53 ///
54 /// 1 gigabyte = 1024 megabytes.
55 pub fn as_gigabytes(&self) -> f64 {
56 self.0 as f64 / (1024.0 * 1024.0 * 1024.0)
57 }
58
59 /// Returns the size in terabytes.
60 ///
61 /// 1 terabyte = 1024 gigabytes.
62 pub fn as_terabytes(&self) -> f64 {
63 self.0 as f64 / (1024.0 * 1024.0 * 1024.0 * 1024.0)
64 }
65
66 /// Determine the appropriate unit for displaying the memory size.
67 ///
68 /// Units are chosen such that the value is at least 1 in that unit.
69 ///
70 /// This is used for formatting the memory size in a human-readable way,
71 /// such as in the [`Display`] implementation for this type.
72 pub fn appropriate_unit(&self) -> MemoryUnit {
73 if self.0 >= 1024 * 1024 * 1024 * 1024 {
74 MemoryUnit::Terabytes
75 } else if self.0 >= 1024 * 1024 * 1024 {
76 MemoryUnit::Gigabytes
77 } else if self.0 >= 1024 * 1024 {
78 MemoryUnit::Megabytes
79 } else if self.0 >= 1024 {
80 MemoryUnit::Kilobytes
81 } else {
82 MemoryUnit::Bytes
83 }
84 }
85}
86
87impl Display for MemorySize {
88 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
89 let unit = self.appropriate_unit();
90 match unit {
91 MemoryUnit::Bytes => write!(f, "{} B", self.as_bytes()),
92 MemoryUnit::Kilobytes => write!(f, "{:.2} KiB", self.as_kilobytes()),
93 MemoryUnit::Megabytes => write!(f, "{:.2} MiB", self.as_megabytes()),
94 MemoryUnit::Gigabytes => write!(f, "{:.2} GiB", self.as_gigabytes()),
95 MemoryUnit::Terabytes => write!(f, "{:.2} TiB", self.as_terabytes()),
96 }
97 }
98}
99
100/// Common units for representing memory size.
101///
102/// Used for determining the most appropriate unit to display a [`MemorySize`].
103#[derive(Clone, Copy, Debug, PartialEq, Eq)]
104pub enum MemoryUnit {
105 /// 8 bits
106 Bytes,
107 /// 1 kilobyte = 1024 bytes
108 Kilobytes,
109 /// 1 megabyte = 1024 kilobytes
110 Megabytes,
111 /// 1 gigabyte = 1024 megabytes
112 Gigabytes,
113 /// 1 terabyte = 1024 gigabytes
114 Terabytes,
115}