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}