#[cfg(not(feature = "std"))]
use alloc::string::{String, ToString};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MemoryUsage {
pub number_allocs: u64,
pub bytes_in_use: u64,
pub bytes_padding: u64,
pub bytes_reserved: u64,
}
impl MemoryUsage {
pub fn combine(&self, other: MemoryUsage) -> MemoryUsage {
MemoryUsage {
number_allocs: self.number_allocs + other.number_allocs,
bytes_in_use: self.bytes_in_use + other.bytes_in_use,
bytes_padding: self.bytes_padding + other.bytes_padding,
bytes_reserved: self.bytes_reserved + other.bytes_reserved,
}
}
}
#[derive(new)]
pub(crate) struct BytesFormat {
bytes: u64,
}
impl core::fmt::Display for BytesFormat {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let unit = 1000;
if self.bytes < unit {
f.write_fmt(format_args!("{} B", self.bytes))
} else {
let size = self.bytes as f64;
let exp = match size.log(1000.0).floor() as usize {
0 => 1,
e => e,
};
let unit_prefix = "KMGTPEZY".as_bytes();
f.write_fmt(format_args!(
"{:.2} {}B",
(size / unit.pow(exp as u32) as f64),
unit_prefix[exp - 1] as char,
))
}
}
}
fn bytes_format(bytes: u64) -> String {
BytesFormat::new(bytes).to_string()
}
impl core::fmt::Display for MemoryUsage {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let usage_percentage = (self.bytes_in_use as f32 / self.bytes_reserved as f32) * 100.0;
let padding_percentage = (self.bytes_padding as f32 / self.bytes_in_use as f32) * 100.0;
writeln!(f, "Memory Usage Report:")?;
writeln!(f, " Number of allocations: {}", self.number_allocs)?;
writeln!(f, " Bytes in use: {}", bytes_format(self.bytes_in_use))?;
writeln!(
f,
" Bytes used for padding: {}",
bytes_format(self.bytes_padding)
)?;
writeln!(
f,
" Total bytes reserved: {}",
bytes_format(self.bytes_reserved)
)?;
writeln!(f, " Usage efficiency: {usage_percentage:.2}%")?;
writeln!(f, " Padding overhead: {padding_percentage:.2}%")
}
}
pub trait MemoryHandle<Binding>: Clone + Send + Sync + core::fmt::Debug {
fn can_mut(&self) -> bool;
fn binding(self) -> Binding;
}