#[macro_export]
macro_rules! obfuscate {
(
type: $inner:ty,
module: $mod_name:ident,
derives: [ $($trait:ident),* $(,)? ],
align: $align:literal $(,)?
) => {
$crate::obfuscate!(
@impl
type: $inner,
module: $mod_name,
derives: [$($trait),*],
align: $align,
check: strict,
);
};
(
type: $inner:ty,
module: $mod_name:ident,
derives: [ $($trait:ident),* $(,)? ] $(,)?
) => {
$crate::obfuscate!(
@impl
type: $inner,
module: $mod_name,
derives: [$($trait),*],
align: 64,
check: relaxed,
);
};
(
type: $inner:ty,
module: $mod_name:ident,
align: $align:literal $(,)?
) => {
$crate::obfuscate!(
@impl
type: $inner,
module: $mod_name,
derives: [],
align: $align,
check: strict,
);
};
(
type: $inner:ty,
module: $mod_name:ident $(,)?
) => {
$crate::obfuscate!(
@impl
type: $inner,
module: $mod_name,
derives: [],
align: 64,
check: relaxed,
);
};
(@impl
type: $inner:ty,
module: $mod_name:ident,
derives: [ $($trait:ident),* ],
align: $align:literal,
check: $check:ident $(,)?
) => {
mod $mod_name {
#[allow(unused_imports)]
use super::*;
const SIZE: usize = ::core::mem::size_of::<$inner>();
const SLOT: usize = ::core::mem::size_of::<*mut ()>();
const SLOTS: usize = SIZE.div_ceil(SLOT);
$crate::__obfuscate_check_align!($check, $inner, $align);
#[doc = concat!(
"Inline, opaque storage for one `",
stringify!($inner),
"` value. **Alignment:** ",
stringify!($align),
" bytes."
)]
#[repr(C, align($align))]
pub(super) struct Opaque {
data: [::core::mem::MaybeUninit<*mut ()>; SLOTS],
}
mod impls {
#[allow(unused_imports)]
use super::super::*;
use super::{Opaque, SLOTS};
$(
$crate::obfuscate_impl!($trait);
)*
#[allow(dead_code)]
impl Opaque {
pub(in super::super) fn new(inner: $inner) -> Self {
let mut wrapper = Self {
data: [::core::mem::MaybeUninit::uninit(); SLOTS],
};
unsafe {
(wrapper.data.as_mut_ptr() as *mut $inner).write(inner);
}
wrapper
}
pub(in super::super) fn as_ref(&self) -> &$inner {
unsafe { &*(self.data.as_ptr() as *const $inner) }
}
pub(in super::super) fn as_mut(&mut self) -> &mut $inner {
unsafe { &mut *(self.data.as_mut_ptr() as *mut $inner) }
}
pub(in super::super) fn into_inner(self) -> $inner {
let this = ::core::mem::ManuallyDrop::new(self);
unsafe { ::core::ptr::read(this.data.as_ptr() as *const $inner) }
}
}
impl ::core::ops::Drop for Opaque {
fn drop(&mut self) {
unsafe {
::core::ptr::drop_in_place(
self.data.as_mut_ptr() as *mut $inner,
);
}
}
}
}
}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __obfuscate_check_align {
(strict, $inner:ty, $align:literal) => {
const _: () = {
let inner = ::core::mem::align_of::<$inner>();
let slot = ::core::mem::align_of::<*mut ()>();
let needed = if inner > slot { inner } else { slot };
assert!(
$align == needed,
"obfuscate!: the `align:` literal does not match the required value. \
Set it to `max(core::mem::align_of::<YourType>(), core::mem::align_of::<*mut ()>())` \
(typically 8 on 64-bit targets, larger if your type has a higher alignment). \
A literal is required because `#[repr(align(N))]` does not accept \
const expressions like `align_of::<T>()` — the macro can't compute it for you.",
);
};
};
(relaxed, $inner:ty, $align:literal) => {
const _: () = assert!(
::core::mem::align_of::<$inner>() <= $align,
"obfuscate!: inner type's alignment exceeds the default wrapper alignment (64 bytes). \
Pass an explicit `align: N` literal (a power of two equal to \
`max(core::mem::align_of::<YourType>(), core::mem::align_of::<*mut ()>())`) \
to override the default.",
);
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! obfuscate_impl {
(Send) => {
unsafe impl ::core::marker::Send for Opaque {}
};
(Sync) => {
unsafe impl ::core::marker::Sync for Opaque {}
};
(Debug) => {
impl ::core::fmt::Debug for Opaque {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
::core::fmt::Debug::fmt(self.as_ref(), f)
}
}
};
(Display) => {
impl ::core::fmt::Display for Opaque {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
::core::fmt::Display::fmt(self.as_ref(), f)
}
}
};
(PartialEq) => {
impl ::core::cmp::PartialEq for Opaque {
fn eq(&self, other: &Self) -> bool {
self.as_ref() == other.as_ref()
}
}
};
(Eq) => {
impl ::core::cmp::Eq for Opaque {}
};
(Hash) => {
impl ::core::hash::Hash for Opaque {
fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
::core::hash::Hash::hash(self.as_ref(), state)
}
}
};
(Clone) => {
impl ::core::clone::Clone for Opaque {
fn clone(&self) -> Self {
Self::new(::core::clone::Clone::clone(self.as_ref()))
}
}
};
(Default) => {
impl ::core::default::Default for Opaque {
fn default() -> Self {
Self::new(::core::default::Default::default())
}
}
};
}
#[cfg(test)]
mod tests {
extern crate alloc;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::sync::atomic::{AtomicUsize, Ordering};
#[derive(Clone, Debug, PartialEq, Eq)]
struct Pod {
a: u64,
b: u32,
}
obfuscate!(
type: Pod,
module: pod,
align: 8,
);
#[test]
fn pod_round_trip() {
let value = Pod {
a: 0xDEAD_BEEF,
b: 7,
};
let wrapper = pod::Opaque::new(value.clone());
assert_eq!(wrapper.as_ref(), &value);
assert_eq!(wrapper.into_inner(), value);
}
#[test]
fn pod_mutation() {
let mut wrapper = pod::Opaque::new(Pod { a: 0, b: 0 });
wrapper.as_mut().a = 99;
wrapper.as_mut().b = 1;
assert_eq!(wrapper.as_ref(), &Pod { a: 99, b: 1 });
}
obfuscate!(
type: Pod,
module: pod_default,
derives: [],
);
#[test]
fn opaque_default_arm_uses_64_byte_alignment() {
assert_eq!(core::mem::align_of::<pod_default::Opaque>(), 64);
}
#[test]
fn opaque_default_arm_round_trip_works() {
let value = Pod {
a: 0xCAFEBABE,
b: 3,
};
let wrapper = pod_default::Opaque::new(value.clone());
assert_eq!(wrapper.as_ref(), &value);
assert_eq!(wrapper.into_inner(), value);
}
#[test]
fn opaque_alignment_matches_declared() {
assert_eq!(core::mem::align_of::<pod::Opaque>(), 8);
assert_eq!(core::mem::align_of::<high_align::Opaque>(), 32);
assert_eq!(
core::mem::align_of::<zst::Opaque>(),
core::mem::align_of::<*mut ()>()
);
}
struct DropCounter(Arc<AtomicUsize>);
impl Drop for DropCounter {
fn drop(&mut self) {
self.0.fetch_add(1, Ordering::SeqCst);
}
}
obfuscate!(
type: DropCounter,
module: counted,
);
#[test]
fn drop_runs_exactly_once() {
let counter = Arc::new(AtomicUsize::new(0));
{
let _w = counted::Opaque::new(DropCounter(counter.clone()));
}
assert_eq!(counter.load(Ordering::SeqCst), 1);
}
#[test]
fn into_inner_does_not_double_drop() {
let counter = Arc::new(AtomicUsize::new(0));
let wrapper = counted::Opaque::new(DropCounter(counter.clone()));
let inner = wrapper.into_inner();
assert_eq!(counter.load(Ordering::SeqCst), 0);
drop(inner);
assert_eq!(counter.load(Ordering::SeqCst), 1);
}
#[repr(align(32))]
#[derive(Clone, Debug, PartialEq, Eq)]
struct HighAlign {
data: [u64; 4],
}
obfuscate!(
type: HighAlign,
module: high_align,
align: 32,
);
#[test]
fn high_alignment_inner_works() {
let value = HighAlign { data: [1, 2, 3, 4] };
let wrapper = high_align::Opaque::new(value.clone());
assert_eq!(core::mem::align_of::<high_align::Opaque>(), 32);
let r: &HighAlign = wrapper.as_ref();
assert_eq!((r as *const HighAlign as usize) % 32, 0);
assert_eq!(r, &value);
}
#[derive(Clone, Debug, PartialEq)]
#[allow(dead_code)]
enum Shape {
Scalar(u64),
Vector(Vec<u32>),
Nested(alloc::boxed::Box<Shape>),
}
obfuscate!(
type: Shape,
module: shape,
);
#[test]
fn enum_with_heap_round_trip() {
let value = Shape::Nested(alloc::boxed::Box::new(Shape::Vector(alloc::vec![
1, 2, 3, 4
])));
let wrapper = shape::Opaque::new(value.clone());
let recovered = wrapper.into_inner();
assert_eq!(recovered, value);
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Default)]
struct AllTraits {
x: u64,
y: String,
}
impl core::fmt::Display for AllTraits {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "AllTraits(x={}, y={})", self.x, self.y)
}
}
obfuscate!(
type: AllTraits,
module: all_traits,
derives: [Send, Sync, Debug, Display, PartialEq, Eq, Hash, Clone, Default],
align: 8,
);
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
#[test]
fn opaque_is_send_and_sync_when_listed() {
assert_send::<all_traits::Opaque>();
assert_sync::<all_traits::Opaque>();
}
#[test]
fn opaque_debug_forwards_to_inner() {
let v = AllTraits {
x: 42,
y: String::from("hello"),
};
let w = all_traits::Opaque::new(v.clone());
assert_eq!(alloc::format!("{:?}", w), alloc::format!("{:?}", v));
}
#[test]
fn opaque_debug_alternate_format_forwards_to_inner() {
let v = AllTraits {
x: 42,
y: String::from("hello"),
};
let w = all_traits::Opaque::new(v.clone());
assert_eq!(alloc::format!("{:#?}", w), alloc::format!("{:#?}", v));
}
#[test]
fn opaque_display_forwards_to_inner() {
let v = AllTraits {
x: 7,
y: String::from("world"),
};
let w = all_traits::Opaque::new(v.clone());
assert_eq!(alloc::format!("{}", w), alloc::format!("{}", v));
assert_eq!(alloc::format!("{}", w), "AllTraits(x=7, y=world)");
}
#[test]
fn opaque_eq_marker_when_listed() {
fn assert_eq_bound<T: Eq>() {}
assert_eq_bound::<all_traits::Opaque>();
}
#[test]
fn opaque_partial_eq_forwards_to_inner() {
let a = all_traits::Opaque::new(AllTraits {
x: 1,
y: String::from("a"),
});
let b = all_traits::Opaque::new(AllTraits {
x: 1,
y: String::from("a"),
});
let c = all_traits::Opaque::new(AllTraits {
x: 2,
y: String::from("a"),
});
assert_eq!(a, b);
assert_ne!(a, c);
}
#[test]
fn opaque_hash_forwards_to_inner() {
use core::hash::{Hash, Hasher};
struct Fnv(u64);
impl Hasher for Fnv {
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, bytes: &[u8]) {
for &b in bytes {
self.0 = self.0.wrapping_mul(0x100000001b3).wrapping_add(b as u64);
}
}
}
let v = AllTraits {
x: 1,
y: String::from("a"),
};
let w = all_traits::Opaque::new(v.clone());
let mut h_inner = Fnv(0xcbf29ce484222325);
v.hash(&mut h_inner);
let mut h_opaque = Fnv(0xcbf29ce484222325);
w.hash(&mut h_opaque);
assert_eq!(h_inner.finish(), h_opaque.finish());
}
#[test]
fn opaque_clone_produces_independent_copy() {
let original = all_traits::Opaque::new(AllTraits {
x: 1,
y: String::from("hi"),
});
let cloned = original.clone();
assert_eq!(original, cloned);
let original_ptr = original.as_ref() as *const _ as usize;
let cloned_ptr = cloned.as_ref() as *const _ as usize;
assert_ne!(original_ptr, cloned_ptr);
}
#[test]
fn opaque_clone_deep_copies_owned_heap_data() {
let mut original = all_traits::Opaque::new(AllTraits {
x: 0,
y: String::from("first"),
});
let cloned = original.clone();
original.as_mut().y = String::from("mutated");
assert_eq!(cloned.as_ref().y, "first");
}
#[test]
fn opaque_default_constructs_default_inner() {
let w: all_traits::Opaque = Default::default();
assert_eq!(w.as_ref(), &AllTraits::default());
}
#[derive(Debug, PartialEq, Eq, Clone, Default)]
struct Zst;
obfuscate!(
type: Zst,
module: zst,
derives: [Debug, PartialEq, Eq, Clone, Default],
align: 8,
);
#[test]
fn zero_sized_type_round_trip() {
let wrapper = zst::Opaque::new(Zst);
assert_eq!(wrapper.as_ref(), &Zst);
assert_eq!(wrapper.clone().into_inner(), Zst);
}
}