dungeon_cell/
core.rs

1mod inner;
2
3use core::mem::MaybeUninit;
4use core::ptr::addr_of;
5
6use crate::align::Unaligned;
7use crate::bound::{bounds, Dynamic};
8use crate::buffer::Buffer;
9use crate::compile_time::{
10    const_transmute, const_usize_assert, AlignmentSmallerOrEqualTo,
11};
12use crate::layout::LayoutType;
13use crate::marker_traits::{IsAlignment, IsBound, IsLayout};
14use crate::vtable::{
15    ConstVTableOf, Descriptor, Inspect, StaticVTable, VTable, VTableOf,
16    VTableSubset,
17};
18
19use self::inner::{as_inner, as_inner_mut, from_inner, into_inner, Inner};
20
21pub use self::inner::Cleanup;
22
23/// The default vtable implementation.
24///
25/// This is a pointer to a [`StaticVTable`] where the pointer has had it's alignment
26/// requirements removed. The alignment requirements are removed for better space efficiency when
27/// used with layouts having a low alignment. On some platforms this may result in a lower
28/// performance. In which case, you can switch to using a `&'static StaticVTable<B>` directly.
29pub type DefaultVtable<B = bounds::Normal> =
30    Unaligned<&'static StaticVTable<B>>;
31
32/// Core of a dungeon type.
33///
34/// [`DungeonCore`] can store any type that fits in
35/// it's layout `L` and a vtable of type `V` can be generated for. This type does not perform
36/// any dynamic memory allocation. It can be thought of as a single value arena.
37///
38/// [`DungeonCore`] always contains a value of some type.
39///
40/// The space overhead of [`DungeonCore`] is kept as small as possible. In most cases,
41/// the space overhead of [`DungeonCore`] is the size of a single [`usize`]. The
42/// space overhead is directly tied to the size of the `V` type.
43///
44/// [`DungeonCore`] is generic over the traits that the values it stores must
45/// implement. The required traits are set by the `V` type. When using [`DefaultVtable`],
46/// the default required traits are `Send + Sync + Unpin + Debug`.
47///
48/// # Examples
49/// ```
50/// use dungeon_cell::{DungeonCore, layout_for};
51///
52/// // create a DungeonCore with a layout required to store i32 or f64
53/// let mut core = DungeonCore::<layout_for!(i32, f64)>::default();
54///
55/// // we can store a i32 and get it back
56/// core.store(1234);
57/// assert_eq!(core.take::<i32>(), Some(1234));
58///
59/// // we can store a f64 and get it back
60/// core.store(1.234);
61/// assert_eq!(core.take::<f64>(), Some(1.234));
62///
63/// // we can't take a type the core isn't storing
64/// core.store(1234);
65/// assert_eq!(core.take::<f64>(), None);
66///
67/// // we can borrow both unique and shared
68/// core.store(1234);
69/// *core.borrow_mut::<i32>().unwrap() += 10;
70/// assert_eq!(core.borrow::<i32>(), Some(&1244));
71/// ```
72#[repr(transparent)]
73pub struct DungeonCore<L, V = DefaultVtable>
74where
75    L: IsLayout + Cleanup<V>,
76    V: VTable,
77{
78    /// Storage of the active value and vtable.
79    inner: <L as Cleanup<V>>::Storage,
80}
81
82// SAFETY: If the vtable and the bound are Send then the stored type must be Send.
83unsafe impl<L: IsLayout + Cleanup<V>, V: VTable> Send for DungeonCore<L, V>
84where
85    V: Send,
86    <V::Bounds as IsBound>::SendMarker: Send,
87{
88}
89
90// SAFETY: If the vtable and the bound are Sync then the stored type must be Sync.
91unsafe impl<L: IsLayout + Cleanup<V>, V: VTable> Sync for DungeonCore<L, V>
92where
93    V: Sync,
94    <V::Bounds as IsBound>::SyncMarker: Sync,
95{
96}
97
98// If the vtable and the bound are Unpin then the stored type must be Unpin.
99impl<L: IsLayout + Cleanup<V>, V: VTable> Unpin for DungeonCore<L, V>
100where
101    V: Unpin,
102    <V::Bounds as IsBound>::UnpinMarker: Unpin,
103{
104}
105
106// If the vtable and the bound are Copy then the stored type must be Copy.
107impl<L: IsLayout + Cleanup<V>, V: VTable> Copy for DungeonCore<L, V>
108where
109    V: Copy,
110    <L as Cleanup<V>>::Storage: Copy,
111{
112}
113
114// If the vtable and the bound are Clone then the stored type must be Clone.
115impl<L: IsLayout + Cleanup<V>, V: VTable> Clone for DungeonCore<L, V>
116where
117    V: Clone,
118    <L as Cleanup<V>>::Storage: Clone,
119{
120    fn clone(&self) -> Self {
121        Self {
122            inner: self.inner.clone(),
123        }
124    }
125}
126
127impl<L: IsLayout + Cleanup<V>, V: VTable> Default for DungeonCore<L, V>
128where
129    V: VTableOf<()>,
130    (): Dynamic<V::Bounds>,
131{
132    /// Create a [`DungeonCore`] storing the value `()`.
133    #[track_caller]
134    fn default() -> Self {
135        // SAFETY: The vtable is for ().
136        unsafe { Self::new_unchecked((), V::instance()) }
137    }
138}
139
140impl<L: IsLayout + Cleanup<V>, V: VTable> DungeonCore<L, V> {
141    /// Create a [`DungeonCore`] storing a value of type `T`.
142    ///
143    /// # Examples
144    /// ```
145    /// use dungeon_cell::{DungeonCore, layout_for};
146    ///
147    /// let core = DungeonCore::<layout_for!(i32)>::new(123_i32);
148    /// ```
149    #[track_caller]
150    pub const fn new<T: Dynamic<V::Bounds>>(value: T) -> Self
151    where
152        V: ConstVTableOf<T>,
153    {
154        // SAFETY: The vtable is for T.
155        unsafe { Self::new_unchecked(value, V::INSTANCE) }
156    }
157
158    /// Store a value of type `T`.
159    ///
160    /// The currently stored value will be dropped.
161    ///
162    /// # Examples
163    /// ```
164    /// use dungeon_cell::{DungeonCore, layout_for};
165    ///
166    /// let mut core = DungeonCore::<layout_for!(u8)>::default();
167    ///
168    /// core.store(4u8);
169    ///
170    /// assert_eq!(core.take::<u8>(), Some(4));
171    /// ```
172    #[track_caller]
173    pub fn store<T: Dynamic<V::Bounds>>(&mut self, value: T)
174    where
175        V: VTableOf<T>,
176    {
177        // Assert the alignment is correct because we give out borrows.
178        const_usize_assert::<AlignmentSmallerOrEqualTo<T, L::Alignment>>();
179
180        // This asserts that the size is correct so we don't have to check.
181        let buffer = Buffer::<L::Size>::new(value);
182
183        // SAFETY: The buffer has a valid value because we just made it from value.
184        // The vtable matches the value because of the safety requirements of the function.
185        let inner = unsafe { Inner::<L, V>::new(buffer, V::instance()) };
186
187        // Replace the old inner with the new value.
188        // We can now drop the value in the old_inner without causing a double drop.
189        // By dropping Inner it will automatically run the drop code for the value
190        // it is storing if it needs to.
191        //
192        // If the drop code panics then this DungeonCore has a new value to drop.
193        let _ = ::core::mem::replace(&mut self.inner, from_inner(inner));
194    }
195
196    /// Replace the value stored with a new one.
197    ///
198    /// If the currently stored value is of type `U`, then the `value` will be stored.
199    /// If the [`DungeonCore`] is storing a value of another
200    /// type, then a `Err` is returned with `value` and the stored value is unaffected.
201    ///
202    /// # Examples
203    /// ```
204    /// use dungeon_cell::{DungeonCore, layout_for};
205    ///
206    /// let mut core = DungeonCore::<layout_for!(i32)>::new(123i32);
207    ///
208    /// assert_eq!(core.replace(4u8), Ok(123i32));
209    /// assert_eq!(core.replace(()), Ok(4u8));
210    /// assert_eq!(core.replace(456i32), Err::<u8, _>(456i32));
211    /// ```
212    pub fn replace<T: Dynamic<V::Bounds>, U: Inspect<V::Id>>(
213        &mut self,
214        value: T,
215    ) -> Result<U, T>
216    where
217        V: VTableOf<T>,
218    {
219        if self.type_descriptor().is_type::<U>() {
220            let (old_value, _) = {
221                // SAFETY: The dungeon_cell is storing a value of type U,
222                // and the vtable is for the value.
223                unsafe { self.replace_unchecked(value, V::instance()) }
224            };
225
226            Ok(old_value)
227        } else {
228            Err(value)
229        }
230    }
231
232    /// Gain ownership of the value inside the [`DungeonCore`].
233    ///
234    /// This will leave the [`DungeonCore`] storing a `()` if the currently stored
235    /// value is of type `T`. If the [`DungeonCore`] is storing a value of another
236    /// type, then a `None` is returned and the stored value is unaffected.
237    ///
238    /// # Examples
239    /// ```
240    /// use dungeon_cell::{DungeonCore, layout_for};
241    ///
242    /// let mut core = DungeonCore::<layout_for!(u8)>::new(4u8);
243    ///
244    /// assert_eq!(core.take::<u8>(), Some(4));
245    /// assert_eq!(core.take::<u8>(), None);
246    /// ```
247    pub fn take<T: Inspect<V::Id>>(&mut self) -> Option<T>
248    where
249        V: VTableOf<()>,
250        (): Dynamic<V::Bounds>,
251    {
252        self.replace(()).ok()
253    }
254
255    /// Borrow the stored value.
256    ///
257    /// If the [`DungeonCore`] is storing a value of another type, then a `None` is returned.
258    ///
259    /// # Examples
260    /// ```
261    /// use dungeon_cell::{DungeonCore, layout_for};
262    ///
263    /// let core = DungeonCore::<layout_for!(u8)>::new(4u8);
264    ///
265    /// assert_eq!(core.borrow::<u8>(), Some(&4));
266    /// assert_eq!(core.borrow::<i8>(), None);
267    /// ```
268    pub fn borrow<T: Inspect<V::Id>>(&self) -> Option<&T> {
269        if self.type_descriptor().is_type::<T>() {
270            // SAFETY:
271            // We just checked that the current stored type is a `T`.
272            Some(unsafe { self.borrow_unchecked::<T>() })
273        } else {
274            None
275        }
276    }
277
278    /// Mutably borrow the stored value.
279    ///
280    /// If the [`DungeonCore`] is storing a value of another type, then a `None` is returned.
281    ///
282    /// # Examples
283    /// ```
284    /// use dungeon_cell::{DungeonCore, layout_for};
285    ///
286    /// let mut core = DungeonCore::<layout_for!(u8)>::new(4u8);
287    ///
288    /// *core.borrow_mut::<u8>().unwrap() += 2;
289    ///
290    /// assert_eq!(core.take::<u8>(), Some(6));
291    ///
292    /// assert_eq!(core.borrow_mut::<u8>(), None);
293    /// ```
294    pub fn borrow_mut<T: Inspect<V::Id>>(&mut self) -> Option<&mut T> {
295        if self.type_descriptor().is_type::<T>() {
296            // SAFETY:
297            // We just checked that the current stored type is a `T`.
298            Some(unsafe { self.borrow_mut_unchecked::<T>() })
299        } else {
300            None
301        }
302    }
303
304    /// Return type [`Descriptor`] for the currently stored value.
305    ///
306    /// descriptor.
307    ///
308    /// # Examples
309    /// ```
310    /// use dungeon_cell::{DungeonCore, layout_for};
311    /// use dungeon_cell::vtable::Descriptor;
312    ///
313    /// let core = DungeonCore::<layout_for!(i32)>::new(123i32);
314    ///
315    /// assert_eq!(*core.type_descriptor(), Descriptor::new::<i32>());
316    ///
317    /// assert_eq!(core.type_descriptor().size(), 4);
318    /// assert_eq!(core.type_descriptor().alignment(), 4);
319    /// assert_eq!(core.type_descriptor().type_name(), "i32");
320    /// ```
321    pub fn type_descriptor(&self) -> &Descriptor<V::Id> {
322        // SAFETY: We don't change the vtable and we only return the descriptor
323        // which can't mutate itself.
324        let vtable = unsafe { as_inner::<L, V>(&self.inner).vtable() };
325
326        vtable.descriptor()
327    }
328
329    /// Try to swap the values of this [`DungeonCore`] with another one.
330    ///
331    /// The values can only be swapped if they can be stored in
332    /// the opposite core. A `true` will be returned if the swap happened.
333    ///
334    /// # Examples
335    /// ```
336    /// use dungeon_cell::{DungeonCore, layout_for};
337    ///
338    /// let mut a = DungeonCore::<layout_for!(i32)>::new(123u8);
339    /// let mut b = DungeonCore::<layout_for!(i16)>::new(456u16);
340    ///
341    /// assert!(a.try_swap(&mut b));
342    ///
343    /// assert_eq!(a.take::<u16>(), Some(456));
344    /// assert_eq!(b.take::<u8>(), Some(123));
345    /// ```
346    ///
347    /// ```
348    /// use dungeon_cell::{DungeonCore, layout_for};
349    ///
350    /// let mut a = DungeonCore::<layout_for!(u8)>::new(123u8);
351    /// let mut b = DungeonCore::<layout_for!(u16)>::new(456u16);
352    ///
353    /// assert!(!a.try_swap(&mut b));
354    ///
355    /// assert_eq!(a.take::<u8>(), Some(123));
356    /// assert_eq!(b.take::<u16>(), Some(456));
357    /// ```
358    pub fn try_swap<L2: IsLayout + Cleanup<V>>(
359        &mut self,
360        other: &mut DungeonCore<L2, V>,
361    ) -> bool {
362        if self.type_descriptor().layout_can_store::<L2>()
363            && other.type_descriptor().layout_can_store::<L>()
364        {
365            let mut temp = Buffer::<L::Size>::uninit();
366
367            let (buffer, vtable) = {
368                // SAFETY: By the end of the borrow the vtable once again
369                // matches the stored value;
370                unsafe { as_inner_mut::<L, V>(&mut self.inner).parts_mut() }
371            };
372
373            let (other_buffer, other_vtable) = {
374                // SAFETY: By the end of the borrow the vtable once again
375                // matches the stored value;
376                unsafe { as_inner_mut::<L2, V>(&mut other.inner).parts_mut() }
377            };
378
379            // Other to temp.
380            // SAFETY: The other_buffer is valid to read from because it must be storing
381            // a value with size given by the vtable.
382            // Temp is nonoverlaping with it because it's a new local variable.
383            unsafe {
384                core::ptr::copy_nonoverlapping(
385                    other_buffer.as_ptr(),
386                    temp.as_mut_ptr(),
387                    other_vtable.descriptor().size(),
388                );
389            }
390
391            // Self to other.
392            // SAFETY: The buffer is valid to read from because it must be storing
393            // a value with size given by the vtable.
394            // other_buffer is nonoverlaping with it because DungeonCore owns
395            // the inner values and we got two &mut at the start.
396            unsafe {
397                core::ptr::copy_nonoverlapping(
398                    buffer.as_ptr(),
399                    other_buffer.as_mut_ptr(),
400                    vtable.descriptor().size(),
401                );
402            }
403
404            // Temp to self.
405            // SAFETY: The temp is valid to read from because it must be storing
406            // a value with size given by the vtable.
407            // Buffer is nonoverlaping with it because temp was just made above.
408            unsafe {
409                core::ptr::copy_nonoverlapping(
410                    temp.as_ptr(),
411                    buffer.as_mut_ptr(),
412                    other_vtable.descriptor().size(),
413                );
414            }
415
416            // Swap the vtables to match the new values.
417            core::mem::swap(vtable, other_vtable);
418
419            true
420        } else {
421            false
422        }
423    }
424
425    /// Convert the [`DungeonCore`] into a larger size or alignment [`DungeonCore`].
426    ///
427    /// # Examples
428    /// ```
429    /// use dungeon_cell::{DungeonCore, layout_for};
430    ///
431    /// let core = DungeonCore::<layout_for!(u8)>::new(123u8);
432    /// let mut core = core.into_larger::<layout_for!(u16)>();
433    ///
434    /// assert_eq!(core.take::<u8>(), Some(123));
435    /// ```
436    ///
437    /// ```compile_fail
438    /// # let _ = dungeon_cell::HAS_CONST_PANIC;
439    /// use dungeon_cell::{DungeonCore, layout_for};
440    ///
441    /// let core = DungeonCore::<layout_for!(u16)>::new(123u16);
442    /// let core = core.into_larger::<layout_for!(u8)>();
443    /// ```
444    pub fn into_larger<L2: IsLayout + Cleanup<V>>(self) -> DungeonCore<L2, V> {
445        // The Buffer::new below checks the size but we need to check the alignment.
446        const_usize_assert::<
447            AlignmentSmallerOrEqualTo<
448                <L::Alignment as IsAlignment>::Marker,
449                L2::Alignment,
450            >,
451        >();
452
453        let (buffer, vtable) = into_inner::<L, V>(self.inner).into_parts();
454
455        let new_buffer = Buffer::<L2::Size>::new(buffer);
456
457        // SAFETY: The vtable matches the stored value because we just got it from
458        // a DungeonCore.
459        let inner = unsafe { Inner::<L2, V>::new(new_buffer, vtable) };
460
461        DungeonCore {
462            inner: from_inner(inner),
463        }
464    }
465
466    /// Try to convert the [`DungeonCore`] into a smaller size or alignment [`DungeonCore`]
467    ///
468    /// This is only possible if the value stored can be stored in the smaller [`DungeonCore`].
469    /// A `Err` with the current [`DungeonCore`] will be returned if the value cannot be
470    /// stored in the smaller core.
471    ///
472    /// This method will return `Ok` for all cases where [`Self::into_larger()`] works.
473    ///
474    /// # Examples
475    /// ```
476    /// use dungeon_cell::{DungeonCore, layout_for};
477    ///
478    /// let core = DungeonCore::<layout_for!(u16)>::new(123u8);
479    /// let mut core = core.try_into_smaller::<layout_for!(u8)>().unwrap();
480    ///
481    /// assert_eq!(core.take::<u8>(), Some(123));
482    /// ```
483    ///
484    /// ```
485    /// use dungeon_cell::{DungeonCore, layout_for};
486    ///
487    /// let core = DungeonCore::<layout_for!(u16)>::new(123u16);
488    ///
489    /// assert!(core.try_into_smaller::<layout_for!(u8)>().is_err());
490    /// ```
491    pub fn try_into_smaller<L2: IsLayout + Cleanup<V>>(
492        self,
493    ) -> Result<DungeonCore<L2, V>, Self> {
494        if self.type_descriptor().layout_can_store::<L2>() {
495            let mut new_buffer = Buffer::<L2::Size>::uninit();
496
497            let (buffer, vtable) = into_inner::<L, V>(self.inner).into_parts();
498
499            // SAFETY: We checked above that the value in the buffer
500            // can fit in the new buffer.
501            unsafe {
502                core::ptr::copy_nonoverlapping(
503                    buffer.as_ptr(),
504                    new_buffer.as_mut_ptr(),
505                    vtable.descriptor().size(),
506                );
507            }
508
509            // SAFETY: The vtable is for the stored value because we just got
510            // it from a DungeonCore.
511            let inner = unsafe { Inner::new(new_buffer, vtable) };
512
513            // SAFETY: The vtable can drop the value in the buffer.
514            Ok(DungeonCore {
515                inner: from_inner::<L2, V>(inner),
516            })
517        } else {
518            Err(self)
519        }
520    }
521
522    pub fn into_less_bounds<Bnew>(
523        self,
524    ) -> DungeonCore<L, <V as VTableSubset<Bnew>>::Subset>
525    where
526        V: VTableSubset<Bnew>,
527        L: Cleanup<<V as VTableSubset<Bnew>>::Subset>,
528    {
529        let (buffer, vtable) = into_inner::<L, V>(self.inner).into_parts();
530
531        // SAFETY: The new vtable is for the same value because
532        // of the safety bounds on VTableSubset.
533        let inner = unsafe { Inner::new(buffer, vtable.into_subset()) };
534
535        DungeonCore {
536            inner: from_inner::<L, <V as VTableSubset<Bnew>>::Subset>(inner),
537        }
538    }
539}
540
541impl<L: IsLayout + Cleanup<V>, V: VTable> DungeonCore<L, V> {
542    /// Create [`DungeonCore`] storing a given value and vtable.
543    ///
544    /// # Safety
545    /// The `vtable` must be for the type `T`.
546    ///
547    /// A valid vtable for a type `T` can be created using
548    /// [`VTableOf`] or [`ConstVTableOf`].
549    #[track_caller]
550    pub const unsafe fn new_unchecked<T>(value: T, vtable: V) -> Self {
551        // Assert the alignment is correct because we give out borrows.
552        const_usize_assert::<AlignmentSmallerOrEqualTo<T, L::Alignment>>();
553
554        // This asserts that the size is correct so we don't have to check.
555        let buffer = Buffer::<L::Size>::new(value);
556
557        // SAFETY: The buffer has a valid value because we just made it from value.
558        // The vtable matches the value because of the safety requirements of the function.
559        let inner = unsafe { Inner::<L, V>::new(buffer, vtable) };
560
561        // Convert into the inner type.
562        DungeonCore {
563            inner: from_inner(inner),
564        }
565    }
566
567    /// Unchecked form of [Self::store].
568    ///
569    /// The stored value will be forgotten. Its drop logic will **not** be ran.
570    ///
571    /// # Safety
572    /// The `vtable` must be for the type `T`.
573    ///
574    /// A valid vtable for a type `T` can be created using
575    /// [`VTableOf`] or [`ConstVTableOf`].
576    #[track_caller]
577    pub unsafe fn store_unchecked<T>(&mut self, value: T, vtable: V) {
578        // We must check that we can store the type in the layout.
579        LayoutType::<L>::assert_can_store::<T>();
580
581        let (buffer, vtable_mut) = {
582            // SAFETY: The vtable is for the stored value once the borrow ends.
583            unsafe { as_inner_mut::<L, V>(&mut self.inner).parts_mut() }
584        };
585
586        // SAFETY: We checked above that the type cal be stored in the layout.
587        unsafe { move_into_buffer(buffer, value) };
588
589        // A panic can't happen here.
590
591        // Set the current type to `T`.
592        *vtable_mut = vtable;
593    }
594
595    /// Unchecked form of [`Self::replace`].
596    ///
597    /// The vtable instance for the value is also returned.
598    ///
599    /// # Safety
600    /// - The [`DungeonCore`] must be storing a valid value of type `U`.
601    /// - The `vtable` must be for the type `T`.
602    pub unsafe fn replace_unchecked<T, U>(
603        &mut self,
604        value: T,
605        vtable: V,
606    ) -> (U, V) {
607        // Assert the alignment is correct because we give out borrows.
608        const_usize_assert::<AlignmentSmallerOrEqualTo<T, L::Alignment>>();
609
610        // This asserts that the size is correct so we don't have to check.
611        let buffer = Buffer::<L::Size>::new(value);
612
613        // SAFETY: The buffer has a valid value because we just made it from value.
614        // The vtable matches the value because of the safety requirements of the function.
615        let inner = unsafe { Inner::<L, V>::new(buffer, vtable) };
616
617        // Replace the old inner with the new value.
618        let old_inner =
619            ::core::mem::replace(&mut self.inner, from_inner(inner));
620
621        // Convert old inner into the buffer and vtable.
622        let (buffer, vtable) = into_inner::<L, V>(old_inner).into_parts();
623
624        // Convert the buffer back into a value.
625        // SAFETY: We know this is a value of U because of the safety requirements
626        // of the function.
627        let old_value = unsafe { Buffer::into_value::<U>(buffer) };
628
629        (old_value, vtable)
630    }
631
632    /// Unchecked form of [Self::borrow].
633    ///
634    /// # Safety
635    /// The [`DungeonCore`] must be storing a valid value of type `T`.
636    pub unsafe fn borrow_unchecked<T>(&self) -> &T {
637        let data = as_inner::<L, V>(&self.inner).buffer();
638
639        // SAFETY: The function safety requirements require that the core
640        // is storing a value of `T`.
641        unsafe { buffer_as_type::<T>(data) }
642    }
643
644    /// Unchecked form of [Self::borrow_mut].
645    ///
646    /// # Safety
647    /// The [`DungeonCore`] must be storing a valid value of type `T`.
648    pub unsafe fn borrow_mut_unchecked<T>(&mut self) -> &mut T {
649        let data = {
650            // SAFETY: The value type is not changed.
651            unsafe { as_inner_mut::<L, V>(&mut self.inner).buffer_mut() }
652        };
653
654        // SAFETY: The function safety requirements require that the core
655        // is storing a value of `T`.
656        unsafe { buffer_as_type_mut::<T>(data) }
657    }
658
659    /// Get the internal vtable and buffer of the [`DungeonCore`].
660    ///
661    /// # Invariants
662    /// The buffer contains a valid value of the type the vtable is for.
663    /// The buffer has the layout described by generic `L`.
664    /// The type implements the bounds given by `B`.
665    ///
666    /// # Safety
667    /// After the borrow of `self` ends, the buffer must still contain a valid
668    /// value of the type the vtable is for. The vtable must be valid in the event of a panic.
669    pub const unsafe fn raw_internals(&self) -> (&[MaybeUninit<u8>], &V) {
670        // SAFETY: The safety requirements of the function require that
671        // the vtable is for the value after the borroe ends.
672        unsafe { as_inner::<L, V>(&self.inner).parts() }
673    }
674
675    /// Get the internal vtable and buffer of the [`DungeonCore`] mutably.
676    ///
677    /// # Invariants
678    /// The buffer contains a valid value of the type the vtable is for.
679    /// The buffer has the layout described by generic `L`.
680    /// The type implements the bounds given by `B`.
681    ///
682    /// # Safety
683    /// After the borrow of `self` ends, the buffer must still contain a valid
684    /// value of the type the vtable is for. Both the vtable and value in the buffer
685    /// can change. The vtable and buffer must be valid in the event of a panic.
686    pub unsafe fn raw_internals_mut(
687        &mut self,
688    ) -> (&mut [MaybeUninit<u8>], &mut V) {
689        // SAFETY: The safety requirements of the function require that
690        // the vtable is for the value after the borroe ends.
691        unsafe { as_inner_mut::<L, V>(&mut self.inner).parts_mut() }
692    }
693
694    /// Convert into the internal vtable and buffer.
695    pub const fn into_raw_internals(self) -> (Buffer<L::Size>, V) {
696        // SAFETY: DungeonCore is `repr(transparent)` to the inner type.
697        let inner = unsafe { const_transmute(self) };
698
699        into_inner::<L, V>(inner).into_parts()
700    }
701}
702
703impl<L: IsLayout + Cleanup<V>, V: VTable> core::fmt::Debug
704    for DungeonCore<L, V>
705{
706    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
707        // SAFETY: The value of the vtable is not changed.
708        let (buffer, vtable) = unsafe { as_inner::<L, V>(&self.inner).parts() };
709
710        if <V::Bounds as IsBound>::BOUND_BY_DEBUG {
711            // SAFETY: We checked that the bound has Debug.
712            unsafe { vtable.bound_impl().debug_value(buffer.as_ptr(), f) }
713        } else {
714            f.debug_struct("DungeonCore")
715                .field("type_name", &vtable.descriptor().type_name())
716                .field("size", &vtable.descriptor().size())
717                .field("alignment", &vtable.descriptor().alignment())
718                .finish()
719        }
720    }
721}
722
723/// Move a value into a byte buffer.
724///
725/// The buffer will gain ownership of the value.
726///
727/// # Safety
728/// The `buffer` slice must be the size and alignment of `T` (or bigger).
729unsafe fn move_into_buffer<T>(buffer: &mut [MaybeUninit<u8>], value: T) {
730    // Wrap the value so we can manually move it.
731    // `value` will be considered invalid after the read below.
732    let value = MaybeUninit::new(value);
733
734    // Get a pointer to the aligned buffer.
735    // This is done in long form to make it easier to read.
736    let buffer: *mut [MaybeUninit<u8>] = buffer as _;
737    let buffer: *mut MaybeUninit<T> = buffer.cast();
738
739    // Manually move the value out of binding `value`.
740
741    // SAFETY:
742    // `value` is valid for a read because we just made it above
743    // from a valid value.
744    //
745    // `buffer` is valid for a write because of the safety requirements
746    // for the outer function.
747    //
748    // They do not overlap.
749    unsafe {
750        core::ptr::copy_nonoverlapping(addr_of!(value), buffer, 1);
751    }
752
753    // Value will not have it's drop code run.
754}
755
756/// View a byte buffer as a type `T`.
757///
758/// # Safety
759/// The `buffer` slice must contain a value of type `T`.
760unsafe fn buffer_as_type<T>(buffer: &[MaybeUninit<u8>]) -> &T {
761    // Get a pointer to the aligned buffer.
762    // This is done in long form to make it easier to read.
763    let buffer: *const [MaybeUninit<u8>] = buffer as _;
764    let buffer: *const MaybeUninit<T> = buffer.cast();
765
766    // SAFETY:
767    // We just borrowed `buffer` so it's valid to dereference.
768    let buffer: &MaybeUninit<T> = unsafe { &*buffer };
769
770    // SAFETY:
771    // The outer safety requirements makes this valid.
772    // `buffer` is a valid value of `T`.
773    unsafe { buffer.assume_init_ref() }
774}
775
776/// View a mutable byte buffer as a type `T`.
777///
778/// # Safety
779/// The `buffer` slice must contain a value of type `T`.
780unsafe fn buffer_as_type_mut<T>(buffer: &mut [MaybeUninit<u8>]) -> &mut T {
781    // Get a pointer to the aligned buffer.
782    // This is done in long form to make it easier to read.
783    let buffer: *mut [MaybeUninit<u8>] = buffer as _;
784    let buffer: *mut MaybeUninit<T> = buffer.cast();
785
786    // SAFETY:
787    // We just borrowed `buffer` so it's valid to dereference.
788    let buffer: &mut MaybeUninit<T> = unsafe { &mut *buffer };
789
790    // SAFETY:
791    // The outer safety requirements makes this valid.
792    // `buffer` is a valid value of `T`.
793    unsafe { buffer.assume_init_mut() }
794}
795
796#[cfg(test)]
797mod test {
798    // use crate::{vtable::{Descriptor, CoreVTable}, Prison};
799
800    #[test]
801    fn a() {
802        // type X = Prison<&'static CoreVTable>;
803        // let x: Descriptor<X> = Descriptor::of::<u8>();
804        //
805        // let x: Descriptor<X> = Descriptor::<X>::of::<u8>();
806    }
807}