use std::mem;
use crate::impls::common::UNUSED_CAPACITY_NAME;
use crate::key::Key;
pub(crate) trait MeasureVisitorImpl {
fn enter_impl<'a>(&'a mut self, name: Key, size: usize);
fn enter_unique_impl(&mut self, name: Key, size: usize);
#[must_use]
fn enter_shared_impl(&mut self, name: Key, size: usize, ptr: *const ()) -> bool;
fn exit_impl(&mut self);
}
#[must_use] pub struct Visitor<'a> {
pub(crate) visitor: &'a mut dyn MeasureVisitorImpl,
}
impl<'a> Drop for Visitor<'a> {
fn drop(&mut self) {
self.visitor.exit_impl();
}
}
impl<'a> Visitor<'a> {
pub fn enter<'b>(&'b mut self, name: Key, size: usize) -> Visitor<'b>
where
'a: 'b,
{
self.visitor.enter_impl(name, size);
Visitor {
visitor: self.visitor,
}
}
pub fn enter_unique<'b>(&'b mut self, name: Key, size: usize) -> Visitor<'b>
where
'a: 'b,
{
self.visitor.enter_unique_impl(name, size);
Visitor {
visitor: self.visitor,
}
}
pub fn enter_shared<'b>(
&'b mut self,
name: Key,
size: usize,
ptr: *const (),
) -> Option<Visitor<'b>>
where
'a: 'b,
{
if self.visitor.enter_shared_impl(name, size, ptr) {
Some(Visitor {
visitor: self.visitor,
})
} else {
None
}
}
pub fn enter_self_sized<'b, T>(&'b mut self) -> Visitor<'b>
where
'a: 'b,
{
self.enter(Key::for_type_name::<T>(), mem::size_of::<T>())
}
pub fn visit_simple<'b>(&'b mut self, name: Key, size: usize)
where
'a: 'b,
{
self.enter(name, size).exit();
}
pub fn visit_simple_sized<'b, T>(&'b mut self)
where
'a: 'b,
{
self.enter_self_sized::<T>().exit();
}
pub fn visit_field<'b, T: Allocative>(&'b mut self, name: Key, field: &T)
where
'a: 'b,
{
let mut visitor = self.enter(name, mem::size_of::<T>());
field.visit(&mut visitor);
visitor.exit();
}
pub fn visit_slice<'b, T: Allocative>(&'b mut self, slice: &[T])
where
'a: 'b,
{
self.visit_iter(slice);
}
pub fn visit_iter<'b, 'i, T: Allocative + 'i, I: IntoIterator<Item = &'i T>>(
&'b mut self,
iter: I,
) where
'a: 'b,
{
if !mem::needs_drop::<T>() || mem::size_of::<T>() == 0 {
self.visit_simple(
Key::for_type_name::<T>(),
mem::size_of::<T>() * iter.into_iter().count(),
);
} else {
for item in iter {
item.visit(self);
}
}
}
pub fn visit_vec_like_body<'b, T>(&'b mut self, data: &[T], capacity: usize)
where
'a: 'b,
T: Allocative,
{
self.visit_slice(data);
self.visit_simple(
UNUSED_CAPACITY_NAME,
mem::size_of::<T>() * capacity.wrapping_sub(data.len()),
);
}
#[allow(clippy::mem_forget)]
pub fn exit(self) {
self.visitor.exit_impl();
mem::forget(self);
}
}
pub trait Allocative {
fn visit<'a, 'b: 'a>(&self, visitor: &'a mut Visitor<'b>);
}