1pub use std::any::TypeId;
4use std::{fmt, marker::PhantomData, mem, ptr::NonNull};
5
6#[doc(hidden)]
10mod internal {
11 use super::{mem, NonNull, TypeId};
12 use std::marker::PhantomData;
13
14 pub trait SendMarker {}
16
17 impl SendMarker for () {}
18
19 pub(super) enum OpCode {
21 Drop,
22 IsTypeId,
23 GetTypeId,
24 }
25
26 pub(super) type ManagerFn = fn(OpCode, NonNull<u8>) -> bool;
28
29 pub(super) struct InlineManager<T: Sized + 'static>(PhantomData<T>);
31 impl<T: Sized + 'static> InlineManager<T> {
32 #[allow(non_snake_case)]
35 pub fn do_op(code: OpCode, arg_ptr: NonNull<u8>) -> bool {
36 let TYPE_ID: TypeId = TypeId::of::<T>();
37
38 match code {
39 OpCode::Drop => unsafe {
40 let ptr: *mut T = mem::transmute(arg_ptr.as_ptr());
43 std::ptr::drop_in_place(ptr);
44 true
45 },
46 OpCode::GetTypeId => unsafe {
47 let ptr: *mut TypeId = mem::transmute(arg_ptr.as_ptr());
48 (*ptr) = TYPE_ID;
49 true
50 },
51 OpCode::IsTypeId => unsafe {
52 let ptr: *mut TypeId = mem::transmute(arg_ptr.as_ptr());
53 (*ptr) == TYPE_ID
54 },
55 }
56 }
57 }
58
59 pub(super) struct BoxedManager<T: Sized + 'static>(PhantomData<T>);
61 impl<T: Sized + 'static> BoxedManager<T> {
62 #[allow(non_snake_case)]
65 pub fn do_op(code: OpCode, arg_ptr: NonNull<u8>) -> bool {
66 let TYPE_ID: TypeId = TypeId::of::<T>();
67
68 match code {
69 OpCode::Drop => unsafe {
70 let ptr: *mut Box<T> = mem::transmute(arg_ptr.as_ptr());
73 std::ptr::drop_in_place(ptr);
74 true
75 },
76 OpCode::GetTypeId => unsafe {
77 let ptr: *mut TypeId = mem::transmute(arg_ptr.as_ptr());
78 (*ptr) = TYPE_ID;
79 true
80 },
81 OpCode::IsTypeId => unsafe {
82 let ptr: *mut TypeId = mem::transmute(arg_ptr.as_ptr());
83 (*ptr) == TYPE_ID
84 },
85 }
86 }
87 }
88
89 #[inline]
91 pub(super) fn get_void_ptr<T: Sized>(item: &T) -> NonNull<u8> {
92 unsafe { NonNull::new_unchecked(mem::transmute(&*item)) }
93 }
94
95 #[inline]
97 pub(super) fn get_ptr<T: Sized>(item: &T) -> NonNull<T> {
98 unsafe { NonNull::new_unchecked(mem::transmute(&*item)) }
99 }
100
101 pub(super) const PTR_SIZE: usize = mem::size_of::<*mut u8>();
103}
104
105use internal::SendMarker;
106
107pub struct NoSend(*const u8); impl SendMarker for NoSend {}
110
111struct Empty;
113
114#[derive(Debug)]
117pub struct AnyBox<M: SendMarker = ()> {
118 manager: internal::ManagerFn,
119 storage: [u8; internal::PTR_SIZE], marker: PhantomData<M>,
122}
123
124impl<M: SendMarker> Drop for AnyBox<M> {
127 fn drop(&mut self) {
128 let data_ptr = internal::get_void_ptr(&self.storage[0]);
129 (self.manager)(internal::OpCode::Drop, data_ptr);
130 }
131}
132
133impl AnyBox<()> {
134 pub fn new<T: Send + Sized + 'static>(item: T) -> Self {
136 let mut this = mem::MaybeUninit::<Self>::zeroed();
137
138 let this_ptr = unsafe { NonNull::new_unchecked(this.as_mut_ptr()) };
140
141 Self::_set_data(this_ptr, item);
142
143 unsafe { this.assume_init() }
145 }
146}
147
148impl AnyBox<NoSend> {
149 pub fn new_nosend<T: Sized + 'static>(item: T) -> Self {
151 let mut this = mem::MaybeUninit::<Self>::zeroed();
152
153 let this_ptr = unsafe { NonNull::new_unchecked(this.as_mut_ptr()) };
155
156 Self::_set_data(this_ptr, item);
157
158 unsafe { this.assume_init() }
160 }
161}
162
163impl<M: SendMarker> AnyBox<M> {
164 pub fn empty() -> Self {
168 let mut this = mem::MaybeUninit::<Self>::zeroed();
169
170 let this_ptr = unsafe { NonNull::new_unchecked(this.as_mut_ptr()) };
172
173 Self::_set_data(this_ptr, Empty);
174
175 unsafe { this.assume_init() }
177 }
178
179 pub fn get_type_id(&self) -> TypeId {
181 let mut type_id = mem::MaybeUninit::<TypeId>::uninit();
182 (self.manager)(internal::OpCode::GetTypeId, unsafe {
184 NonNull::new_unchecked(type_id.as_mut_ptr() as *mut u8)
185 });
186 unsafe { type_id.assume_init() }
188 }
189
190 pub fn is_empty(&self) -> bool {
192 self.is::<Empty>()
193 }
194
195 pub fn is<T: Sized + 'static>(&self) -> bool {
197 let type_id = TypeId::of::<T>();
198 (self.manager)(internal::OpCode::IsTypeId, internal::get_void_ptr(&type_id))
199 }
200
201 pub fn get<T: Sized + 'static>(&self) -> Option<&T> {
203 match self.is::<T>() {
204 false => None,
205 true => Some(unsafe { self.get_unchecked() }),
206 }
207 }
208
209 pub unsafe fn get_unchecked<T: Sized + 'static>(&self) -> &T {
214 let data_ptr = Self::_get_data(internal::get_ptr(self));
215 &*data_ptr.as_ptr()
216 }
217
218 pub fn get_mut<T: Sized + 'static>(&mut self) -> Option<&mut T> {
220 match self.is::<T>() {
221 false => None,
222 true => Some(unsafe { self.get_mut_unchecked() }),
223 }
224 }
225
226 pub unsafe fn get_mut_unchecked<T: Sized + 'static>(&mut self) -> &mut T {
228 let data_ptr = Self::_get_data(internal::get_ptr(self));
229 &mut *data_ptr.as_ptr()
230 }
231
232 pub fn take<T: Sized + 'static>(self) -> Result<T, Self> {
234 match self.is::<T>() {
235 false => Err(self),
236 true => Ok(unsafe { self.take_unchecked() }),
237 }
238 }
239
240 pub unsafe fn take_unchecked<T: Sized + 'static>(self) -> T {
242 let this = mem::ManuallyDrop::new(self);
244 Self::_take_data(internal::get_ptr(&this))
245 }
246}
247
248impl<M: SendMarker> AnyBox<M> {
251 fn _set_data<T: Sized + 'static>(this_ptr: NonNull<Self>, item: T) {
252 let this_ptr = this_ptr.as_ptr();
253 unsafe {
255 let size: usize = mem::size_of::<T>();
256 if size > internal::PTR_SIZE {
257 let storage_ptr = mem::transmute(&(*this_ptr).storage[0]);
258 let item = Box::new(item);
260 std::ptr::write(storage_ptr, item);
261
262 (*this_ptr).manager = internal::BoxedManager::<T>::do_op;
263 } else {
264 let storage_ptr = mem::transmute(&(*this_ptr).storage[0]);
265 std::ptr::write(storage_ptr, item);
266
267 (*this_ptr).manager = internal::InlineManager::<T>::do_op;
268 }
269 }
270 }
271
272 fn _get_data<T: Sized + 'static>(this_ptr: NonNull<Self>) -> NonNull<T> {
273 let this_ptr = this_ptr.as_ptr();
274 unsafe {
276 let storage_ptr: *mut u8 = &mut (*this_ptr).storage[0];
277
278 let size: usize = mem::size_of::<T>();
279 let item_ptr = if size > internal::PTR_SIZE {
280 let ptr: *mut Box<T> = mem::transmute(storage_ptr);
281 (*ptr).as_mut() as *mut T
282 } else {
283 let ptr: *mut T = mem::transmute(storage_ptr);
284 ptr
285 };
286
287 NonNull::new_unchecked(item_ptr)
288 }
289 }
290
291 fn _take_data<T: Sized + 'static>(this_ptr: NonNull<Self>) -> T {
292 let this_ptr = this_ptr.as_ptr();
293 unsafe {
295 let storage_ptr: *mut u8 = &mut (*this_ptr).storage[0];
296
297 let size: usize = mem::size_of::<T>();
298 let item = if size > internal::PTR_SIZE {
299 let ptr: *mut Box<T> = mem::transmute(storage_ptr);
300 let ptr: Box<T> = std::ptr::read(ptr);
301 *ptr
303 } else {
304 let ptr: *mut T = mem::transmute(storage_ptr);
305 std::ptr::read(ptr)
306 };
307
308 item
309 }
310 }
311}
312
313impl fmt::Display for AnyBox {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 let type_id = unsafe {
318 let mut val = mem::MaybeUninit::<TypeId>::uninit();
319 (self.manager)(
320 internal::OpCode::GetTypeId,
321 NonNull::new_unchecked(mem::transmute(val.as_mut_ptr())),
322 );
323 val.assume_init()
324 };
325
326 write!(f, "AnyBox::<{:?}>", type_id)
327 }
328}
329
330#[cfg(test)]
337mod tests {
338 use super::AnyBox;
339 use serial_test::serial;
340 use std::sync::atomic::{AtomicUsize, Ordering};
341
342 static _ITEM_NEW_COUNTER: AtomicUsize = AtomicUsize::new(0);
344 static _ITEM_DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
345
346 struct Item<T> {
347 _data: T,
348 }
349
350 impl<T: Default> Item<T> {
351 fn new() -> Self {
352 _ITEM_NEW_COUNTER.fetch_add(1, Ordering::Relaxed);
353 Item {
354 _data: T::default(),
355 }
356 }
357 }
358
359 impl<T> Drop for Item<T> {
360 fn drop(&mut self) {
361 _ITEM_DROP_COUNTER.fetch_add(1, Ordering::Relaxed);
362 }
363 }
364
365 #[test]
368 fn size_of() {
369 const PTR_SIZE_X2: usize = std::mem::size_of::<*mut u8>() << 1;
370 assert_eq!(std::mem::size_of::<AnyBox>(), PTR_SIZE_X2);
371 assert_eq!(std::mem::size_of::<Option<AnyBox>>(), PTR_SIZE_X2);
372 assert_eq!(
373 std::mem::size_of::<std::sync::Arc<dyn std::any::Any>>(),
374 PTR_SIZE_X2
375 );
376 }
377
378 #[test]
379 #[serial]
380 fn size_8_byte() {
381 _ITEM_NEW_COUNTER.store(0, Ordering::Release);
382 _ITEM_DROP_COUNTER.store(0, Ordering::Release);
383
384 {
385 let p = AnyBox::new(Item::<usize>::new());
386 assert!(p.is::<Item<usize>>());
387 assert!(!p.is::<isize>());
388 }
389
390 {
391 let p = AnyBox::new(Item::<usize>::new());
392 let item = p.take::<usize>();
393 assert!(!item.is_ok());
394
395 if let Err(p) = item {
396 let item = p.take::<Item<usize>>();
397 assert!(item.is_ok());
398 }
399 }
400
401 assert_eq!(_ITEM_NEW_COUNTER.load(Ordering::Relaxed), 2);
402 assert_eq!(
403 _ITEM_NEW_COUNTER.load(Ordering::Relaxed),
404 _ITEM_DROP_COUNTER.load(Ordering::Relaxed)
405 );
406 }
407
408 #[test]
409 #[serial]
410 fn size_16_byte() {
411 _ITEM_NEW_COUNTER.store(0, Ordering::Release);
412 _ITEM_DROP_COUNTER.store(0, Ordering::Release);
413
414 {
415 let p = AnyBox::new(Item::<(usize, usize)>::new());
416 assert!(p.is::<Item<(usize, usize)>>());
417 assert!(!p.is::<isize>());
418 }
419
420 {
421 let p = AnyBox::new(Item::<(usize, usize)>::new());
422 let item = p.take::<usize>();
423 assert!(!item.is_ok());
424
425 if let Err(p) = item {
426 let item = p.take::<Item<(usize, usize)>>();
427 assert!(item.is_ok());
428 }
429 }
430
431 assert_eq!(_ITEM_NEW_COUNTER.load(Ordering::Relaxed), 2);
432 assert_eq!(
433 _ITEM_NEW_COUNTER.load(Ordering::Relaxed),
434 _ITEM_DROP_COUNTER.load(Ordering::Relaxed)
435 );
436 }
437}
438
439