use core::marker::PhantomPinned;
use core::num::*;
use core::{marker::PhantomData, sync::atomic::*};
use crate::{DbgFlags, FlatType, HashSet, MemDbgImpl, RefDisplay, impl_mem_size::MemSizeHelper};
#[cfg(not(feature = "std"))]
use alloc::collections::VecDeque;
#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, string::String, vec, vec::Vec};
#[cfg(feature = "std")]
use std::collections::VecDeque;
macro_rules! impl_mem_dbg {
($($ty:ty),*) => {$(
impl MemDbgImpl for $ty {}
)*};
}
macro_rules! impl_mem_dbg_for_deref {
($flag:ident, |$self:ident| $get_ptr:expr) => {
fn _mem_dbg_depth_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
field_name: Option<&str>,
is_last: bool,
padded_size: usize,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
if flags.contains(DbgFlags::$flag) {
let $self = self;
let ptr: usize = $get_ptr;
if dbg_refs.contains(&ptr) {
self._mem_dbg_depth_on_impl(
writer,
total_size,
max_depth,
prefix,
field_name,
is_last,
padded_size,
flags,
dbg_refs,
RefDisplay::BackReference(ptr),
)
} else {
dbg_refs.insert(ptr);
self._mem_dbg_depth_on_impl(
writer,
total_size,
max_depth,
prefix,
field_name,
is_last,
padded_size,
flags,
dbg_refs,
RefDisplay::FirstEncounter(ptr),
)
}
} else {
self._mem_dbg_depth_on_impl(
writer,
total_size,
max_depth,
prefix,
field_name,
is_last,
padded_size,
flags,
dbg_refs,
RefDisplay::None,
)
}
}
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
if flags.contains(DbgFlags::$flag) {
let inner = &**self;
let padded_size = core::mem::size_of_val(inner);
inner._mem_dbg_depth_on(
writer,
total_size,
max_depth,
prefix,
None,
is_last,
padded_size,
flags,
dbg_refs,
)
} else {
Ok(())
}
}
};
}
impl_mem_dbg! {
(), bool, char, f32, f64,
u8, u16, u32, u64, u128, usize,
i8, i16, i32, i64, i128, isize,
AtomicBool,
AtomicI8, AtomicI16, AtomicI32, AtomicIsize,
AtomicU8, AtomicU16, AtomicU32, AtomicUsize,
NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize,
NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
PhantomPinned, str, String
}
#[cfg(target_has_atomic = "64")]
impl_mem_dbg! { AtomicI64, AtomicU64 }
impl<T: ?Sized> MemDbgImpl for PhantomData<T> {}
impl<T: ?Sized + MemDbgImpl> MemDbgImpl for &'_ T {
impl_mem_dbg_for_deref!(FOLLOW_REFS, |s| *s as *const T as *const () as usize);
}
impl<T: ?Sized + MemDbgImpl> MemDbgImpl for &'_ mut T {
impl_mem_dbg_for_deref!(FOLLOW_REFS, |s| *s as *const T as *const () as usize);
}
impl<T: MemDbgImpl> MemDbgImpl for Option<T> {}
impl<T: MemDbgImpl, E: MemDbgImpl> MemDbgImpl for Result<T, E> {}
impl<T: ?Sized + MemDbgImpl> MemDbgImpl for Box<T> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
self.as_ref()._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
}
}
#[cfg(feature = "std")]
impl<T: MemDbgImpl> MemDbgImpl for std::rc::Rc<T> {
impl_mem_dbg_for_deref!(FOLLOW_RCS, |s| std::rc::Rc::as_ptr(s) as usize);
}
#[cfg(feature = "std")]
impl<T: MemDbgImpl> MemDbgImpl for std::sync::Arc<T> {
impl_mem_dbg_for_deref!(FOLLOW_RCS, |s| std::sync::Arc::as_ptr(s) as usize);
}
impl<T: FlatType + MemDbgImpl> MemDbgImpl for [T] where [T]: MemSizeHelper<<T as FlatType>::Flat> {}
impl<T: FlatType + MemDbgImpl, const N: usize> MemDbgImpl for [T; N] where
[T; N]: MemSizeHelper<<T as FlatType>::Flat>
{
}
impl<T: FlatType + MemDbgImpl> MemDbgImpl for Vec<T> where
Vec<T>: MemSizeHelper<<T as FlatType>::Flat>
{
}
impl<T: FlatType + MemDbgImpl> MemDbgImpl for VecDeque<T> where
VecDeque<T>: MemSizeHelper<<T as FlatType>::Flat>
{
}
macro_rules! impl_tuples_muncher {
() => {};
(($idx:tt => $ty:ident), $(($i:tt => $t:ident),)*) => {
impl_tuples_muncher!([($idx => $ty);] $(($i => $t),)*);
impl_tuples_muncher!($(($i => $t),)*);
};
([$(($accIdx: tt => $accTyp: ident);)+] ($idx:tt => $typ:ident), $( ($nidx:tt => $ntyp:ident), )*) => {
impl_tuples_muncher!([($idx => $typ); $(($accIdx => $accTyp); )*] $( ($nidx => $ntyp), ) *);
};
([($idx:tt => $ty:ident); $( ($nidx:tt => $nty:ident); )*]) => {
impl_tuples_muncher!([($idx => $ty); $(($nidx => $nty);)* ], ($ty, $($nty,)*));
};
([($idx:tt => $ty:ident); $( ($nidx:tt => $nty:ident); )*], $tty:ty) => {
impl<$ty: crate::MemSize + MemDbgImpl, $($nty: crate::MemSize + MemDbgImpl,)*> MemDbgImpl for ($ty, $($nty,)*) {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
_is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
let mut _max_idx = $idx;
$(_max_idx = _max_idx.max($nidx);)*
let mut id_sizes: Vec<(usize, usize)> = vec![];
let n;
{
id_sizes.push(($idx, core::mem::offset_of!($tty, $idx)));
$(id_sizes.push(($nidx, core::mem::offset_of!($tty, $nidx)));)*
n = id_sizes.len();
id_sizes.push((n, core::mem::size_of::<Self>()));
id_sizes.sort_by_key(|x| x.1);
for i in 0..n {
id_sizes[i].1 = id_sizes[i + 1].1 - id_sizes[i].1;
};
id_sizes.sort_by_key(|x| x.0);
}
self.$idx._mem_dbg_depth_on(writer, total_size, max_depth, prefix, Some(stringify!($idx)), $idx == _max_idx, id_sizes[$idx].1, flags, dbg_refs)?;
$(
self.$nidx._mem_dbg_depth_on(writer, total_size, max_depth, prefix, Some(stringify!($nidx)), $nidx == _max_idx, id_sizes[$nidx].1, flags, dbg_refs)?;
)*
Ok(())
}
}
};
}
impl_tuples_muncher!(
(9 => T9),
(8 => T8),
(7 => T7),
(6 => T6),
(5 => T5),
(4 => T4),
(3 => T3),
(2 => T2),
(1 => T1),
(0 => T0),
);
macro_rules! impl_mem_dbg_fn {
() => {
impl<R> MemDbgImpl for fn() -> R {}
};
($first:ident $(, $rest:ident)*) => {
impl<$first, $($rest,)* R> MemDbgImpl for fn($first, $($rest,)*) -> R {}
impl_mem_dbg_fn!($($rest),*);
};
}
impl_mem_dbg_fn!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
#[cfg(feature = "std")]
impl<K: FlatType> MemDbgImpl for std::collections::HashSet<K> where
std::collections::HashSet<K>: MemSizeHelper<<K as FlatType>::Flat>
{
}
#[cfg(feature = "std")]
impl<K: FlatType, V: FlatType> MemDbgImpl for std::collections::HashMap<K, V> where
std::collections::HashMap<K, V>:
crate::impl_mem_size::MemSizeHelper2<<K as FlatType>::Flat, <V as FlatType>::Flat>
{
}
#[cfg(feature = "std")]
impl<T: FlatType> MemDbgImpl for std::collections::BTreeSet<T> where
std::collections::BTreeSet<T>: MemSizeHelper<<T as FlatType>::Flat>
{
}
#[cfg(feature = "std")]
impl<K: FlatType, V: FlatType> MemDbgImpl for std::collections::BTreeMap<K, V> where
std::collections::BTreeMap<K, V>:
crate::impl_mem_size::MemSizeHelper2<<K as FlatType>::Flat, <V as FlatType>::Flat>
{
}
#[cfg(feature = "mmap-rs")]
impl_mem_dbg!(mmap_rs::Mmap, mmap_rs::MmapMut);
impl<H> MemDbgImpl for core::hash::BuildHasherDefault<H> {
}
#[cfg(feature = "std")]
impl MemDbgImpl for std::hash::DefaultHasher {
}
#[cfg(feature = "std")]
impl MemDbgImpl for std::collections::hash_map::RandomState {
}
#[cfg(feature = "std")]
impl MemDbgImpl for core::alloc::Layout {
}
impl<Idx: MemDbgImpl> MemDbgImpl for core::ops::Range<Idx> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
self.start._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)?;
self.end._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
}
}
impl<Idx: MemDbgImpl> MemDbgImpl for core::ops::RangeFrom<Idx> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
self.start._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
}
}
impl<Idx: MemDbgImpl> MemDbgImpl for core::ops::RangeInclusive<Idx> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
self.start()._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)?;
self.end()._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
}
}
impl<Idx: MemDbgImpl> MemDbgImpl for core::ops::RangeTo<Idx> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
self.end._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
}
}
impl<Idx: MemDbgImpl> MemDbgImpl for core::ops::RangeToInclusive<Idx> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
self.end._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
}
}
impl<T: ?Sized> MemDbgImpl for core::ptr::NonNull<T> {
}
#[cfg(feature = "rand")]
impl_mem_dbg!(
rand::rngs::SmallRng,
rand::rngs::StdRng,
rand::rngs::ThreadRng
);
struct MutablyBorrowed;
impl crate::FlatType for MutablyBorrowed {
type Flat = crate::True;
}
impl crate::MemSize for MutablyBorrowed {
fn mem_size_rec(
&self,
_flags: crate::SizeFlags,
_refs: &mut crate::HashMap<usize, usize>,
) -> usize {
0
}
}
impl MemDbgImpl for MutablyBorrowed {
fn _mem_dbg_depth_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
field_name: Option<&str>,
is_last: bool,
padded_size: usize,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
self._mem_dbg_depth_on_impl(
writer,
total_size,
max_depth,
prefix,
field_name,
is_last,
padded_size,
flags & !DbgFlags::TYPE_NAME,
dbg_refs,
RefDisplay::None,
)
}
}
impl<T: MemDbgImpl> MemDbgImpl for core::cell::RefCell<T> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
if let Ok(borrow) = self.try_borrow() {
borrow._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
} else {
MutablyBorrowed._mem_dbg_depth_on(
writer,
total_size,
max_depth,
prefix,
Some("<mutably borrowed>"),
true,
0,
flags,
dbg_refs,
)
}
}
}
impl<T: MemDbgImpl> MemDbgImpl for core::cell::Cell<T> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
let borrow = unsafe { &*self.as_ptr() };
borrow._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
}
}
impl<T: MemDbgImpl> MemDbgImpl for core::cell::UnsafeCell<T> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
let borrow = unsafe { &*self.get() };
borrow._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
}
}
#[cfg(feature = "std")]
impl<T: MemDbgImpl> MemDbgImpl for std::sync::Mutex<T> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
self.lock()
.unwrap_or_else(|e| e.into_inner())
._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
}
}
#[cfg(feature = "std")]
impl<T: MemDbgImpl> MemDbgImpl for std::sync::RwLock<T> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
self.read()
.unwrap_or_else(|e| e.into_inner())
._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
}
}
impl<T: MemDbgImpl> MemDbgImpl for core::cell::OnceCell<T> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
self.get()._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
}
}
#[cfg(feature = "std")]
impl<T: MemDbgImpl> MemDbgImpl for std::sync::MutexGuard<'_, T> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
use core::ops::Deref;
if flags.contains(DbgFlags::FOLLOW_REFS) {
self.deref()._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
} else {
Ok(())
}
}
}
#[cfg(feature = "std")]
impl<T: MemDbgImpl> MemDbgImpl for std::sync::RwLockReadGuard<'_, T> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
use core::ops::Deref;
if flags.contains(DbgFlags::FOLLOW_REFS) {
self.deref()._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
} else {
Ok(())
}
}
}
#[cfg(feature = "std")]
impl<T: MemDbgImpl> MemDbgImpl for std::sync::RwLockWriteGuard<'_, T> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
use core::ops::Deref;
if flags.contains(DbgFlags::FOLLOW_REFS) {
self.deref()._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
} else {
Ok(())
}
}
}
#[cfg(feature = "std")]
impl_mem_dbg!(
std::path::Path,
std::path::PathBuf,
std::ffi::OsStr,
std::ffi::OsString,
std::fs::File,
std::fs::OpenOptions,
std::fs::Metadata,
std::fs::FileTimes,
std::fs::FileType,
std::fs::Permissions
);
#[cfg(feature = "std")]
impl<T: MemDbgImpl + std::io::Read> MemDbgImpl for std::io::BufReader<T> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
self.get_ref()._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
}
}
#[cfg(feature = "std")]
impl<T: MemDbgImpl + std::io::Write> MemDbgImpl for std::io::BufWriter<T> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
self.get_ref()._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
}
}
#[cfg(feature = "std")]
impl<T: MemDbgImpl> MemDbgImpl for std::io::Cursor<T> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
self.get_ref()._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
}
}
#[cfg(feature = "maligned")]
impl_mem_dbg!(
maligned::A2,
maligned::A4,
maligned::A8,
maligned::A16,
maligned::A32,
maligned::A64,
maligned::A128,
maligned::A256,
maligned::A512
);
#[cfg(feature = "maligned")]
impl<A: maligned::Alignment, T: MemDbgImpl> MemDbgImpl for maligned::Aligned<A, T> {
fn _mem_dbg_rec_on(
&self,
writer: &mut impl core::fmt::Write,
total_size: usize,
max_depth: usize,
prefix: &mut String,
is_last: bool,
flags: DbgFlags,
dbg_refs: &mut HashSet<usize>,
) -> core::fmt::Result {
use core::ops::Deref;
self.deref()._mem_dbg_rec_on(
writer, total_size, max_depth, prefix, is_last, flags, dbg_refs,
)
}
}
#[cfg(feature = "half")]
impl_mem_dbg!(half::f16, half::bf16);