use core::marker::{PhantomData, PhantomPinned};
use core::num::*;
use core::sync::atomic::*;
#[cfg(feature = "std")]
use core::ops::Deref;
use crate::{Boolean, False, FlatType, HashMap, MemSize, SizeFlags, True};
#[cfg(not(feature = "std"))]
use alloc::borrow::{Cow, ToOwned};
#[cfg(not(feature = "std"))]
use alloc::collections::{BinaryHeap, LinkedList, VecDeque};
#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, string::String, vec::Vec};
#[cfg(feature = "std")]
use std::borrow::{Cow, ToOwned};
#[cfg(feature = "std")]
use std::collections::{BinaryHeap, LinkedList, VecDeque};
macro_rules! impl_size_of {
($flat:ty; $($ty:ty),*) => {$(
impl FlatType for $ty {
type Flat = $flat;
}
impl MemSize for $ty {
#[inline(always)]
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
}
}
)*};
}
impl_size_of! {True;
(), 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
}
#[cfg(target_has_atomic = "64")]
impl_size_of! {True; AtomicI64, AtomicU64}
impl FlatType for str {
type Flat = False;
}
impl MemSize for str {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
self.len()
}
}
impl FlatType for String {
type Flat = False;
}
impl MemSize for String {
fn mem_size_rec(&self, flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
+ if flags.contains(SizeFlags::CAPACITY) {
self.capacity()
} else {
self.len()
}
}
}
impl<T: ?Sized> FlatType for PhantomData<T> {
type Flat = True;
}
impl<T: ?Sized> MemSize for PhantomData<T> {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
0
}
}
#[inline(always)]
fn record_followed_pointer_size<T: ?Sized + MemSize>(
value: &T,
ptr: usize,
flags: SizeFlags,
refs: &mut HashMap<usize, usize>,
) {
if flags.contains(SizeFlags::FOLLOW_REFS) && !refs.contains_key(&ptr) {
refs.insert(ptr, 0);
let inner_size = <T as MemSize>::mem_size_rec(value, flags, refs);
refs.insert(ptr, inner_size);
}
}
impl<T: ?Sized + MemSize> FlatType for &'_ T {
type Flat = False;
}
impl<T: ?Sized + MemSize> MemSize for &'_ T {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
record_followed_pointer_size(*self, *self as *const T as *const () as usize, flags, refs);
core::mem::size_of::<Self>()
}
}
impl<T: ?Sized + MemSize> FlatType for &'_ mut T {
type Flat = False;
}
impl<T: ?Sized + MemSize> MemSize for &'_ mut T {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
<&'_ T as MemSize>::mem_size_rec(&&**self, flags, refs)
}
}
impl<T: ?Sized> FlatType for *const T {
type Flat = True;
}
impl<T: ?Sized> MemSize for *const T {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
}
}
impl<T: ?Sized> FlatType for *mut T {
type Flat = True;
}
impl<T: ?Sized> MemSize for *mut T {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
}
}
impl<T: FlatType> FlatType for Option<T> {
type Flat = T::Flat;
}
impl<T: MemSize> MemSize for Option<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
+ self.as_ref().map_or(0, |x| {
<T as MemSize>::mem_size_rec(x, flags, refs) - core::mem::size_of::<T>()
})
}
}
impl<T: FlatType, E: FlatType> FlatType for Result<T, E> {
type Flat = <T::Flat as Boolean>::And<E::Flat>;
}
impl<T: MemSize, E: MemSize> MemSize for Result<T, E> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
+ match self {
Ok(t) => <T as MemSize>::mem_size_rec(t, flags, refs) - core::mem::size_of::<T>(),
Err(e) => <E as MemSize>::mem_size_rec(e, flags, refs) - core::mem::size_of::<E>(),
}
}
}
impl<B: FlatType, C: FlatType> FlatType for core::ops::ControlFlow<B, C> {
type Flat = <B::Flat as Boolean>::And<C::Flat>;
}
impl<B: MemSize, C: MemSize> MemSize for core::ops::ControlFlow<B, C> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
+ match self {
core::ops::ControlFlow::Break(b) => {
<B as MemSize>::mem_size_rec(b, flags, refs) - core::mem::size_of::<B>()
}
core::ops::ControlFlow::Continue(c) => {
<C as MemSize>::mem_size_rec(c, flags, refs) - core::mem::size_of::<C>()
}
}
}
}
impl<T: FlatType> FlatType for core::task::Poll<T> {
type Flat = T::Flat;
}
impl<T: MemSize> MemSize for core::task::Poll<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
+ match self {
core::task::Poll::Ready(t) => {
<T as MemSize>::mem_size_rec(t, flags, refs) - core::mem::size_of::<T>()
}
core::task::Poll::Pending => 0,
}
}
}
impl<T: FlatType> FlatType for core::ops::Bound<T> {
type Flat = T::Flat;
}
impl<T: MemSize> MemSize for core::ops::Bound<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
+ match self {
core::ops::Bound::Included(t) | core::ops::Bound::Excluded(t) => {
<T as MemSize>::mem_size_rec(t, flags, refs) - core::mem::size_of::<T>()
}
core::ops::Bound::Unbounded => 0,
}
}
}
impl<T: FlatType> FlatType for core::cmp::Reverse<T> {
type Flat = T::Flat;
}
impl<T: MemSize> MemSize for core::cmp::Reverse<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
<T as MemSize>::mem_size_rec(&self.0, flags, refs)
}
}
impl<T: ?Sized> FlatType for Box<T> {
type Flat = False;
}
impl<T: ?Sized + MemSize> MemSize for Box<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>() + <T as MemSize>::mem_size_rec(self.as_ref(), flags, refs)
}
}
impl<B: ToOwned + ?Sized> FlatType for Cow<'_, B> {
type Flat = False;
}
impl<B> MemSize for Cow<'_, B>
where
B: ToOwned + MemSize + ?Sized,
B::Owned: MemSize,
{
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
+ match self {
Cow::Borrowed(borrowed) => {
<&B as MemSize>::mem_size_rec(borrowed, flags, refs)
- core::mem::size_of::<&B>()
}
Cow::Owned(owned) => {
<B::Owned as MemSize>::mem_size_rec(owned, flags, refs)
- core::mem::size_of::<B::Owned>()
}
}
}
}
impl<P: FlatType> FlatType for core::pin::Pin<P> {
type Flat = P::Flat;
}
impl<P: MemSize> MemSize for core::pin::Pin<P> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
let pointer = unsafe { &*(self as *const core::pin::Pin<P> as *const P) };
<P as MemSize>::mem_size_rec(pointer, flags, refs)
}
}
#[repr(C, align(2))]
struct RcInner<T: ?Sized> {
_strong: core::cell::Cell<usize>,
_weak: core::cell::Cell<usize>,
_data: T,
}
#[inline(always)]
fn record_followed_shared_size<T: MemSize>(
inner: &T,
ptr: usize,
inner_header_size: usize,
flags: SizeFlags,
refs: &mut HashMap<usize, usize>,
) {
if !flags.contains(SizeFlags::FOLLOW_RCS) {
return;
}
if let Some(size) = refs.get(&ptr).copied() {
if size != 0 {
let inner_size = inner_header_size + <T as MemSize>::mem_size_rec(inner, flags, refs)
- core::mem::size_of::<T>();
if let Some(size) = refs.get_mut(&ptr) {
*size = core::cmp::max(*size, inner_size);
}
}
return;
}
refs.insert(ptr, 0);
let inner_size = inner_header_size + <T as MemSize>::mem_size_rec(inner, flags, refs)
- core::mem::size_of::<T>();
refs.insert(ptr, inner_size);
}
#[cfg(feature = "std")]
impl<T> FlatType for std::rc::Rc<T> {
type Flat = False;
}
#[cfg(feature = "std")]
impl<T: MemSize> MemSize for std::rc::Rc<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
record_followed_shared_size(
self.as_ref(),
std::rc::Rc::as_ptr(self) as usize,
core::mem::size_of::<RcInner<T>>(),
flags,
refs,
);
core::mem::size_of::<Self>()
}
}
#[cfg(not(feature = "std"))]
impl<T> FlatType for alloc::rc::Rc<T> {
type Flat = False;
}
#[cfg(not(feature = "std"))]
impl<T: MemSize> MemSize for alloc::rc::Rc<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
let ptr = alloc::rc::Rc::as_ptr(self) as usize;
record_followed_shared_size(
self.as_ref(),
ptr,
core::mem::size_of::<RcInner<T>>(),
flags,
refs,
);
core::mem::size_of::<Self>()
}
}
#[cfg(feature = "std")]
impl<T: ?Sized> FlatType for std::rc::Weak<T> {
type Flat = True;
}
#[cfg(feature = "std")]
impl<T: ?Sized> MemSize for std::rc::Weak<T> {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
}
}
#[cfg(not(feature = "std"))]
impl<T: ?Sized> FlatType for alloc::rc::Weak<T> {
type Flat = True;
}
#[cfg(not(feature = "std"))]
impl<T: ?Sized> MemSize for alloc::rc::Weak<T> {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
}
}
#[cfg(feature = "std")]
impl<T> FlatType for std::sync::Arc<T> {
type Flat = False;
}
#[repr(C, align(2))]
struct ArcInner<T: ?Sized> {
_strong: core::sync::atomic::AtomicUsize,
_weak: core::sync::atomic::AtomicUsize,
_data: T,
}
#[cfg(feature = "std")]
impl<T: MemSize> MemSize for std::sync::Arc<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
record_followed_shared_size(
self.as_ref(),
std::sync::Arc::as_ptr(self) as usize,
core::mem::size_of::<ArcInner<T>>(),
flags,
refs,
);
core::mem::size_of::<Self>()
}
}
#[cfg(all(not(feature = "std"), target_has_atomic = "ptr"))]
impl<T> FlatType for alloc::sync::Arc<T> {
type Flat = False;
}
#[cfg(all(not(feature = "std"), target_has_atomic = "ptr"))]
impl<T: MemSize> MemSize for alloc::sync::Arc<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
let ptr = alloc::sync::Arc::as_ptr(self) as usize;
record_followed_shared_size(
self.as_ref(),
ptr,
core::mem::size_of::<ArcInner<T>>(),
flags,
refs,
);
core::mem::size_of::<Self>()
}
}
#[cfg(feature = "std")]
impl<T: ?Sized> FlatType for std::sync::Weak<T> {
type Flat = True;
}
#[cfg(feature = "std")]
impl<T: ?Sized> MemSize for std::sync::Weak<T> {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
}
}
#[cfg(all(not(feature = "std"), target_has_atomic = "ptr"))]
impl<T: ?Sized> FlatType for alloc::sync::Weak<T> {
type Flat = True;
}
#[cfg(all(not(feature = "std"), target_has_atomic = "ptr"))]
impl<T: ?Sized> MemSize for alloc::sync::Weak<T> {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
}
}
#[inline(always)]
fn element_storage_size<'a, T, I>(
iter: I,
len: usize,
flags: SizeFlags,
refs: &mut HashMap<usize, usize>,
) -> usize
where
T: FlatType + MemSize + 'a,
I: IntoIterator<Item = &'a T>,
{
if <<T as FlatType>::Flat as Boolean>::VALUE {
len * core::mem::size_of::<T>()
} else {
iter.into_iter()
.map(|x| <T as MemSize>::mem_size_rec(x, flags, refs))
.sum()
}
}
#[inline(always)]
fn capacity_backed_storage_size<'a, T, I>(
iter: I,
len: usize,
capacity: usize,
flags: SizeFlags,
refs: &mut HashMap<usize, usize>,
) -> usize
where
T: FlatType + MemSize + 'a,
I: IntoIterator<Item = &'a T>,
{
if <<T as FlatType>::Flat as Boolean>::VALUE {
let len = if flags.contains(SizeFlags::CAPACITY) {
capacity
} else {
len
};
len * core::mem::size_of::<T>()
} else {
element_storage_size(iter, len, flags, refs)
+ if flags.contains(SizeFlags::CAPACITY) {
(capacity - len) * core::mem::size_of::<T>()
} else {
0
}
}
}
#[cfg(feature = "std")]
#[inline(always)]
fn element_heap_extras<'a, T, I>(
iter: I,
flags: SizeFlags,
refs: &mut HashMap<usize, usize>,
) -> usize
where
T: FlatType + MemSize + 'a,
I: IntoIterator<Item = &'a T>,
{
if <<T as FlatType>::Flat as Boolean>::VALUE {
0
} else {
iter.into_iter()
.map(|x| <T as MemSize>::mem_size_rec(x, flags, refs) - core::mem::size_of::<T>())
.sum()
}
}
#[cfg(feature = "std")]
#[inline(always)]
fn map_heap_extras<'a, K, V, I>(
iter: I,
flags: SizeFlags,
refs: &mut HashMap<usize, usize>,
) -> usize
where
K: FlatType + MemSize + 'a,
V: FlatType + MemSize + 'a,
I: IntoIterator<Item = (&'a K, &'a V)>,
{
let key_flat = <<K as FlatType>::Flat as Boolean>::VALUE;
let value_flat = <<V as FlatType>::Flat as Boolean>::VALUE;
if key_flat && value_flat {
0
} else {
iter.into_iter()
.map(|(k, v)| {
let key_extra = if key_flat {
0
} else {
<K as MemSize>::mem_size_rec(k, flags, refs) - core::mem::size_of::<K>()
};
let value_extra = if value_flat {
0
} else {
<V as MemSize>::mem_size_rec(v, flags, refs) - core::mem::size_of::<V>()
};
key_extra + value_extra
})
.sum()
}
}
impl<T: FlatType> FlatType for [T] {
type Flat = False;
}
impl<T: FlatType + MemSize> MemSize for [T] {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
element_storage_size(self.iter(), self.len(), flags, refs)
}
}
impl<T: FlatType, const N: usize> FlatType for [T; N] {
type Flat = T::Flat;
}
impl<T: FlatType + MemSize, const N: usize> MemSize for [T; N] {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
element_storage_size(self.iter(), N, flags, refs)
}
}
impl<T> FlatType for Vec<T> {
type Flat = False;
}
impl<T: FlatType + MemSize> MemSize for Vec<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
+ capacity_backed_storage_size(self.iter(), self.len(), self.capacity(), flags, refs)
}
}
impl<T> FlatType for BinaryHeap<T> {
type Flat = False;
}
impl<T: FlatType + MemSize> MemSize for BinaryHeap<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
+ capacity_backed_storage_size(self.iter(), self.len(), self.capacity(), flags, refs)
}
}
impl<T> FlatType for VecDeque<T> {
type Flat = False;
}
impl<T: FlatType + MemSize> MemSize for VecDeque<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
+ capacity_backed_storage_size(self.iter(), self.len(), self.capacity(), flags, refs)
}
}
#[doc(hidden)]
pub struct LinkedListNode<T> {
_next: Option<core::ptr::NonNull<LinkedListNode<T>>>,
_prev: Option<core::ptr::NonNull<LinkedListNode<T>>>,
_element: T,
}
impl<T> FlatType for LinkedList<T> {
type Flat = False;
}
impl<T: FlatType + MemSize> MemSize for LinkedList<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
+ if <<T as FlatType>::Flat as Boolean>::VALUE {
self.len() * core::mem::size_of::<LinkedListNode<T>>()
} else {
let per_node_overhead =
core::mem::size_of::<LinkedListNode<T>>() - core::mem::size_of::<T>();
self.iter()
.map(|x| <T as MemSize>::mem_size_rec(x, flags, refs) + per_node_overhead)
.sum::<usize>()
}
}
}
macro_rules! and_chain {
($single:ty) => { $single };
($first:ty, $($rest:ty),+) => { <$first as Boolean>::And<and_chain!($($rest),+)> };
}
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<$ty: FlatType, $($nty: FlatType,)*> FlatType for ($ty, $($nty,)*) {
type Flat = and_chain!(<$ty as FlatType>::Flat $(, <$nty as FlatType>::Flat)*);
}
impl<$ty: MemSize, $($nty: MemSize,)*> MemSize for ($ty, $($nty,)*) {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
let mut bytes = ::core::mem::size_of::<Self>();
bytes += <$ty as MemSize>::mem_size_rec(&self.$idx, flags, refs) - ::core::mem::size_of::<$ty>();
$( bytes += <$nty as MemSize>::mem_size_rec(&self.$nidx, flags, refs) - ::core::mem::size_of::<$nty>(); )*
bytes
}
}
impl<$ty, $($nty,)* R> FlatType for fn($ty, $($nty,)*) -> R {
type Flat = True;
}
impl<$ty, $($nty,)* R> MemSize for fn($ty, $($nty,)*) -> R {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
::core::mem::size_of::<Self>()
}
}
}
}
impl_tuples_muncher!(
(9 => T9),
(8 => T8),
(7 => T7),
(6 => T6),
(5 => T5),
(4 => T4),
(3 => T3),
(2 => T2),
(1 => T1),
(0 => T0),
);
impl<R> FlatType for fn() -> R {
type Flat = True;
}
impl<R> MemSize for fn() -> R {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
}
}
impl<Idx: FlatType> FlatType for core::ops::Range<Idx> {
type Flat = Idx::Flat;
}
impl<Idx: MemSize> MemSize for core::ops::Range<Idx> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
+ <Idx as MemSize>::mem_size_rec(&self.start, flags, refs)
+ <Idx as MemSize>::mem_size_rec(&self.end, flags, refs)
- 2 * core::mem::size_of::<Idx>()
}
}
impl<Idx: FlatType> FlatType for core::ops::RangeFrom<Idx> {
type Flat = Idx::Flat;
}
impl<Idx: MemSize> MemSize for core::ops::RangeFrom<Idx> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>() + <Idx as MemSize>::mem_size_rec(&self.start, flags, refs)
- core::mem::size_of::<Idx>()
}
}
impl<Idx: FlatType> FlatType for core::ops::RangeInclusive<Idx> {
type Flat = Idx::Flat;
}
impl<Idx: MemSize> MemSize for core::ops::RangeInclusive<Idx> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
+ <Idx as MemSize>::mem_size_rec(self.start(), flags, refs)
+ <Idx as MemSize>::mem_size_rec(self.end(), flags, refs)
- 2 * core::mem::size_of::<Idx>()
}
}
impl<Idx: FlatType> FlatType for core::ops::RangeTo<Idx> {
type Flat = Idx::Flat;
}
impl<Idx: MemSize> MemSize for core::ops::RangeTo<Idx> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>() + <Idx as MemSize>::mem_size_rec(&self.end, flags, refs)
- core::mem::size_of::<Idx>()
}
}
impl<Idx: FlatType> FlatType for core::ops::RangeToInclusive<Idx> {
type Flat = Idx::Flat;
}
impl<Idx: MemSize> MemSize for core::ops::RangeToInclusive<Idx> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>() + <Idx as MemSize>::mem_size_rec(&self.end, flags, refs)
- core::mem::size_of::<Idx>()
}
}
#[cfg(feature = "rand")]
impl_size_of!(True;
rand::rngs::SmallRng,
rand::rngs::ThreadRng,
rand::rngs::StdRng
);
impl<T: FlatType> FlatType for core::cell::RefCell<T> {
type Flat = T::Flat;
}
impl<T: MemSize> MemSize for core::cell::RefCell<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
if let Ok(borrow) = self.try_borrow() {
core::mem::size_of::<Self>() - core::mem::size_of::<T>()
+ <T as MemSize>::mem_size_rec(&*borrow, flags, refs)
} else {
core::mem::size_of::<Self>()
}
}
}
impl<T: ?Sized> FlatType for core::cell::Cell<T> {
type Flat = True;
}
impl<T: ?Sized> MemSize for core::cell::Cell<T> {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of_val(self)
}
}
impl<T: FlatType> FlatType for core::cell::OnceCell<T> {
type Flat = T::Flat;
}
impl<T: MemSize> MemSize for core::cell::OnceCell<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
let mut size = core::mem::size_of::<Self>();
if let Some(t) = self.get() {
size += <T as MemSize>::mem_size_rec(t, flags, refs) - core::mem::size_of::<T>();
}
size
}
}
#[cfg(feature = "std")]
impl<T: FlatType> FlatType for std::sync::OnceLock<T> {
type Flat = T::Flat;
}
#[cfg(feature = "std")]
impl<T: MemSize> MemSize for std::sync::OnceLock<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
let mut size = core::mem::size_of::<Self>();
if let Some(t) = self.get() {
size += <T as MemSize>::mem_size_rec(t, flags, refs) - core::mem::size_of::<T>();
}
size
}
}
impl<T: ?Sized> FlatType for core::cell::UnsafeCell<T> {
type Flat = True;
}
impl<T: ?Sized> MemSize for core::cell::UnsafeCell<T> {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of_val(self)
}
}
#[cfg(feature = "std")]
impl<T: FlatType> FlatType for std::sync::Mutex<T> {
type Flat = T::Flat;
}
#[cfg(feature = "std")]
impl<T: MemSize> MemSize for std::sync::Mutex<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
match self.try_lock() {
Ok(guard) => {
core::mem::size_of::<Self>() - core::mem::size_of::<T>()
+ <T as MemSize>::mem_size_rec(&guard, flags, refs)
}
Err(std::sync::TryLockError::Poisoned(err)) => {
let guard = err.into_inner();
core::mem::size_of::<Self>() - core::mem::size_of::<T>()
+ <T as MemSize>::mem_size_rec(&guard, flags, refs)
}
Err(std::sync::TryLockError::WouldBlock) => core::mem::size_of::<Self>(),
}
}
}
#[cfg(feature = "std")]
impl<T: FlatType> FlatType for std::sync::RwLock<T> {
type Flat = T::Flat;
}
#[cfg(feature = "std")]
impl<T: MemSize> MemSize for std::sync::RwLock<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
match self.try_read() {
Ok(guard) => {
core::mem::size_of::<Self>() - core::mem::size_of::<T>()
+ <T as MemSize>::mem_size_rec(&guard, flags, refs)
}
Err(std::sync::TryLockError::Poisoned(err)) => {
let guard = err.into_inner();
core::mem::size_of::<Self>() - core::mem::size_of::<T>()
+ <T as MemSize>::mem_size_rec(&guard, flags, refs)
}
Err(std::sync::TryLockError::WouldBlock) => core::mem::size_of::<Self>(),
}
}
}
#[cfg(feature = "std")]
#[inline(always)]
fn deref_pointer_size<M>(obj: &M, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize
where
M: Deref<Target: MemSize + Sized>,
{
let target = obj.deref();
let ptr = target as *const M::Target as *const () as usize;
record_followed_pointer_size(target, ptr, flags, refs);
core::mem::size_of::<M>()
}
#[cfg(feature = "std")]
impl<T> FlatType for std::sync::MutexGuard<'_, T> {
type Flat = False;
}
#[cfg(feature = "std")]
impl<T: MemSize> MemSize for std::sync::MutexGuard<'_, T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
deref_pointer_size(self, flags, refs)
}
}
#[cfg(feature = "std")]
impl<T> FlatType for std::sync::RwLockReadGuard<'_, T> {
type Flat = False;
}
#[cfg(feature = "std")]
impl<T: MemSize> MemSize for std::sync::RwLockReadGuard<'_, T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
deref_pointer_size(self, flags, refs)
}
}
#[cfg(feature = "std")]
impl<T> FlatType for std::sync::RwLockWriteGuard<'_, T> {
type Flat = False;
}
#[cfg(feature = "std")]
impl<T: MemSize> MemSize for std::sync::RwLockWriteGuard<'_, T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
deref_pointer_size(self, flags, refs)
}
}
#[cfg(feature = "std")]
impl FlatType for std::path::Path {
type Flat = False;
}
#[cfg(feature = "std")]
impl MemSize for std::path::Path {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
<std::ffi::OsStr as MemSize>::mem_size_rec(self.as_os_str(), flags, refs)
}
}
#[cfg(feature = "std")]
impl FlatType for std::path::PathBuf {
type Flat = False;
}
#[cfg(feature = "std")]
impl MemSize for std::path::PathBuf {
fn mem_size_rec(&self, flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
+ if flags.contains(SizeFlags::CAPACITY) {
self.capacity()
} else {
self.as_os_str().len()
}
}
}
#[cfg(feature = "std")]
impl FlatType for std::ffi::OsStr {
type Flat = False;
}
#[cfg(feature = "std")]
impl MemSize for std::ffi::OsStr {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
self.as_encoded_bytes().len()
}
}
#[cfg(feature = "std")]
impl FlatType for std::ffi::OsString {
type Flat = False;
}
#[cfg(feature = "std")]
impl MemSize for std::ffi::OsString {
fn mem_size_rec(&self, flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
+ if flags.contains(SizeFlags::CAPACITY) {
self.capacity()
} else {
self.len()
}
}
}
#[cfg(feature = "std")]
impl_size_of!(False;
std::fs::File,
std::fs::OpenOptions,
std::fs::Metadata,
std::fs::FileType,
std::fs::FileTimes,
std::fs::Permissions
);
#[cfg(feature = "std")]
impl<T> FlatType for std::io::BufReader<T> {
type Flat = False;
}
#[cfg(feature = "std")]
impl<T: MemSize + std::io::Read> MemSize for std::io::BufReader<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>() - core::mem::size_of::<T>()
+ self.capacity()
+ <T as MemSize>::mem_size_rec(self.get_ref(), flags, refs)
}
}
#[cfg(feature = "std")]
impl<T: std::io::Write> FlatType for std::io::BufWriter<T> {
type Flat = False;
}
#[cfg(feature = "std")]
impl<T: MemSize + std::io::Write> MemSize for std::io::BufWriter<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>() - core::mem::size_of::<T>()
+ self.capacity()
+ <T as MemSize>::mem_size_rec(self.get_ref(), flags, refs)
}
}
#[cfg(feature = "std")]
impl<T> FlatType for std::io::Cursor<T> {
type Flat = False;
}
#[cfg(feature = "std")]
impl<T: MemSize> MemSize for std::io::Cursor<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>() - core::mem::size_of::<T>()
+ <T as MemSize>::mem_size_rec(self.get_ref(), flags, refs)
}
}
impl_size_of!(True;
core::net::Ipv4Addr,
core::net::Ipv6Addr,
core::net::IpAddr,
core::net::SocketAddrV4,
core::net::SocketAddrV6,
core::net::SocketAddr
);
impl_size_of!(True; core::time::Duration);
#[cfg(feature = "std")]
impl_size_of!(True;
std::time::Instant,
std::time::SystemTime,
std::time::SystemTimeError
);
#[cfg(feature = "mmap-rs")]
impl FlatType for mmap_rs::Mmap {
type Flat = False;
}
#[cfg(feature = "mmap-rs")]
impl MemSize for mmap_rs::Mmap {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>() + self.len()
}
}
#[cfg(feature = "mmap-rs")]
impl FlatType for mmap_rs::MmapMut {
type Flat = False;
}
#[cfg(feature = "mmap-rs")]
impl MemSize for mmap_rs::MmapMut {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>() + self.len()
}
}
#[cfg(feature = "std")]
#[cfg(all(
any(target_arch = "x86_64", target_arch = "x86"),
target_feature = "sse2",
not(miri),
))]
const GROUP_WIDTH: usize = 16;
#[cfg(feature = "std")]
#[cfg(all(
not(all(
any(target_arch = "x86_64", target_arch = "x86"),
target_feature = "sse2",
not(miri),
)),
any(
target_pointer_width = "64",
target_arch = "aarch64",
target_arch = "x86_64",
target_arch = "wasm32",
),
))]
const GROUP_WIDTH: usize = 8;
#[cfg(feature = "std")]
#[cfg(all(
not(all(
any(target_arch = "x86_64", target_arch = "x86"),
target_feature = "sse2",
not(miri),
)),
not(any(
target_pointer_width = "64",
target_arch = "aarch64",
target_arch = "x86_64",
target_arch = "wasm32",
)),
))]
const GROUP_WIDTH: usize = 4;
#[cfg(feature = "std")]
#[inline(always)]
fn capacity_to_buckets<T>(cap: usize) -> Option<usize> {
if cap == 0 {
return Some(0);
}
if cap < 15 {
let min_cap = match (GROUP_WIDTH, core::mem::size_of::<T>()) {
(16, 0..=1) => 14,
(16, 2..=3) => 7,
(8, 0..=1) => 7,
_ => 3,
};
let cap = core::cmp::max(cap, min_cap);
return Some(if cap < 4 {
4
} else if cap < 8 {
8
} else {
16
});
}
let adjusted_cap = cap.checked_mul(8)? / 7;
Some(adjusted_cap.next_power_of_two())
}
#[cfg(feature = "std")]
#[inline(always)]
fn hash_table_allocation_size<T>(capacity: usize) -> usize {
let buckets = match capacity_to_buckets::<T>(capacity) {
Some(buckets) => buckets,
None => return usize::MAX,
};
if buckets == 0 {
return 0;
}
let ctrl_align = core::cmp::max(core::mem::align_of::<T>(), GROUP_WIDTH);
let bucket_bytes = match core::mem::size_of::<T>().checked_mul(buckets) {
Some(bucket_bytes) => bucket_bytes,
None => return usize::MAX,
};
let ctrl_offset = match bucket_bytes.checked_add(ctrl_align - 1) {
Some(offset) => offset & !(ctrl_align - 1),
None => return usize::MAX,
};
ctrl_offset
.checked_add(buckets)
.and_then(|size| size.checked_add(GROUP_WIDTH))
.unwrap_or(usize::MAX)
}
#[cfg(feature = "std")]
impl<T> FlatType for std::collections::HashSet<T> {
type Flat = False;
}
#[cfg(feature = "std")]
impl<T: FlatType + MemSize> MemSize for std::collections::HashSet<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
let heap_extras = element_heap_extras(self.iter(), flags, refs);
fix_set_for_capacity(self, heap_extras, flags)
}
}
#[cfg(feature = "std")]
fn fix_set_for_capacity<K>(
hash_set: &std::collections::HashSet<K>,
heap_extras: usize,
flags: SizeFlags,
) -> usize {
let capacity = if flags.contains(SizeFlags::CAPACITY) {
hash_set.capacity()
} else {
hash_set.len()
};
core::mem::size_of::<std::collections::HashSet<K>>()
+ hash_table_allocation_size::<K>(capacity)
+ heap_extras
}
#[cfg(feature = "std")]
impl<K, V> FlatType for std::collections::HashMap<K, V> {
type Flat = False;
}
#[cfg(feature = "std")]
impl<K: FlatType + MemSize, V: FlatType + MemSize> MemSize for std::collections::HashMap<K, V> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
let heap_extras = map_heap_extras(self.iter(), flags, refs);
fix_map_for_capacity(self, heap_extras, flags)
}
}
#[cfg(feature = "std")]
fn fix_map_for_capacity<K, V>(
hash_map: &std::collections::HashMap<K, V>,
heap_extras: usize,
flags: SizeFlags,
) -> usize {
let capacity = if flags.contains(SizeFlags::CAPACITY) {
hash_map.capacity()
} else {
hash_map.len()
};
core::mem::size_of::<std::collections::HashMap<K, V>>()
+ hash_table_allocation_size::<(K, V)>(capacity)
+ heap_extras
}
#[cfg(feature = "std")]
fn estimate_btree_size<K, V>(len: usize, item_heap_size: usize) -> usize {
if len == 0 {
return 0;
}
const B: usize = 6;
const CAPACITY: usize = 2 * B - 1;
let ptr_size = core::mem::size_of::<usize>();
let header_size = 2 * core::mem::size_of::<usize>();
let align_up = |size: usize, align: usize| -> usize { (size + align - 1) & !(align - 1) };
let k_size = core::mem::size_of::<K>();
let v_size = core::mem::size_of::<V>();
let mut leaf_size = header_size;
leaf_size = align_up(leaf_size, core::mem::align_of::<K>());
leaf_size += k_size * CAPACITY;
leaf_size = align_up(leaf_size, core::mem::align_of::<V>());
leaf_size += v_size * CAPACITY;
let mut internal_size = leaf_size;
internal_size = align_up(internal_size, core::mem::align_of::<usize>());
internal_size += ptr_size * (CAPACITY + 1);
const FILL: usize = B + 1;
const INTERNAL_FANOUT: usize = FILL + 1;
let heap_size = if len <= CAPACITY {
leaf_size
} else {
let leaf_count = len.div_ceil(FILL);
let mut total = leaf_count * leaf_size;
let mut level = leaf_count;
while level > 1 {
level = level.div_ceil(INTERNAL_FANOUT);
total += level * internal_size;
}
total
};
heap_size + item_heap_size
}
#[cfg(feature = "std")]
impl<T> FlatType for std::collections::BTreeSet<T> {
type Flat = False;
}
#[cfg(feature = "std")]
impl<T: FlatType + MemSize> MemSize for std::collections::BTreeSet<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
let item_heap_size = element_heap_extras(self.iter(), flags, refs);
core::mem::size_of::<std::collections::BTreeSet<T>>()
+ estimate_btree_size::<T, ()>(self.len(), item_heap_size)
}
}
#[cfg(feature = "std")]
impl<K, V> FlatType for std::collections::BTreeMap<K, V> {
type Flat = False;
}
#[cfg(feature = "std")]
impl<K: FlatType + MemSize, V: FlatType + MemSize> MemSize for std::collections::BTreeMap<K, V> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
let item_heap_size = map_heap_extras(self.iter(), flags, refs);
core::mem::size_of::<std::collections::BTreeMap<K, V>>()
+ estimate_btree_size::<K, V>(self.len(), item_heap_size)
}
}
impl<H> FlatType for core::hash::BuildHasherDefault<H> {
type Flat = True;
}
impl<H> MemSize for core::hash::BuildHasherDefault<H> {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
debug_assert_eq!(core::mem::size_of::<Self>(), 0);
0
}
}
#[cfg(feature = "std")]
impl FlatType for std::hash::DefaultHasher {
type Flat = True;
}
#[cfg(feature = "std")]
impl MemSize for std::hash::DefaultHasher {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
}
}
#[cfg(feature = "std")]
impl FlatType for std::collections::hash_map::RandomState {
type Flat = True;
}
#[cfg(feature = "std")]
impl MemSize for std::collections::hash_map::RandomState {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
}
}
impl_size_of!(True; core::alloc::Layout);
impl<T: ?Sized> FlatType for core::ptr::NonNull<T> {
type Flat = True;
}
impl<T: ?Sized> MemSize for core::ptr::NonNull<T> {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>()
}
}
#[cfg(feature = "maligned")]
impl_size_of!(True;
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: MemSize + FlatType> FlatType for maligned::Aligned<A, T> {
type Flat = T::Flat;
}
#[cfg(feature = "maligned")]
impl<A: maligned::Alignment, T: MemSize> MemSize for maligned::Aligned<A, T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
use core::ops::Deref;
core::mem::size_of::<Self>() - core::mem::size_of::<T>()
+ <T as MemSize>::mem_size_rec(self.deref(), flags, refs)
}
}
#[cfg(feature = "half")]
impl_size_of!(True; half::f16, half::bf16);
#[cfg(feature = "aliasable")]
mod aliasable {
use super::*;
use ::aliasable::AliasableMut;
use ::aliasable::boxed::AliasableBox;
use ::aliasable::string::AliasableString;
use ::aliasable::vec::AliasableVec;
use core::ops::Deref;
impl<T: ?Sized> FlatType for AliasableBox<T> {
type Flat = False;
}
impl<T: ?Sized + MemSize> MemSize for AliasableBox<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>() + <T as MemSize>::mem_size_rec(self.deref(), flags, refs)
}
}
impl<T> FlatType for AliasableVec<T> {
type Flat = False;
}
impl<T: FlatType + MemSize> MemSize for AliasableVec<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>() + <[T] as MemSize>::mem_size_rec(self.deref(), flags, refs)
}
}
impl FlatType for AliasableString {
type Flat = False;
}
impl MemSize for AliasableString {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
core::mem::size_of::<Self>() + self.deref().len()
}
}
impl<T: ?Sized + MemSize> FlatType for AliasableMut<'_, T> {
type Flat = False;
}
impl<T: ?Sized + MemSize> MemSize for AliasableMut<'_, T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
<&T as MemSize>::mem_size_rec(&self.deref(), flags, refs)
}
}
}
#[cfg(feature = "maybe-dangling")]
impl<T: FlatType> FlatType for maybe_dangling::MaybeDangling<T> {
type Flat = T::Flat;
}
#[cfg(feature = "maybe-dangling")]
impl<T: MemSize> MemSize for maybe_dangling::MaybeDangling<T> {
fn mem_size_rec(&self, flags: SizeFlags, refs: &mut HashMap<usize, usize>) -> usize {
use core::ops::Deref;
<T as MemSize>::mem_size_rec(self.deref(), flags, refs)
}
}