1#![doc = include_str!("../README.md")]
2
3use core::mem::{size_of, align_of, ManuallyDrop, MaybeUninit};
4use core::ptr::{addr_of, addr_of_mut};
5
6#[repr(C)]
10pub struct ReprCWrapper<const SIZE: usize, T> {
11 buffer: MaybeUninit<[u64; SIZE]>,
12 phantom: core::marker::PhantomData<T>,
13}
14
15impl<const SIZE: usize, T> From<T> for ReprCWrapper<SIZE, T> {
16 fn from(val: T) -> Self {
17 Self::new(val)
18 }
19}
20
21impl<const SIZE: usize, T> Drop for ReprCWrapper<SIZE, T> {
22 fn drop(&mut self) {
23 unsafe{
24 let val = &mut *self.buffer.as_mut_ptr().cast::<ManuallyDrop<T>>();
25 ManuallyDrop::<T>::drop(val);
26 }
27 }
28}
29
30impl<const SIZE: usize, T> core::ops::Deref for ReprCWrapper<SIZE, T> {
31 type Target = T;
32
33 fn deref(&self) -> &Self::Target {
34 unsafe{ &*addr_of!(self.buffer).cast::<ManuallyDrop::<T>>() }
35 }
36}
37
38impl<const SIZE: usize, T> core::ops::DerefMut for ReprCWrapper<SIZE, T> {
39 fn deref_mut(&mut self) -> &mut Self::Target {
40 unsafe{ &mut *addr_of_mut!(self.buffer).cast::<ManuallyDrop::<T>>() }
41 }
42}
43
44impl<const SIZE: usize, T> ReprCWrapper<SIZE, T> {
45 pub fn new(val: T) -> Self {
47 assert!(align_of::<T>() <= align_of::<Self>());
48 assert_eq!(SIZE, (size_of::<ManuallyDrop::<T>>() + size_of::<u64>() - 1) / size_of::<u64>());
49
50 let val = ManuallyDrop::<T>::new(val);
51 let mut wrapper = Self {
52 buffer: MaybeUninit::uninit(),
53 phantom: core::marker::PhantomData
54 };
55 unsafe{ (wrapper.buffer.as_mut_ptr().cast::<ManuallyDrop::<T>>()).write(val); }
56 wrapper
57 }
58 pub fn into_inner(self) -> T {
70 let val = unsafe{ core::ptr::read(addr_of!(self.buffer).cast::<ManuallyDrop<T>>()) };
71 core::mem::forget(self);
72 ManuallyDrop::<T>::into_inner(val)
73 }
74}
75
76#[macro_export]
82macro_rules! repr_c_wrapper_t {
83 ( $t:ty ) => { $crate::ReprCWrapper<{(core::mem::size_of::<core::mem::ManuallyDrop::<$t>>() + core::mem::size_of::<u64>() - 1) / core::mem::size_of::<u64>()}, $t> };
84}
85
86#[cfg(test)]
87mod test {
88 use super::*;
89
90 #[test]
91 fn test_basics() {
92
93 let mut wrapper: repr_c_wrapper_t!(String) = "Hello".to_string().into();
94 assert_eq!(*wrapper, "Hello");
95
96 *wrapper = "World".to_string();
97 assert_eq!(*wrapper, "World");
98
99 let the_string = wrapper.into_inner();
100 assert_eq!(the_string, "World");
101 }
102
103 struct VecCWrapper(repr_c_wrapper_t!(Vec<usize>));
104
105 #[test]
106 fn test_repr_c_wrapper_t_macro() {
107
108 let wrapped_vec = VecCWrapper(vec![3, 2, 1].into());
109
110 assert_eq!(*wrapped_vec.0, &[3, 2, 1]);
111 }
112
113 #[repr(align(8))]
114 #[derive(Debug, Default, PartialEq)]
115 struct WithPadding([u8;3]);
116 struct WithPaddingCWrapper(repr_c_wrapper_t!(WithPadding));
117
118 #[test]
119 pub fn test_against_reading_uninit() {
120 let wrapped = WithPaddingCWrapper(WithPadding::default().into());
121 assert_eq!(&*wrapped.0, &WithPadding::default());
122 let wrapped = WithPaddingCWrapper(WithPadding::default().into());
123 assert_eq!(&*wrapped.0, &WithPadding::default());
124 }
125
126 #[repr(align(256))]
127 #[derive(Debug, PartialEq)]
128 struct WellAligned([u8;256]);
129 struct WellAlignedCWrapper(repr_c_wrapper_t!(WellAligned));
130
131 #[test]
132 #[should_panic]
133 pub fn test_against_unaligned() {
134 let wrapped_wa = WellAlignedCWrapper(WellAligned([0; 256]).into());
135 assert_eq!(&*wrapped_wa.0, &WellAligned([0; 256]));
136 let wrapped_wa = WellAlignedCWrapper(WellAligned([0; 256]).into());
137 assert_eq!(&*wrapped_wa.0, &WellAligned([0; 256]));
138 }
139
140}
141
142