#![forbid(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
extern crate core;
#[cfg(feature = "derive")]
extern crate self as deepsize;
#[cfg(feature = "derive")]
pub use deepsize_derive::*;
use core::mem::{size_of, size_of_val};
#[cfg(test)]
mod test;
mod default_impls;
mod external_impls;
pub trait DeepSizeOf {
fn deep_size_of(&self) -> usize {
size_of_val(self) + self.deep_size_of_children(&mut Context::new())
}
fn deep_size_of_children(&self, context: &mut Context) -> usize;
}
#[cfg(not(feature = "std"))]
use alloc::collections::BTreeSet as GenericSet;
#[cfg(feature = "std")]
use std::collections::HashSet as GenericSet;
#[derive(Debug)]
pub struct Context {
arcs: GenericSet<usize>,
rcs: GenericSet<usize>,
}
impl Context {
fn new() -> Self {
Self {
arcs: GenericSet::new(),
rcs: GenericSet::new(),
}
}
fn add_arc<T: ?Sized>(&mut self, arc: &alloc::sync::Arc<T>) {
self.arcs.insert(&**arc as *const T as *const u8 as usize);
}
fn contains_arc<T: ?Sized>(&self, arc: &alloc::sync::Arc<T>) -> bool {
self.arcs
.contains(&(&**arc as *const T as *const u8 as usize))
}
fn add_rc<T: ?Sized>(&mut self, rc: &alloc::rc::Rc<T>) {
self.rcs.insert(&**rc as *const T as *const u8 as usize);
}
fn contains_rc<T: ?Sized>(&self, rc: &alloc::rc::Rc<T>) -> bool {
self.rcs
.contains(&(&**rc as *const T as *const u8 as usize))
}
}
impl<T> DeepSizeOf for alloc::vec::Vec<T>
where
T: DeepSizeOf,
{
fn deep_size_of_children(&self, context: &mut Context) -> usize {
self.iter()
.map(|child| child.deep_size_of_children(context))
.sum::<usize>()
+ self.capacity() * size_of::<T>()
}
}
impl<T> DeepSizeOf for alloc::collections::VecDeque<T>
where
T: DeepSizeOf,
{
fn deep_size_of_children(&self, context: &mut Context) -> usize {
self.iter()
.map(|child| child.deep_size_of_children(context))
.sum::<usize>()
+ self.capacity() * size_of::<T>() }
}
impl<T> DeepSizeOf for alloc::collections::LinkedList<T>
where
T: DeepSizeOf,
{
fn deep_size_of_children(&self, context: &mut Context) -> usize {
self.iter().fold(0, |sum, child| {
sum + size_of_val(child) + child.deep_size_of_children(context) + size_of::<usize>() * 2
})
}
}
#[cfg(feature = "std")]
impl<K, V, S> DeepSizeOf for std::collections::HashMap<K, V, S>
where
K: DeepSizeOf + Eq + std::hash::Hash,
V: DeepSizeOf,
S: std::hash::BuildHasher,
{
fn deep_size_of_children(&self, context: &mut Context) -> usize {
self.iter().fold(0, |sum, (key, val)| {
sum + key.deep_size_of_children(context) + val.deep_size_of_children(context)
}) + self.capacity() * size_of::<(K, V)>()
}
}
#[cfg(feature = "std")]
impl<K, S> DeepSizeOf for std::collections::HashSet<K, S>
where
K: DeepSizeOf + Eq + std::hash::Hash,
S: std::hash::BuildHasher,
{
fn deep_size_of_children(&self, context: &mut Context) -> usize {
self.iter()
.fold(0, |sum, key| sum + key.deep_size_of_children(context))
+ self.capacity() * size_of::<K>()
}
}
const BTREE_B: usize = 6;
const BTREE_MIN: usize = 2 * BTREE_B - 1;
const BTREE_MAX: usize = BTREE_B - 1;
#[cfg(feature = "std")]
impl<K: Ord + DeepSizeOf, V: DeepSizeOf> DeepSizeOf for std::collections::BTreeMap<K, V> {
fn deep_size_of_children(&self, context: &mut Context) -> usize {
let element_size = self.iter().fold(0, |sum, (k, v)| {
sum + k.deep_size_of_children(context) + v.deep_size_of_children(context)
});
let overhead = size_of::<(usize, u16, u16, [(K, V); BTREE_MAX], [usize; BTREE_B])>();
element_size + self.len() * overhead * 2 / (BTREE_MAX + BTREE_MIN)
}
}
#[cfg(feature = "std")]
impl<K: Ord + DeepSizeOf> DeepSizeOf for std::collections::BTreeSet<K> {
fn deep_size_of_children(&self, context: &mut Context) -> usize {
let element_size = self
.iter()
.fold(0, |sum, item| sum + item.deep_size_of_children(context));
let overhead = size_of::<(usize, u16, u16, [K; BTREE_MAX], [usize; BTREE_B])>();
element_size + self.len() * overhead * 2 / (BTREE_MAX + BTREE_MIN)
}
}
impl<T> DeepSizeOf for alloc::boxed::Box<T>
where
T: DeepSizeOf + ?Sized,
{
fn deep_size_of_children(&self, context: &mut Context) -> usize {
let val: &T = &*self;
size_of_val(val) + val.deep_size_of_children(context)
}
}
impl<T> DeepSizeOf for alloc::sync::Arc<T>
where
T: DeepSizeOf + ?Sized,
{
fn deep_size_of_children(&self, context: &mut Context) -> usize {
if context.contains_arc(self) {
0
} else {
context.add_arc(self);
let val: &T = &*self;
size_of_val(val) + val.deep_size_of_children(context)
}
}
}
impl<T> DeepSizeOf for alloc::rc::Rc<T>
where
T: DeepSizeOf + ?Sized,
{
fn deep_size_of_children(&self, context: &mut Context) -> usize {
if context.contains_rc(self) {
0
} else {
context.add_rc(self);
let val: &T = &*self;
size_of_val(val) + val.deep_size_of_children(context)
}
}
}
impl<T> DeepSizeOf for &T
where
T: DeepSizeOf + ?Sized,
{
fn deep_size_of_children(&self, _context: &mut Context) -> usize {
0
}
}
impl<T> DeepSizeOf for &mut T
where
T: DeepSizeOf + ?Sized,
{
fn deep_size_of_children(&self, _context: &mut Context) -> usize {
0
}
}
impl<T> DeepSizeOf for [T]
where
T: DeepSizeOf,
{
fn deep_size_of_children(&self, context: &mut Context) -> usize {
self.iter()
.map(|child| child.deep_size_of_children(context))
.sum()
}
}