#![cfg(all(feature = "std", feature = "derive"))]
use anyhow::Context;
use mem_dbg::*;
fn boxed_usize_payload_size() -> usize {
core::mem::size_of::<usize>()
}
#[derive(MemSize, MemDbg)]
#[mem_size(rec)]
struct ActiveWrapperFields {
reverse: core::cmp::Reverse<Box<usize>>,
bound: core::ops::Bound<Box<usize>>,
poll: core::task::Poll<Box<usize>>,
flow_break: core::ops::ControlFlow<Box<usize>, Box<usize>>,
flow_continue: core::ops::ControlFlow<Box<usize>, Box<usize>>,
}
#[derive(MemSize, MemDbg)]
#[mem_size(rec)]
struct EmptyWrapperFields {
bound: core::ops::Bound<Box<usize>>,
poll: core::task::Poll<Box<usize>>,
}
#[test]
fn test_active_wrapper_payloads() -> anyhow::Result<()> {
let node = ActiveWrapperFields {
reverse: core::cmp::Reverse(Box::new(1)),
bound: core::ops::Bound::Included(Box::new(2)),
poll: core::task::Poll::Ready(Box::new(3)),
flow_break: core::ops::ControlFlow::Break(Box::new(4)),
flow_continue: core::ops::ControlFlow::Continue(Box::new(5)),
};
assert_eq!(
node.mem_size(SizeFlags::default()),
core::mem::size_of::<ActiveWrapperFields>() + 5 * boxed_usize_payload_size()
);
let mut output = String::new();
node.mem_dbg_depth_on(&mut output, 2, DbgFlags::default())?;
assert!(output.contains("ActiveWrapperFields"));
assert!(output.contains("reverse"));
assert!(output.contains("bound"));
assert!(output.contains("poll"));
assert!(output.contains("flow_break"));
assert!(output.contains("flow_continue"));
Ok(())
}
#[test]
fn test_empty_wrapper_variants() -> anyhow::Result<()> {
let node = EmptyWrapperFields {
bound: core::ops::Bound::Unbounded,
poll: core::task::Poll::Pending,
};
assert_eq!(
node.mem_size(SizeFlags::default()),
core::mem::size_of::<EmptyWrapperFields>()
);
let mut output = String::new();
node.mem_dbg_depth_on(&mut output, 2, DbgFlags::default())?;
assert!(output.contains("EmptyWrapperFields"));
assert!(output.contains("bound"));
assert!(output.contains("poll"));
Ok(())
}
#[test]
fn test_individual_wrapper_sizes() -> anyhow::Result<()> {
let reverse = core::cmp::Reverse(Box::new(1usize));
assert_eq!(
reverse.mem_size(SizeFlags::default()),
core::mem::size_of::<core::cmp::Reverse<Box<usize>>>() + boxed_usize_payload_size()
);
let included = core::ops::Bound::Included(Box::new(1usize));
let excluded = core::ops::Bound::Excluded(Box::new(1usize));
let unbounded: core::ops::Bound<Box<usize>> = core::ops::Bound::Unbounded;
assert_eq!(
included.mem_size(SizeFlags::default()),
core::mem::size_of::<core::ops::Bound<Box<usize>>>() + boxed_usize_payload_size()
);
assert_eq!(
excluded.mem_size(SizeFlags::default()),
core::mem::size_of::<core::ops::Bound<Box<usize>>>() + boxed_usize_payload_size()
);
assert_eq!(
unbounded.mem_size(SizeFlags::default()),
core::mem::size_of::<core::ops::Bound<Box<usize>>>()
);
let ready = core::task::Poll::Ready(Box::new(1usize));
let pending: core::task::Poll<Box<usize>> = core::task::Poll::Pending;
assert_eq!(
ready.mem_size(SizeFlags::default()),
core::mem::size_of::<core::task::Poll<Box<usize>>>() + boxed_usize_payload_size()
);
assert_eq!(
pending.mem_size(SizeFlags::default()),
core::mem::size_of::<core::task::Poll<Box<usize>>>()
);
let flow_break: core::ops::ControlFlow<Box<usize>, Box<usize>> =
core::ops::ControlFlow::Break(Box::new(1usize));
let flow_continue: core::ops::ControlFlow<Box<usize>, Box<usize>> =
core::ops::ControlFlow::Continue(Box::new(1usize));
assert_eq!(
flow_break.mem_size(SizeFlags::default()),
core::mem::size_of::<core::ops::ControlFlow<Box<usize>, Box<usize>>>()
+ boxed_usize_payload_size()
);
assert_eq!(
flow_continue.mem_size(SizeFlags::default()),
core::mem::size_of::<core::ops::ControlFlow<Box<usize>, Box<usize>>>()
+ boxed_usize_payload_size()
);
Ok(())
}
#[test]
fn test_niche_optimized_wrappers() -> anyhow::Result<()> {
use core::num::NonZeroU32;
let backing = 7u8;
let stack_ref: &u8 = &backing;
assert_eq!(
core::mem::size_of::<core::task::Poll<&u8>>(),
core::mem::size_of::<&u8>(),
);
let pending: core::task::Poll<&u8> = core::task::Poll::Pending;
let ready: core::task::Poll<&u8> = core::task::Poll::Ready(stack_ref);
assert_eq!(
pending.mem_size(SizeFlags::default()),
core::mem::size_of::<core::task::Poll<&u8>>(),
);
assert_eq!(
ready.mem_size(SizeFlags::default()),
core::mem::size_of::<core::task::Poll<&u8>>(),
);
assert_eq!(
core::mem::size_of::<core::ops::ControlFlow<&u8, ()>>(),
core::mem::size_of::<&u8>(),
);
let flow_break: core::ops::ControlFlow<&u8, ()> = core::ops::ControlFlow::Break(stack_ref);
let flow_continue: core::ops::ControlFlow<&u8, ()> = core::ops::ControlFlow::Continue(());
assert_eq!(
flow_break.mem_size(SizeFlags::default()),
core::mem::size_of::<core::ops::ControlFlow<&u8, ()>>(),
);
assert_eq!(
flow_continue.mem_size(SizeFlags::default()),
core::mem::size_of::<core::ops::ControlFlow<&u8, ()>>(),
);
assert_eq!(
core::mem::size_of::<core::cmp::Reverse<&u8>>(),
core::mem::size_of::<&u8>(),
);
let reverse = core::cmp::Reverse(stack_ref);
assert_eq!(
reverse.mem_size(SizeFlags::default()),
core::mem::size_of::<core::cmp::Reverse<&u8>>(),
);
let nz = NonZeroU32::new(5).context("5 is non-zero")?;
assert_eq!(core::mem::size_of::<Option<NonZeroU32>>(), 4);
assert_eq!(core::mem::size_of::<core::task::Poll<NonZeroU32>>(), 4);
let poll_nz_ready = core::task::Poll::<NonZeroU32>::Ready(nz);
let poll_nz_pending: core::task::Poll<NonZeroU32> = core::task::Poll::Pending;
assert_eq!(
poll_nz_ready.mem_size(SizeFlags::default()),
core::mem::size_of::<core::task::Poll<NonZeroU32>>(),
);
assert_eq!(
poll_nz_pending.mem_size(SizeFlags::default()),
core::mem::size_of::<core::task::Poll<NonZeroU32>>(),
);
let bound_nz_included = core::ops::Bound::<NonZeroU32>::Included(nz);
let bound_nz_excluded = core::ops::Bound::<NonZeroU32>::Excluded(nz);
let bound_nz_unbounded: core::ops::Bound<NonZeroU32> = core::ops::Bound::Unbounded;
let bound_nz_size = core::mem::size_of::<core::ops::Bound<NonZeroU32>>();
assert_eq!(
bound_nz_included.mem_size(SizeFlags::default()),
bound_nz_size
);
assert_eq!(
bound_nz_excluded.mem_size(SizeFlags::default()),
bound_nz_size
);
assert_eq!(
bound_nz_unbounded.mem_size(SizeFlags::default()),
bound_nz_size
);
Ok(())
}
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_reverse_labels_inner_field() {
let value = core::cmp::Reverse(Box::new(7u32));
let out = render(&value);
assert!(out.contains("Reverse"));
assert!(out.contains("╰╴0"), "missing tuple-style 0 label:\n{out}");
}
#[test]
fn test_bound_variants_label_payload() {
let included: core::ops::Bound<Box<u32>> = core::ops::Bound::Included(Box::new(1));
let excluded: core::ops::Bound<Box<u32>> = core::ops::Bound::Excluded(Box::new(2));
let unbounded: core::ops::Bound<Box<u32>> = core::ops::Bound::Unbounded;
assert!(render(&included).contains("╰╴Included"));
assert!(render(&excluded).contains("╰╴Excluded"));
let out_unbounded = render(&unbounded);
assert!(out_unbounded.contains("Bound"));
assert!(!out_unbounded.contains("Included"));
assert!(!out_unbounded.contains("Excluded"));
}
#[test]
fn test_poll_variants_label_payload() {
let ready: core::task::Poll<Box<u32>> = core::task::Poll::Ready(Box::new(1));
let pending: core::task::Poll<Box<u32>> = core::task::Poll::Pending;
assert!(render(&ready).contains("╰╴Ready"));
let out_pending = render(&pending);
assert!(!out_pending.contains("Ready"));
}
#[test]
fn test_control_flow_variants_label_payload() {
let brk: core::ops::ControlFlow<Box<u32>, Box<u32>> =
core::ops::ControlFlow::Break(Box::new(1));
let cont: core::ops::ControlFlow<Box<u32>, Box<u32>> =
core::ops::ControlFlow::Continue(Box::new(2));
assert!(render(&brk).contains("╰╴Break"));
assert!(render(&cont).contains("╰╴Continue"));
}