#![cfg(feature = "std")]
#![cfg(feature = "derive")]
use mem_dbg::*;
use std::cell::{Cell, OnceCell, RefCell, UnsafeCell};
use std::sync::OnceLock;
#[test]
fn test_cell_in_struct() {
#[derive(MemSize)]
#[mem_size(rec)]
struct Test {
cell: Cell<i32>,
}
let s = Test {
cell: Cell::new(42),
};
let size = s.mem_size(SizeFlags::default());
assert_eq!(size, std::mem::size_of::<Cell<i32>>());
}
#[test]
fn test_cell_with_different_types() {
#[derive(MemSize)]
#[mem_size(rec)]
struct Test {
cell_u8: Cell<u8>,
cell_u64: Cell<u64>,
cell_bool: Cell<bool>,
}
let s = Test {
cell_u8: Cell::new(1),
cell_u64: Cell::new(100),
cell_bool: Cell::new(true),
};
let size = s.mem_size(SizeFlags::default());
assert_eq!(size, std::mem::size_of::<Test>());
}
#[test]
fn test_cell_with_memdbg() {
#[derive(MemSize, MemDbg)]
#[mem_size(rec)]
struct Test {
value: Cell<i32>,
}
let s = Test {
value: Cell::new(123),
};
let size = s.mem_size(SizeFlags::default());
assert_eq!(size, std::mem::size_of::<Test>());
let result = s.mem_dbg(DbgFlags::default());
assert!(result.is_ok());
for depth in 0..3 {
let result = s.mem_dbg_depth(depth, DbgFlags::default());
assert!(result.is_ok());
}
}
#[test]
fn test_refcell_in_struct() {
#[derive(MemSize)]
#[mem_size(rec)]
struct Test {
ref_cell: RefCell<i32>,
}
let s = Test {
ref_cell: RefCell::new(42),
};
let size = s.mem_size(SizeFlags::default());
assert_eq!(size, std::mem::size_of::<RefCell<i32>>());
}
#[test]
fn test_refcell_with_vec() {
#[derive(MemSize)]
struct Test {
ref_cell: RefCell<Vec<i32>>,
}
let s = Test {
ref_cell: RefCell::new(vec![1, 2, 3, 4, 5]),
};
let size = s.mem_size(SizeFlags::default());
assert!(size > std::mem::size_of::<RefCell<Vec<i32>>>());
}
#[test]
fn test_refcell_with_memdbg() {
#[derive(MemSize, MemDbg)]
struct Test {
data: RefCell<String>,
}
let s = Test {
data: RefCell::new("hello".to_string()),
};
let size = s.mem_size(SizeFlags::default());
assert!(size > 0);
let result = s.mem_dbg(DbgFlags::default());
assert!(result.is_ok());
for depth in 0..3 {
let result = s.mem_dbg_depth(depth, DbgFlags::default());
assert!(result.is_ok());
}
}
#[test]
fn test_unsafe_cell_in_struct() {
#[derive(MemSize)]
#[mem_size(rec)]
struct Test {
unsafe_cell: UnsafeCell<i32>,
}
let s = Test {
unsafe_cell: UnsafeCell::new(42),
};
let size = s.mem_size(SizeFlags::default());
assert_eq!(size, std::mem::size_of::<UnsafeCell<i32>>());
}
#[test]
fn test_unsafe_cell_with_vec() {
#[derive(MemSize)]
#[mem_size(flat)]
struct Test {
unsafe_cell: UnsafeCell<Vec<i32>>,
}
let s = Test {
unsafe_cell: UnsafeCell::new(vec![1, 2, 3, 4, 5]),
};
let size = s.mem_size(SizeFlags::default());
assert_eq!(size, std::mem::size_of::<Test>());
}
#[test]
fn test_unsafe_cell_with_memdbg() {
#[derive(MemSize, MemDbg)]
#[mem_size(rec)]
struct Test {
value: UnsafeCell<u64>,
}
let s = Test {
value: UnsafeCell::new(999),
};
let size = s.mem_size(SizeFlags::default());
assert_eq!(size, std::mem::size_of::<Test>());
let result = s.mem_dbg(DbgFlags::default());
assert!(result.is_ok());
for depth in 0..3 {
let result = s.mem_dbg_depth(depth, DbgFlags::default());
assert!(result.is_ok());
}
}
#[test]
fn test_cell_and_unsafe_cell_do_not_recurse_into_inner_value() {
struct PanicOnVisit;
impl FlatType for PanicOnVisit {
type Flat = False;
}
impl MemSize for PanicOnVisit {
fn mem_size_rec(&self, _flags: SizeFlags, _refs: &mut HashMap<usize, usize>) -> usize {
panic!("inner value must not be inspected");
}
}
impl MemDbgImpl for PanicOnVisit {}
let cell = Cell::new(PanicOnVisit);
assert_eq!(
cell.mem_size(SizeFlags::default()),
std::mem::size_of_val(&cell)
);
let mut output = String::new();
assert!(cell.mem_dbg_on(&mut output, DbgFlags::default()).is_ok());
let unsafe_cell = UnsafeCell::new(PanicOnVisit);
assert_eq!(
unsafe_cell.mem_size(SizeFlags::default()),
std::mem::size_of_val(&unsafe_cell)
);
output.clear();
assert!(
unsafe_cell
.mem_dbg_on(&mut output, DbgFlags::default())
.is_ok()
);
}
#[test]
fn test_oncecell_empty() {
#[derive(MemSize)]
struct Test {
once_cell: OnceCell<String>,
}
let s = Test {
once_cell: OnceCell::new(),
};
let size = s.mem_size(SizeFlags::default());
assert_eq!(size, std::mem::size_of::<Test>());
}
#[test]
fn test_oncecell_initialized() {
#[derive(MemSize)]
struct Test {
once_cell: OnceCell<String>,
}
let once_cell = OnceCell::new();
once_cell.set("initialized".to_string()).unwrap();
let s = Test { once_cell };
let size = s.mem_size(SizeFlags::default());
let expected = std::mem::size_of::<Test>() + "initialized".len();
assert_eq!(size, expected);
}
#[test]
fn test_oncecell_with_vec() {
#[derive(MemSize)]
struct Test {
once_cell: OnceCell<Vec<i32>>,
}
let once_cell = OnceCell::new();
once_cell.set(vec![1, 2, 3, 4, 5]).unwrap();
let s = Test { once_cell };
let size = s.mem_size(SizeFlags::default());
let expected = std::mem::size_of::<Test>() + 5 * std::mem::size_of::<i32>();
assert_eq!(size, expected);
}
#[test]
fn test_oncecell_with_memdbg() {
#[derive(MemSize, MemDbg)]
struct Test {
data: OnceCell<String>,
}
let once_cell = OnceCell::new();
once_cell.set("test data".to_string()).unwrap();
let s = Test { data: once_cell };
let size = s.mem_size(SizeFlags::default());
assert!(size >= std::mem::size_of::<Test>());
let result = s.mem_dbg(DbgFlags::default());
assert!(result.is_ok());
for depth in 0..3 {
let result = s.mem_dbg_depth(depth, DbgFlags::default());
assert!(result.is_ok());
}
}
#[test]
fn test_oncelock_empty() {
#[derive(MemSize)]
struct Test {
once_lock: OnceLock<String>,
}
let s = Test {
once_lock: OnceLock::new(),
};
assert_eq!(
s.mem_size(SizeFlags::default()),
std::mem::size_of::<Test>()
);
}
#[test]
fn test_oncelock_initialized() {
#[derive(MemSize)]
struct Test {
once_lock: OnceLock<String>,
}
let once_lock = OnceLock::new();
once_lock.set("initialized".to_string()).unwrap();
let s = Test { once_lock };
let expected = std::mem::size_of::<Test>() + "initialized".len();
assert_eq!(s.mem_size(SizeFlags::default()), expected);
}
#[test]
fn test_oncelock_with_vec() {
#[derive(MemSize)]
struct Test {
once_lock: OnceLock<Vec<i32>>,
}
let once_lock = OnceLock::new();
once_lock.set(vec![1, 2, 3, 4, 5]).unwrap();
let s = Test { once_lock };
let expected = std::mem::size_of::<Test>() + 5 * std::mem::size_of::<i32>();
assert_eq!(s.mem_size(SizeFlags::default()), expected);
}
#[test]
fn test_oncelock_with_memdbg() {
#[derive(MemSize, MemDbg)]
struct Test {
data: OnceLock<String>,
}
let once_lock = OnceLock::new();
once_lock.set("test data".to_string()).unwrap();
let s = Test { data: once_lock };
assert!(s.mem_size(SizeFlags::default()) >= std::mem::size_of::<Test>());
let mut output = String::new();
s.mem_dbg_depth_on(&mut output, 2, DbgFlags::default())
.unwrap();
assert!(output.contains("Test"));
assert!(output.contains("data"));
}
#[test]
fn test_all_cells_in_struct() {
#[derive(MemSize, MemDbg)]
struct Test {
cell: Cell<i32>,
ref_cell: RefCell<i32>,
unsafe_cell: UnsafeCell<i32>,
once_cell: OnceCell<String>,
}
let once_cell = OnceCell::new();
once_cell.set("initialized".to_string()).unwrap();
let s = Test {
cell: Cell::new(100),
ref_cell: RefCell::new(200),
unsafe_cell: UnsafeCell::new(300),
once_cell,
};
let size = s.mem_size(SizeFlags::default());
assert!(size >= std::mem::size_of::<Test>());
let result = s.mem_dbg(DbgFlags::default());
assert!(result.is_ok());
for depth in 0..3 {
let result = s.mem_dbg_depth(depth, DbgFlags::default());
assert!(result.is_ok());
}
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_refcell_mem_dbg_during_borrow_mut() {
#[derive(MemSize, MemDbg)]
struct Test {
data: RefCell<Vec<i32>>,
other: u64,
}
let s = Test {
data: RefCell::new(vec![1, 2, 3]),
other: 42,
};
let _guard = s.data.borrow_mut();
let mut output = String::new();
s.mem_dbg_on(&mut output, DbgFlags::default()).unwrap();
let arch = std::env::consts::ARCH;
insta::with_settings!({snapshot_suffix => arch}, {
insta::assert_snapshot!("refcell_mutably_borrowed", output);
});
}
#[derive(MemSize, MemDbg)]
struct Inner {
heavy: Vec<u8>,
}
fn render<T: MemDbg>(value: &T) -> String {
let mut out = String::new();
value
.mem_dbg_on(&mut out, DbgFlags::default())
.expect("mem_dbg_on");
out
}
#[test]
fn test_oncecell_renders_inner_children() {
let cell: OnceCell<Inner> = OnceCell::new();
cell.set(Inner {
heavy: vec![0u8; 64],
})
.ok()
.expect("oncecell set");
let out = render(&cell);
assert!(out.contains("OnceCell"), "missing OnceCell line:\n{out}");
assert!(
out.contains("heavy"),
"OnceCell did not recurse into Inner:\n{out}"
);
}
#[test]
fn test_oncecell_empty_renders_only_self() {
let cell: OnceCell<Inner> = OnceCell::new();
let out = render(&cell);
assert!(out.contains("OnceCell"));
assert!(!out.contains("heavy"));
}
#[test]
fn test_oncelock_renders_inner_children() {
let cell: OnceLock<Inner> = OnceLock::new();
cell.set(Inner {
heavy: vec![0u8; 64],
})
.ok()
.expect("oncelock set");
let out = render(&cell);
assert!(out.contains("OnceLock"), "missing OnceLock line:\n{out}");
assert!(
out.contains("heavy"),
"OnceLock did not recurse into Inner:\n{out}"
);
}
#[test]
fn test_oncelock_empty_renders_only_self() {
let cell: OnceLock<Inner> = OnceLock::new();
let out = render(&cell);
assert!(out.contains("OnceLock"));
assert!(!out.contains("heavy"));
}