Skip to main content

intuicio_data/managed/
mod.rs

1//! Value boxes with runtime checked borrowing.
2//!
3//! A managed box is an owner plus a [`Lifetime`],
4//! so handles to it can be handed to a script and still be checked at
5//! runtime. When the owner goes away, every handle reports it instead of
6//! dangling.
7//!
8//! # The four roles
9//!
10//! | Role | Typed | Type-erased |
11//! |------|-------|-------------|
12//! | owns the value | [`Managed`] | [`DynamicManaged`] |
13//! | shared handle | [`ManagedRef`] | [`DynamicManagedRef`] |
14//! | exclusive handle | [`ManagedRefMut`] | [`DynamicManagedRefMut`] |
15//! | unclaimed handle | [`ManagedLazy`] | [`DynamicManagedLazy`] |
16//!
17//! The typed boxes know their Rust type at compile time. The dynamic ones
18//! carry a [`TypeHash`] instead and check it on every access, which is what
19//! script values use. `into_dynamic` and `into_typed` convert between them.
20//!
21//! Two more shapes build on these: [`value`] wraps all roles in one enum, so
22//! code can accept a value without caring how it is held, and [`gc`] adds
23//! boxes that survive reference cycles.
24//!
25//! ```
26//! # use intuicio_data::managed::Managed;
27//! let mut value = Managed::new(42);
28//! let borrow = value.borrow().unwrap();
29//! // a shared handle is out, so an exclusive one is refused
30//! assert!(value.borrow_mut().is_none());
31//! assert_eq!(*borrow.read().unwrap(), 42);
32//! ```
33pub mod gc;
34pub mod value;
35
36use crate::{
37    Finalize, Finalizer,
38    lifetime::{
39        Lifetime, LifetimeLazy, LifetimeRef, LifetimeRefMut, ValueReadAccess, ValueWriteAccess,
40    },
41    managed::value::{DynamicManagedValue, ManagedValue},
42    non_zero_alloc, non_zero_dealloc,
43    type_hash::TypeHash,
44};
45use std::{alloc::Layout, cell::UnsafeCell, mem::MaybeUninit};
46
47/// Owner of a value plus its runtime borrow state.
48///
49/// The value is stored inline, so this is just `T` with a lifetime attached.
50/// Handles taken from it go dead when it is dropped. See the
51/// [module docs](self).
52///
53/// The value sits in an [`UnsafeCell`] because handles keep raw pointers to
54/// it. A pointer taken out of a plain field is derived from a borrow of the
55/// box. A later `&mut self` method invalidates that borrow, which makes every
56/// live handle unsound. [`UnsafeCell`] marks the value as shared mutable, so
57/// pointers taken from the value stay valid.
58#[derive(Default)]
59pub struct Managed<T> {
60    lifetime: Lifetime,
61    data: UnsafeCell<T>,
62}
63
64/// # Safety
65///
66/// The value is only reachable through the lifetime, which does the borrow
67/// checks at runtime. That makes the [`UnsafeCell`] safe to share.
68unsafe impl<T> Sync for Managed<T> where T: Sync {}
69
70impl<T> Managed<T> {
71    /// Takes ownership of a value with a fresh lifetime.
72    pub fn new(data: T) -> Self {
73        Self {
74            lifetime: Default::default(),
75            data: UnsafeCell::new(data),
76        }
77    }
78
79    /// Takes ownership of a value with a lifetime prepared elsewhere.
80    pub fn new_raw(data: T, lifetime: Lifetime) -> Self {
81        Self {
82            lifetime,
83            data: UnsafeCell::new(data),
84        }
85    }
86
87    /// Splits into the lifetime and the value, dropping no handles.
88    pub fn into_inner(self) -> (Lifetime, T) {
89        (self.lifetime, self.data.into_inner())
90    }
91
92    /// Moves the value into a type-erased box, giving `self` back when the
93    /// allocation fails.
94    ///
95    /// The lifetime is not carried over, so handles taken so far go dead.
96    pub fn into_dynamic(self) -> Result<DynamicManaged, Self> {
97        match DynamicManaged::new(self.data.into_inner()) {
98            Ok(value) => Ok(value),
99            Err(data) => Err(Managed {
100                lifetime: self.lifetime,
101                data: UnsafeCell::new(data),
102            }),
103        }
104    }
105
106    /// Replaces the lifetime, killing every handle taken so far.
107    pub fn renew(mut self) -> Self {
108        self.lifetime = Lifetime::default();
109        self
110    }
111
112    /// Returns the borrow state of this value.
113    pub fn lifetime(&self) -> &Lifetime {
114        &self.lifetime
115    }
116
117    /// Guards the value for reading, or returns [`None`] while it is written.
118    pub fn read(&'_ self) -> Option<ValueReadAccess<'_, T>> {
119        unsafe { self.lifetime.read_ptr(self.data.get() as *const T) }
120    }
121
122    /// Guards the value for writing, or returns [`None`] while it is accessed.
123    pub fn write(&'_ mut self) -> Option<ValueWriteAccess<'_, T>> {
124        unsafe { self.lifetime.write_ptr(self.data.get()) }
125    }
126
127    /// Takes the value out, or gives the box back while any access guard is
128    /// live.
129    pub fn consume(self) -> Result<T, Self> {
130        if self.lifetime.state().is_in_use() {
131            Err(self)
132        } else {
133            Ok(self.data.into_inner())
134        }
135    }
136
137    /// Moves the value into the place `target` points at.
138    ///
139    /// # Panics
140    ///
141    /// Panics when `target` cannot be written.
142    pub fn move_into_ref(self, mut target: ManagedRefMut<T>) -> Result<(), Self> {
143        *target.write().unwrap() = self.consume()?;
144        Ok(())
145    }
146
147    /// Moves the value into the place `target` points at.
148    ///
149    /// # Panics
150    ///
151    /// Panics when `target` cannot be written.
152    pub fn move_into_lazy(self, target: ManagedLazy<T>) -> Result<(), Self> {
153        *target.write().unwrap() = self.consume()?;
154        Ok(())
155    }
156
157    /// Takes a shared handle, or returns [`None`] when an exclusive one is out.
158    pub fn borrow(&self) -> Option<ManagedRef<T>> {
159        Some(ManagedRef {
160            lifetime: self.lifetime.borrow()?,
161            data: self.data.get(),
162        })
163    }
164
165    /// Takes an exclusive handle, or returns [`None`] when any handle is out.
166    pub fn borrow_mut(&mut self) -> Option<ManagedRefMut<T>> {
167        Some(ManagedRefMut {
168            lifetime: self.lifetime.borrow_mut()?,
169            data: self.data.get(),
170        })
171    }
172
173    /// Takes an unclaimed handle.
174    pub fn lazy(&mut self) -> ManagedLazy<T> {
175        ManagedLazy {
176            lifetime: self.lifetime.lazy(),
177            data: self.data.get(),
178        }
179    }
180
181    /// [`Managed::lazy`] from a shared reference.
182    ///
183    /// # Safety
184    ///
185    /// The returned handle can write to a value the caller only borrowed
186    /// immutably. Only use it when nothing else holds a `&T` to it.
187    pub unsafe fn lazy_immutable(&self) -> ManagedLazy<T> {
188        ManagedLazy {
189            lifetime: self.lifetime.lazy(),
190            data: self.data.get(),
191        }
192    }
193
194    /// Replaces the value with one built from it, under a fresh lifetime.
195    ///
196    /// # Safety
197    ///
198    /// Handles taken so far are not checked before the value is moved out, and
199    /// they go dead. Nothing may be accessing the value.
200    pub unsafe fn map<U>(self, f: impl FnOnce(T) -> U) -> Managed<U> {
201        Managed {
202            lifetime: Default::default(),
203            data: UnsafeCell::new(f(self.data.into_inner())),
204        }
205    }
206
207    /// [`Managed::map`] that can decline, dropping the value when it does.
208    ///
209    /// # Safety
210    ///
211    /// Same as [`Managed::map`].
212    pub unsafe fn try_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Managed<U>> {
213        f(self.data.into_inner()).map(|data| Managed {
214            lifetime: Default::default(),
215            data: UnsafeCell::new(data),
216        })
217    }
218
219    /// Returns a pointer to the value, bypassing the borrow state.
220    ///
221    /// # Safety
222    ///
223    /// The caller takes over checking for conflicting access, and must not
224    /// outlive this box.
225    pub unsafe fn as_ptr(&self) -> *const T {
226        self.data.get() as *const T
227    }
228
229    /// Returns a mutable pointer to the value, bypassing the borrow state.
230    ///
231    /// # Safety
232    ///
233    /// The caller takes over checking for conflicting access, and must not
234    /// outlive this box.
235    pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
236        self.data.get()
237    }
238}
239
240/// Shared handle to a value owned by a [`Managed`], the runtime `&T`.
241///
242/// Keeps its claim until dropped, and reports a dead owner by returning
243/// [`None`] from [`ManagedRef::read`].
244pub struct ManagedRef<T: ?Sized> {
245    lifetime: LifetimeRef,
246    data: *const T,
247}
248
249unsafe impl<T: ?Sized> Send for ManagedRef<T> where T: Send {}
250unsafe impl<T: ?Sized> Sync for ManagedRef<T> where T: Sync {}
251
252impl<T: ?Sized> ManagedRef<T> {
253    /// Pairs a reference with a shared borrow taken from its lifetime.
254    pub fn new(data: &T, lifetime: LifetimeRef) -> Self {
255        Self {
256            lifetime,
257            data: data as *const T,
258        }
259    }
260
261    /// [`ManagedRef::new`] over a raw pointer. A null pointer yields [`None`].
262    ///
263    /// # Safety
264    ///
265    /// `data` must stay valid for as long as `lifetime` says it does, and
266    /// `lifetime` must be the borrow state that guards it.
267    pub unsafe fn new_raw(data: *const T, lifetime: LifetimeRef) -> Option<Self> {
268        if data.is_null() {
269            None
270        } else {
271            Some(Self { lifetime, data })
272        }
273    }
274
275    /// Builds a handle to a plain reference along with the lifetime that backs
276    /// it.
277    ///
278    /// The caller has to keep the returned [`Lifetime`] alive for at least as
279    /// long as the handle.
280    pub fn make(data: &T) -> (Self, Lifetime) {
281        let result = Lifetime::default();
282        (Self::new(data, result.borrow().unwrap()), result)
283    }
284
285    /// [`ManagedRef::make`] over a raw pointer.
286    ///
287    /// # Safety
288    ///
289    /// `data` must stay valid for as long as the returned handle lives.
290    pub unsafe fn make_raw(data: *const T) -> Option<(Self, Lifetime)> {
291        let result = Lifetime::default();
292        Some((
293            unsafe { Self::new_raw(data, result.borrow().unwrap()) }?,
294            result,
295        ))
296    }
297
298    /// Splits into the borrow token and the pointer.
299    pub fn into_inner(self) -> (LifetimeRef, *const T) {
300        (self.lifetime, self.data)
301    }
302
303    /// Erases the type, keeping the same claim.
304    pub fn into_dynamic(self) -> DynamicManagedRef {
305        unsafe {
306            DynamicManagedRef::new_raw(TypeHash::of::<T>(), self.lifetime, self.data as *const u8)
307                .unwrap()
308        }
309    }
310
311    /// Returns the borrow token.
312    pub fn lifetime(&self) -> &LifetimeRef {
313        &self.lifetime
314    }
315
316    /// Takes another shared handle to the same value.
317    pub fn borrow(&self) -> Option<ManagedRef<T>> {
318        Some(ManagedRef {
319            lifetime: self.lifetime.borrow()?,
320            data: self.data,
321        })
322    }
323
324    /// Turns this shared handle into an unclaimed one that can also write.
325    ///
326    /// # Safety
327    ///
328    /// The value was only borrowed immutably, so writing through the result is
329    /// only sound when nothing else holds a `&T` to it.
330    pub unsafe fn lazy_immutable(&self) -> ManagedLazy<T> {
331        ManagedLazy {
332            lifetime: self.lifetime.lazy(),
333            data: self.data as *mut T,
334        }
335    }
336
337    /// Guards the value for reading, or returns [`None`] when it is written or
338    /// the owner is gone.
339    pub fn read(&'_ self) -> Option<ValueReadAccess<'_, T>> {
340        unsafe { self.lifetime.read_ptr(self.data) }
341    }
342
343    /// Narrows this handle down to a part of the value, such as one field.
344    ///
345    /// # Safety
346    ///
347    /// `f` must return a reference into the same value, and the owner must
348    /// still be alive.
349    pub unsafe fn map<U>(self, f: impl FnOnce(&T) -> &U) -> ManagedRef<U> {
350        unsafe {
351            let data = f(&*self.data);
352            ManagedRef {
353                lifetime: self.lifetime,
354                data: data as *const U,
355            }
356        }
357    }
358
359    /// [`ManagedRef::map`] that can decline.
360    ///
361    /// # Safety
362    ///
363    /// Same as [`ManagedRef::map`].
364    pub unsafe fn try_map<U>(self, f: impl FnOnce(&T) -> Option<&U>) -> Option<ManagedRef<U>> {
365        unsafe {
366            f(&*self.data).map(|data| ManagedRef {
367                lifetime: self.lifetime,
368                data: data as *const U,
369            })
370        }
371    }
372
373    /// Returns the pointer while the owner is alive, bypassing access checks.
374    ///
375    /// # Safety
376    ///
377    /// The caller takes over checking for conflicting access.
378    pub unsafe fn as_ptr(&self) -> Option<*const T> {
379        if self.lifetime.exists() {
380            Some(self.data)
381        } else {
382            None
383        }
384    }
385}
386
387impl<T> TryFrom<ManagedValue<T>> for ManagedRef<T> {
388    type Error = ();
389
390    fn try_from(value: ManagedValue<T>) -> Result<Self, Self::Error> {
391        match value {
392            ManagedValue::Ref(value) => Ok(value),
393            _ => Err(()),
394        }
395    }
396}
397
398/// Exclusive handle to a value owned by a [`Managed`], the runtime `&mut T`.
399///
400/// Can be reborrowed, both shared and exclusive, one level deeper.
401pub struct ManagedRefMut<T: ?Sized> {
402    lifetime: LifetimeRefMut,
403    data: *mut T,
404}
405
406unsafe impl<T: ?Sized> Send for ManagedRefMut<T> where T: Send {}
407unsafe impl<T: ?Sized> Sync for ManagedRefMut<T> where T: Sync {}
408
409impl<T: ?Sized> ManagedRefMut<T> {
410    /// Pairs a mutable reference with an exclusive borrow of its lifetime.
411    pub fn new(data: &mut T, lifetime: LifetimeRefMut) -> Self {
412        Self {
413            lifetime,
414            data: data as *mut T,
415        }
416    }
417
418    /// [`ManagedRefMut::new`] over a raw pointer. A null pointer yields
419    /// [`None`].
420    ///
421    /// # Safety
422    ///
423    /// `data` must stay valid and unaliased for as long as `lifetime` says it
424    /// does, and `lifetime` must be the borrow state that guards it.
425    pub unsafe fn new_raw(data: *mut T, lifetime: LifetimeRefMut) -> Option<Self> {
426        if data.is_null() {
427            None
428        } else {
429            Some(Self { lifetime, data })
430        }
431    }
432
433    /// Builds a handle to a plain mutable reference along with the lifetime that
434    /// backs it.
435    ///
436    /// The caller has to keep the returned [`Lifetime`] alive for at least as
437    /// long as the handle.
438    pub fn make(data: &mut T) -> (Self, Lifetime) {
439        let result = Lifetime::default();
440        (Self::new(data, result.borrow_mut().unwrap()), result)
441    }
442
443    /// [`ManagedRefMut::make`] over a raw pointer.
444    ///
445    /// # Safety
446    ///
447    /// `data` must stay valid and unaliased for as long as the returned handle
448    /// lives.
449    pub unsafe fn make_raw(data: *mut T) -> Option<(Self, Lifetime)> {
450        let result = Lifetime::default();
451        Some((
452            unsafe { Self::new_raw(data, result.borrow_mut().unwrap()) }?,
453            result,
454        ))
455    }
456
457    /// Splits into the borrow token and the pointer.
458    pub fn into_inner(self) -> (LifetimeRefMut, *mut T) {
459        (self.lifetime, self.data)
460    }
461
462    /// Erases the type, keeping the same claim.
463    pub fn into_dynamic(self) -> DynamicManagedRefMut {
464        unsafe {
465            DynamicManagedRefMut::new_raw(TypeHash::of::<T>(), self.lifetime, self.data as *mut u8)
466                .unwrap()
467        }
468    }
469
470    /// Returns the borrow token.
471    pub fn lifetime(&self) -> &LifetimeRefMut {
472        &self.lifetime
473    }
474
475    /// Takes a shared handle nested under this one.
476    pub fn borrow(&self) -> Option<ManagedRef<T>> {
477        Some(ManagedRef {
478            lifetime: self.lifetime.borrow()?,
479            data: self.data,
480        })
481    }
482
483    /// Takes an exclusive handle nested under this one.
484    pub fn borrow_mut(&mut self) -> Option<ManagedRefMut<T>> {
485        Some(ManagedRefMut {
486            lifetime: self.lifetime.borrow_mut()?,
487            data: self.data,
488        })
489    }
490
491    /// Takes an unclaimed handle.
492    pub fn lazy(&self) -> ManagedLazy<T> {
493        ManagedLazy {
494            lifetime: self.lifetime.lazy(),
495            data: self.data,
496        }
497    }
498
499    /// Guards the value for reading, or returns [`None`] when it is written or
500    /// the owner is gone.
501    pub fn read(&'_ self) -> Option<ValueReadAccess<'_, T>> {
502        unsafe { self.lifetime.read_ptr(self.data) }
503    }
504
505    /// Guards the value for writing, or returns [`None`] when it is accessed or
506    /// the owner is gone.
507    pub fn write(&'_ mut self) -> Option<ValueWriteAccess<'_, T>> {
508        unsafe { self.lifetime.write_ptr(self.data) }
509    }
510
511    /// Narrows this handle down to a part of the value, such as one field.
512    ///
513    /// # Safety
514    ///
515    /// `f` must return a reference into the same value, and the owner must
516    /// still be alive.
517    pub unsafe fn map<U>(self, f: impl FnOnce(&mut T) -> &mut U) -> ManagedRefMut<U> {
518        unsafe {
519            let data = f(&mut *self.data);
520            ManagedRefMut {
521                lifetime: self.lifetime,
522                data: data as *mut U,
523            }
524        }
525    }
526
527    /// [`ManagedRefMut::map`] that can decline.
528    ///
529    /// # Safety
530    ///
531    /// Same as [`ManagedRefMut::map`].
532    pub unsafe fn try_map<U>(
533        self,
534        f: impl FnOnce(&mut T) -> Option<&mut U>,
535    ) -> Option<ManagedRefMut<U>> {
536        unsafe {
537            f(&mut *self.data).map(|data| ManagedRefMut {
538                lifetime: self.lifetime,
539                data: data as *mut U,
540            })
541        }
542    }
543
544    /// Returns the pointer while the owner is alive, bypassing access checks.
545    ///
546    /// # Safety
547    ///
548    /// The caller takes over checking for conflicting access.
549    pub unsafe fn as_ptr(&self) -> Option<*const T> {
550        if self.lifetime.exists() {
551            Some(self.data)
552        } else {
553            None
554        }
555    }
556
557    /// Returns the mutable pointer while the owner is alive, bypassing access
558    /// checks.
559    ///
560    /// # Safety
561    ///
562    /// The caller takes over checking for conflicting access.
563    pub unsafe fn as_mut_ptr(&mut self) -> Option<*mut T> {
564        if self.lifetime.exists() {
565            Some(self.data)
566        } else {
567            None
568        }
569    }
570}
571
572impl<T> TryFrom<ManagedValue<T>> for ManagedRefMut<T> {
573    type Error = ();
574
575    fn try_from(value: ManagedValue<T>) -> Result<Self, Self::Error> {
576        match value {
577            ManagedValue::RefMut(value) => Ok(value),
578            _ => Err(()),
579        }
580    }
581}
582
583/// Unclaimed handle to a value owned by a [`Managed`].
584///
585/// Holding one blocks nobody, and it can be cloned freely. Every access is
586/// checked when it happens. This is the handle a script variable holds, because
587/// such a variable is read and written at any point, with no Rust borrow to
588/// model it.
589pub struct ManagedLazy<T: ?Sized> {
590    lifetime: LifetimeLazy,
591    data: *mut T,
592}
593
594unsafe impl<T: ?Sized> Send for ManagedLazy<T> where T: Send {}
595unsafe impl<T: ?Sized> Sync for ManagedLazy<T> where T: Sync {}
596
597impl<T: ?Sized> Clone for ManagedLazy<T> {
598    fn clone(&self) -> Self {
599        Self {
600            lifetime: self.lifetime.clone(),
601            data: self.data,
602        }
603    }
604}
605
606impl<T: ?Sized> ManagedLazy<T> {
607    /// Pairs a mutable reference with an unclaimed handle to its lifetime.
608    pub fn new(data: &mut T, lifetime: LifetimeLazy) -> Self {
609        Self {
610            lifetime,
611            data: data as *mut T,
612        }
613    }
614
615    /// [`ManagedLazy::new`] over a raw pointer. A null pointer yields [`None`].
616    ///
617    /// # Safety
618    ///
619    /// `data` must stay valid for as long as `lifetime` says it does, and
620    /// `lifetime` must be the borrow state that guards it.
621    pub unsafe fn new_raw(data: *mut T, lifetime: LifetimeLazy) -> Option<Self> {
622        if data.is_null() {
623            None
624        } else {
625            Some(Self { lifetime, data })
626        }
627    }
628
629    /// Builds a handle to a plain mutable reference along with the lifetime that
630    /// backs it.
631    ///
632    /// The caller has to keep the returned [`Lifetime`] alive for at least as
633    /// long as the handle.
634    pub fn make(data: &mut T) -> (Self, Lifetime) {
635        let result = Lifetime::default();
636        (Self::new(data, result.lazy()), result)
637    }
638
639    /// [`ManagedLazy::make`] over a raw pointer.
640    ///
641    /// # Safety
642    ///
643    /// `data` must stay valid for as long as the returned handle lives.
644    pub unsafe fn make_raw(data: *mut T) -> Option<(Self, Lifetime)> {
645        let result = Lifetime::default();
646        Some((unsafe { Self::new_raw(data, result.lazy()) }?, result))
647    }
648
649    /// Splits into the lifetime handle and the pointer.
650    pub fn into_inner(self) -> (LifetimeLazy, *mut T) {
651        (self.lifetime, self.data)
652    }
653
654    /// Erases the type, keeping the same handle.
655    pub fn into_dynamic(self) -> DynamicManagedLazy {
656        unsafe {
657            DynamicManagedLazy::new_raw(TypeHash::of::<T>(), self.lifetime, self.data as *mut u8)
658                .unwrap()
659        }
660    }
661
662    /// Returns the lifetime handle.
663    pub fn lifetime(&self) -> &LifetimeLazy {
664        &self.lifetime
665    }
666
667    /// Upgrades to a shared handle that holds its claim.
668    pub fn borrow(&self) -> Option<ManagedRef<T>> {
669        Some(ManagedRef {
670            lifetime: self.lifetime.borrow()?,
671            data: self.data,
672        })
673    }
674
675    /// Upgrades to an exclusive handle that holds its claim.
676    pub fn borrow_mut(&mut self) -> Option<ManagedRefMut<T>> {
677        Some(ManagedRefMut {
678            lifetime: self.lifetime.borrow_mut()?,
679            data: self.data,
680        })
681    }
682
683    /// Guards the value for reading, or returns [`None`] when it is written or
684    /// the owner is gone.
685    pub fn read(&'_ self) -> Option<ValueReadAccess<'_, T>> {
686        unsafe { self.lifetime.read_ptr(self.data) }
687    }
688
689    /// Guards the value for writing, or returns [`None`] when it is accessed or
690    /// the owner is gone.
691    ///
692    /// Takes `&self`, since a lazy handle claims nothing of its own.
693    pub fn write(&'_ self) -> Option<ValueWriteAccess<'_, T>> {
694        unsafe { self.lifetime.write_ptr(self.data) }
695    }
696
697    /// Narrows this handle down to a part of the value, such as one field.
698    ///
699    /// # Safety
700    ///
701    /// `f` must return a reference into the same value, and the owner must
702    /// still be alive.
703    pub unsafe fn map<U>(self, f: impl FnOnce(&mut T) -> &mut U) -> ManagedLazy<U> {
704        unsafe {
705            let data = f(&mut *self.data);
706            ManagedLazy {
707                lifetime: self.lifetime,
708                data: data as *mut U,
709            }
710        }
711    }
712
713    /// [`ManagedLazy::map`] that can decline.
714    ///
715    /// # Safety
716    ///
717    /// Same as [`ManagedLazy::map`].
718    pub unsafe fn try_map<U>(
719        self,
720        f: impl FnOnce(&mut T) -> Option<&mut U>,
721    ) -> Option<ManagedLazy<U>> {
722        unsafe {
723            f(&mut *self.data).map(|data| ManagedLazy {
724                lifetime: self.lifetime,
725                data: data as *mut U,
726            })
727        }
728    }
729
730    /// Returns the pointer while the owner is alive, bypassing access checks.
731    ///
732    /// # Safety
733    ///
734    /// The caller takes over checking for conflicting access.
735    pub unsafe fn as_ptr(&self) -> Option<*const T> {
736        if self.lifetime.exists() {
737            Some(self.data)
738        } else {
739            None
740        }
741    }
742
743    /// Returns the mutable pointer while the owner is alive, bypassing access
744    /// checks.
745    ///
746    /// # Safety
747    ///
748    /// The caller takes over checking for conflicting access.
749    pub unsafe fn as_mut_ptr(&self) -> Option<*mut T> {
750        if self.lifetime.exists() {
751            Some(self.data)
752        } else {
753            None
754        }
755    }
756}
757
758impl<T> TryFrom<ManagedValue<T>> for ManagedLazy<T> {
759    type Error = ();
760
761    fn try_from(value: ManagedValue<T>) -> Result<Self, Self::Error> {
762        match value {
763            ManagedValue::Lazy(value) => Ok(value),
764            _ => Err(()),
765        }
766    }
767}
768
769/// Owner of a value whose type is only known at runtime.
770///
771/// The [`Managed`] counterpart for script values: the value lives in its own
772/// allocation, identified by a [`TypeHash`] and destroyed through a stored
773/// drop function. Every typed access checks the hash first.
774pub struct DynamicManaged {
775    type_hash: TypeHash,
776    lifetime: Lifetime,
777    memory: *mut u8,
778    layout: Layout,
779    finalizer: Finalizer,
780    drop: bool,
781}
782
783unsafe impl Send for DynamicManaged {}
784unsafe impl Sync for DynamicManaged {}
785
786impl Drop for DynamicManaged {
787    fn drop(&mut self) {
788        if self.drop {
789            unsafe {
790                if self.memory.is_null() {
791                    return;
792                }
793                let data_pointer = self.memory.cast::<()>();
794                self.finalizer.finalize(data_pointer);
795                non_zero_dealloc(self.memory, self.layout);
796                self.memory = std::ptr::null_mut();
797            }
798        }
799    }
800}
801
802impl DynamicManaged {
803    /// Moves a value into a new allocation, giving it back when the allocation
804    /// fails.
805    pub fn new<T: Finalize>(data: T) -> Result<Self, T> {
806        let layout = Layout::new::<T>().pad_to_align();
807        unsafe {
808            let memory = non_zero_alloc(layout);
809            if memory.is_null() {
810                Err(data)
811            } else {
812                memory.cast::<T>().write(data);
813                Ok(Self {
814                    type_hash: TypeHash::of::<T>(),
815                    lifetime: Default::default(),
816                    memory,
817                    layout,
818                    finalizer: Finalizer::of::<T>(),
819                    drop: true,
820                })
821            }
822        }
823    }
824
825    /// Takes ownership of an existing allocation.
826    ///
827    /// Returns [`None`] for a null pointer. The box will free `memory` and run
828    /// `finalizer` on drop.
829    pub fn new_raw(
830        type_hash: TypeHash,
831        lifetime: Lifetime,
832        memory: *mut u8,
833        layout: Layout,
834        finalizer: impl Into<Finalizer>,
835    ) -> Option<Self> {
836        if memory.is_null() {
837            None
838        } else {
839            Some(Self {
840                type_hash,
841                lifetime,
842                memory,
843                layout,
844                finalizer: finalizer.into(),
845                drop: true,
846            })
847        }
848    }
849
850    /// Allocates room for a value without writing one into it.
851    ///
852    /// Nothing stops the box from running its finalizer on drop, so the caller
853    /// must fill the memory before it is dropped or read.
854    pub fn new_uninitialized(
855        type_hash: TypeHash,
856        layout: Layout,
857        finalizer: impl Into<Finalizer>,
858    ) -> Self {
859        let layout = layout.pad_to_align();
860        let memory = unsafe { non_zero_alloc(layout) };
861        Self {
862            type_hash,
863            lifetime: Default::default(),
864            memory,
865            layout,
866            finalizer: finalizer.into(),
867            drop: true,
868        }
869    }
870
871    /// Builds a box by copying a byte image of a value into a new allocation.
872    ///
873    /// # Safety
874    ///
875    /// `bytes` must be a valid image of a value of the type named by
876    /// `type_hash`, matching `layout`, and it is moved, so the caller must not
877    /// drop the source afterwards.
878    pub unsafe fn from_bytes(
879        type_hash: TypeHash,
880        lifetime: Lifetime,
881        bytes: Vec<u8>,
882        layout: Layout,
883        finalizer: impl Into<Finalizer>,
884    ) -> Self {
885        let layout = layout.pad_to_align();
886        let memory = unsafe { non_zero_alloc(layout) };
887        unsafe { memory.copy_from(bytes.as_ptr(), bytes.len()) };
888        Self {
889            type_hash,
890            lifetime,
891            memory,
892            layout,
893            finalizer: finalizer.into(),
894            drop: true,
895        }
896    }
897
898    /// Splits into the parts the box was built from, and stops it from freeing
899    /// the allocation.
900    ///
901    /// The caller becomes responsible for running the finalizer and freeing the
902    /// memory.
903    #[allow(clippy::type_complexity)]
904    pub fn into_inner(mut self) -> (TypeHash, Lifetime, *mut u8, Layout, Finalizer) {
905        self.drop = false;
906        (
907            self.type_hash,
908            std::mem::take(&mut self.lifetime),
909            self.memory,
910            self.layout,
911            self.finalizer.clone(),
912        )
913    }
914
915    /// Moves the value into a typed box, giving `self` back on a type mismatch
916    /// or while it is accessed.
917    pub fn into_typed<T>(self) -> Result<Managed<T>, Self> {
918        Ok(Managed::new(self.consume()?))
919    }
920
921    /// Replaces the lifetime, killing every handle taken so far.
922    pub fn renew(mut self) -> Self {
923        self.lifetime = Lifetime::default();
924        self
925    }
926
927    /// Returns the type of the stored value.
928    pub fn type_hash(&self) -> &TypeHash {
929        &self.type_hash
930    }
931
932    /// Returns the borrow state of this value.
933    pub fn lifetime(&self) -> &Lifetime {
934        &self.lifetime
935    }
936
937    /// Returns the layout of the allocation.
938    pub fn layout(&self) -> &Layout {
939        &self.layout
940    }
941
942    /// Returns how the stored value is destroyed.
943    pub fn finalizer(&self) -> &Finalizer {
944        &self.finalizer
945    }
946
947    /// Returns the value as raw bytes.
948    ///
949    /// # Safety
950    ///
951    /// Bypasses the borrow state, so the caller must know that nothing is
952    /// writing the value.
953    pub unsafe fn memory(&self) -> &[u8] {
954        unsafe { std::slice::from_raw_parts(self.memory, self.layout.size()) }
955    }
956
957    /// Returns the value as mutable raw bytes.
958    ///
959    /// # Safety
960    ///
961    /// Bypasses the borrow state, and writing bytes that are not a valid value
962    /// of the stored type makes every later access undefined.
963    pub unsafe fn memory_mut(&mut self) -> &mut [u8] {
964        unsafe { std::slice::from_raw_parts_mut(self.memory, self.layout.size()) }
965    }
966
967    /// Returns `true` when the stored type is `T`.
968    pub fn is<T>(&self) -> bool {
969        self.type_hash == TypeHash::of::<T>()
970    }
971
972    /// Guards the value for reading, or returns [`None`] on a type mismatch or
973    /// while it is written.
974    pub fn read<T>(&'_ self) -> Option<ValueReadAccess<'_, T>> {
975        if self.type_hash == TypeHash::of::<T>() {
976            unsafe { self.lifetime.read_ptr(self.memory.cast::<T>()) }
977        } else {
978            None
979        }
980    }
981
982    /// Guards the value for writing, or returns [`None`] on a type mismatch or
983    /// while it is accessed.
984    pub fn write<T>(&'_ mut self) -> Option<ValueWriteAccess<'_, T>> {
985        if self.type_hash == TypeHash::of::<T>() {
986            unsafe { self.lifetime.write_ptr(self.memory.cast::<T>()) }
987        } else {
988            None
989        }
990    }
991
992    /// Takes the value out and frees the allocation.
993    ///
994    /// Gives the box back on a type mismatch or while any access guard is live.
995    pub fn consume<T>(mut self) -> Result<T, Self> {
996        if self.type_hash == TypeHash::of::<T>() && !self.lifetime.state().is_in_use() {
997            if self.memory.is_null() {
998                return Err(self);
999            }
1000            self.drop = false;
1001            let mut result = MaybeUninit::<T>::uninit();
1002            unsafe {
1003                result.as_mut_ptr().copy_from(self.memory.cast::<T>(), 1);
1004                non_zero_dealloc(self.memory, self.layout);
1005                self.memory = std::ptr::null_mut();
1006                Ok(result.assume_init())
1007            }
1008        } else {
1009            Err(self)
1010        }
1011    }
1012
1013    /// Moves the value into the place `target` points at and frees this
1014    /// allocation.
1015    ///
1016    /// Gives the box back when the types differ or both sides are the same
1017    /// allocation.
1018    pub fn move_into_ref(self, target: DynamicManagedRefMut) -> Result<(), Self> {
1019        if self.type_hash == target.type_hash && self.memory != target.data {
1020            if self.memory.is_null() {
1021                return Err(self);
1022            }
1023            let (_, _, memory, layout, _) = self.into_inner();
1024            unsafe {
1025                target.data.copy_from(memory, layout.size());
1026                non_zero_dealloc(memory, layout);
1027            }
1028            Ok(())
1029        } else {
1030            Err(self)
1031        }
1032    }
1033
1034    /// Moves the value into the place `target` points at and frees this
1035    /// allocation.
1036    ///
1037    /// Gives the box back when the types differ or both sides are the same
1038    /// allocation.
1039    pub fn move_into_lazy(self, target: DynamicManagedLazy) -> Result<(), Self> {
1040        if self.type_hash == target.type_hash && self.memory != target.data {
1041            if self.memory.is_null() {
1042                return Err(self);
1043            }
1044            let (_, _, memory, layout, _) = self.into_inner();
1045            unsafe {
1046                target.data.copy_from(memory, layout.size());
1047                non_zero_dealloc(memory, layout);
1048            }
1049            Ok(())
1050        } else {
1051            Err(self)
1052        }
1053    }
1054
1055    /// Takes a shared handle, or returns [`None`] when an exclusive one is out.
1056    pub fn borrow(&self) -> Option<DynamicManagedRef> {
1057        unsafe { DynamicManagedRef::new_raw(self.type_hash, self.lifetime.borrow()?, self.memory) }
1058    }
1059
1060    /// Takes an exclusive handle, or returns [`None`] when any handle is out.
1061    pub fn borrow_mut(&mut self) -> Option<DynamicManagedRefMut> {
1062        unsafe {
1063            DynamicManagedRefMut::new_raw(self.type_hash, self.lifetime.borrow_mut()?, self.memory)
1064        }
1065    }
1066
1067    /// Takes an unclaimed handle.
1068    pub fn lazy(&self) -> DynamicManagedLazy {
1069        unsafe {
1070            DynamicManagedLazy::new_raw(self.type_hash, self.lifetime.lazy(), self.memory).unwrap()
1071        }
1072    }
1073
1074    /// Replaces the value with one built from it, in a new allocation.
1075    ///
1076    /// # Safety
1077    ///
1078    /// Handles taken so far are not checked before the value is moved out, and
1079    /// they go dead. Returns [`None`] when the stored type is not `T`.
1080    pub unsafe fn map<T, U: Finalize>(self, f: impl FnOnce(T) -> U) -> Option<Self> {
1081        let data = self.consume::<T>().ok()?;
1082        let data = f(data);
1083        Self::new(data).ok()
1084    }
1085
1086    /// [`DynamicManaged::map`] that can decline, dropping the value when it
1087    /// does.
1088    ///
1089    /// # Safety
1090    ///
1091    /// Same as [`DynamicManaged::map`].
1092    pub unsafe fn try_map<T, U: Finalize>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Self> {
1093        let data = self.consume::<T>().ok()?;
1094        let data = f(data)?;
1095        Self::new(data).ok()
1096    }
1097
1098    /// Returns a typed pointer while nothing is accessing the value.
1099    ///
1100    /// # Safety
1101    ///
1102    /// The caller takes over checking for conflicting access.
1103    pub unsafe fn as_ptr<T>(&self) -> Option<*const T> {
1104        if self.type_hash == TypeHash::of::<T>() && !self.lifetime.state().is_in_use() {
1105            Some(self.memory.cast::<T>())
1106        } else {
1107            None
1108        }
1109    }
1110
1111    /// Returns a typed mutable pointer while nothing is accessing the value.
1112    ///
1113    /// # Safety
1114    ///
1115    /// The caller takes over checking for conflicting access.
1116    pub unsafe fn as_mut_ptr<T>(&mut self) -> Option<*mut T> {
1117        if self.type_hash == TypeHash::of::<T>() && !self.lifetime.state().is_in_use() {
1118            Some(self.memory.cast::<T>())
1119        } else {
1120            None
1121        }
1122    }
1123
1124    /// Returns the allocation pointer, checking nothing at all.
1125    ///
1126    /// # Safety
1127    ///
1128    /// Neither the type nor the borrow state is checked.
1129    pub unsafe fn as_ptr_raw(&self) -> *const u8 {
1130        self.memory
1131    }
1132
1133    /// Returns the mutable allocation pointer, checking nothing at all.
1134    ///
1135    /// # Safety
1136    ///
1137    /// Neither the type nor the borrow state is checked.
1138    pub unsafe fn as_mut_ptr_raw(&mut self) -> *mut u8 {
1139        self.memory
1140    }
1141}
1142
1143impl TryFrom<DynamicManagedValue> for DynamicManaged {
1144    type Error = ();
1145
1146    fn try_from(value: DynamicManagedValue) -> Result<Self, Self::Error> {
1147        match value {
1148            DynamicManagedValue::Owned(value) => Ok(value),
1149            _ => Err(()),
1150        }
1151    }
1152}
1153
1154/// Shared handle to a value whose type is only known at runtime.
1155///
1156/// The [`ManagedRef`] counterpart for script values.
1157pub struct DynamicManagedRef {
1158    type_hash: TypeHash,
1159    lifetime: LifetimeRef,
1160    data: *const u8,
1161}
1162
1163unsafe impl Send for DynamicManagedRef {}
1164unsafe impl Sync for DynamicManagedRef {}
1165
1166impl DynamicManagedRef {
1167    /// Pairs a reference with a shared borrow taken from its lifetime.
1168    pub fn new<T: ?Sized>(data: &T, lifetime: LifetimeRef) -> Self {
1169        Self {
1170            type_hash: TypeHash::of::<T>(),
1171            lifetime,
1172            data: data as *const T as *const u8,
1173        }
1174    }
1175
1176    /// [`DynamicManagedRef::new`] for a type only known at runtime. A null
1177    /// pointer yields [`None`].
1178    ///
1179    /// # Safety
1180    ///
1181    /// `data` must point at a value of the type named by `type_hash`, and must
1182    /// stay valid for as long as `lifetime` says it does.
1183    pub unsafe fn new_raw(
1184        type_hash: TypeHash,
1185        lifetime: LifetimeRef,
1186        data: *const u8,
1187    ) -> Option<Self> {
1188        if data.is_null() {
1189            None
1190        } else {
1191            Some(Self {
1192                type_hash,
1193                lifetime,
1194                data,
1195            })
1196        }
1197    }
1198
1199    /// Builds a handle to a plain reference along with the lifetime that backs
1200    /// it.
1201    pub fn make<T: ?Sized>(data: &T) -> (Self, Lifetime) {
1202        let result = Lifetime::default();
1203        (Self::new(data, result.borrow().unwrap()), result)
1204    }
1205
1206    /// Splits into type, borrow token and pointer.
1207    pub fn into_inner(self) -> (TypeHash, LifetimeRef, *const u8) {
1208        (self.type_hash, self.lifetime, self.data)
1209    }
1210
1211    /// Recovers the typed handle, or gives `self` back on a type mismatch.
1212    pub fn into_typed<T>(self) -> Result<ManagedRef<T>, Self> {
1213        if self.type_hash == TypeHash::of::<T>() {
1214            unsafe { Ok(ManagedRef::new_raw(self.data.cast::<T>(), self.lifetime).unwrap()) }
1215        } else {
1216            Err(self)
1217        }
1218    }
1219
1220    /// Returns the type of the value.
1221    pub fn type_hash(&self) -> &TypeHash {
1222        &self.type_hash
1223    }
1224
1225    /// Returns the borrow token.
1226    pub fn lifetime(&self) -> &LifetimeRef {
1227        &self.lifetime
1228    }
1229
1230    /// Takes another shared handle to the same value.
1231    pub fn borrow(&self) -> Option<DynamicManagedRef> {
1232        Some(DynamicManagedRef {
1233            type_hash: self.type_hash,
1234            lifetime: self.lifetime.borrow()?,
1235            data: self.data,
1236        })
1237    }
1238
1239    /// Turns this shared handle into an unclaimed one that can also write.
1240    ///
1241    /// # Safety
1242    ///
1243    /// The value was only borrowed immutably, so writing through the result is
1244    /// only sound when nothing else holds a shared reference to it.
1245    pub unsafe fn lazy_immutable(&self) -> DynamicManagedLazy {
1246        DynamicManagedLazy {
1247            type_hash: self.type_hash,
1248            lifetime: self.lifetime.lazy(),
1249            data: self.data as *mut u8,
1250        }
1251    }
1252
1253    /// Returns `true` when the value is a `T`.
1254    pub fn is<T>(&self) -> bool {
1255        self.type_hash == TypeHash::of::<T>()
1256    }
1257
1258    /// Guards the value for reading, or returns [`None`] on a type mismatch or
1259    /// while it is written.
1260    pub fn read<T>(&'_ self) -> Option<ValueReadAccess<'_, T>> {
1261        if self.type_hash == TypeHash::of::<T>() {
1262            unsafe { self.lifetime.read_ptr(self.data.cast::<T>()) }
1263        } else {
1264            None
1265        }
1266    }
1267
1268    /// Narrows this handle down to a part of the value, retyping it to `U`.
1269    ///
1270    /// # Safety
1271    ///
1272    /// `f` must return a reference into the same value, and the owner must
1273    /// still be alive. Returns [`None`] when the value is not a `T`.
1274    pub unsafe fn map<T, U>(self, f: impl FnOnce(&T) -> &U) -> Option<Self> {
1275        if self.type_hash == TypeHash::of::<T>() {
1276            unsafe {
1277                let data = f(&*self.data.cast::<T>());
1278                Some(Self {
1279                    type_hash: TypeHash::of::<U>(),
1280                    lifetime: self.lifetime,
1281                    data: data as *const U as *const u8,
1282                })
1283            }
1284        } else {
1285            None
1286        }
1287    }
1288
1289    /// [`DynamicManagedRef::map`] that can decline.
1290    ///
1291    /// # Safety
1292    ///
1293    /// Same as [`DynamicManagedRef::map`].
1294    pub unsafe fn try_map<T, U>(self, f: impl FnOnce(&T) -> Option<&U>) -> Option<Self> {
1295        if self.type_hash == TypeHash::of::<T>() {
1296            unsafe {
1297                let data = f(&*self.data.cast::<T>())?;
1298                Some(Self {
1299                    type_hash: TypeHash::of::<U>(),
1300                    lifetime: self.lifetime,
1301                    data: data as *const U as *const u8,
1302                })
1303            }
1304        } else {
1305            None
1306        }
1307    }
1308
1309    /// Returns a typed pointer while the owner is alive.
1310    ///
1311    /// # Safety
1312    ///
1313    /// The caller takes over checking for conflicting access.
1314    pub unsafe fn as_ptr<T>(&self) -> Option<*const T> {
1315        if self.type_hash == TypeHash::of::<T>() && self.lifetime.exists() {
1316            Some(self.data.cast::<T>())
1317        } else {
1318            None
1319        }
1320    }
1321
1322    /// Returns the untyped pointer while the owner is alive.
1323    ///
1324    /// # Safety
1325    ///
1326    /// Neither the type nor conflicting access is checked.
1327    pub unsafe fn as_ptr_raw(&self) -> Option<*const u8> {
1328        if self.lifetime.exists() {
1329            Some(self.data)
1330        } else {
1331            None
1332        }
1333    }
1334}
1335
1336impl TryFrom<DynamicManagedValue> for DynamicManagedRef {
1337    type Error = ();
1338
1339    fn try_from(value: DynamicManagedValue) -> Result<Self, Self::Error> {
1340        match value {
1341            DynamicManagedValue::Ref(value) => Ok(value),
1342            _ => Err(()),
1343        }
1344    }
1345}
1346
1347/// Exclusive handle to a value whose type is only known at runtime.
1348///
1349/// The [`ManagedRefMut`] counterpart for script values.
1350pub struct DynamicManagedRefMut {
1351    type_hash: TypeHash,
1352    lifetime: LifetimeRefMut,
1353    data: *mut u8,
1354}
1355
1356unsafe impl Send for DynamicManagedRefMut {}
1357unsafe impl Sync for DynamicManagedRefMut {}
1358
1359impl DynamicManagedRefMut {
1360    /// Pairs a mutable reference with an exclusive borrow of its lifetime.
1361    pub fn new<T: ?Sized>(data: &mut T, lifetime: LifetimeRefMut) -> Self {
1362        Self {
1363            type_hash: TypeHash::of::<T>(),
1364            lifetime,
1365            data: data as *mut T as *mut u8,
1366        }
1367    }
1368
1369    /// [`DynamicManagedRefMut::new`] for a type only known at runtime. A null
1370    /// pointer yields [`None`].
1371    ///
1372    /// # Safety
1373    ///
1374    /// `data` must point at a value of the type named by `type_hash`, and must
1375    /// stay valid and unaliased for as long as `lifetime` says it does.
1376    pub unsafe fn new_raw(
1377        type_hash: TypeHash,
1378        lifetime: LifetimeRefMut,
1379        data: *mut u8,
1380    ) -> Option<Self> {
1381        if data.is_null() {
1382            None
1383        } else {
1384            Some(Self {
1385                type_hash,
1386                lifetime,
1387                data,
1388            })
1389        }
1390    }
1391
1392    /// Builds a handle to a plain mutable reference along with the lifetime that
1393    /// backs it.
1394    pub fn make<T: ?Sized>(data: &mut T) -> (Self, Lifetime) {
1395        let result = Lifetime::default();
1396        (Self::new(data, result.borrow_mut().unwrap()), result)
1397    }
1398
1399    /// Splits into type, borrow token and pointer.
1400    pub fn into_inner(self) -> (TypeHash, LifetimeRefMut, *mut u8) {
1401        (self.type_hash, self.lifetime, self.data)
1402    }
1403
1404    /// Recovers the typed handle, or gives `self` back on a type mismatch.
1405    pub fn into_typed<T>(self) -> Result<ManagedRefMut<T>, Self> {
1406        if self.type_hash == TypeHash::of::<T>() {
1407            unsafe { Ok(ManagedRefMut::new_raw(self.data.cast::<T>(), self.lifetime).unwrap()) }
1408        } else {
1409            Err(self)
1410        }
1411    }
1412
1413    /// Returns the type of the value.
1414    pub fn type_hash(&self) -> &TypeHash {
1415        &self.type_hash
1416    }
1417
1418    /// Returns the borrow token.
1419    pub fn lifetime(&self) -> &LifetimeRefMut {
1420        &self.lifetime
1421    }
1422
1423    /// Takes a shared handle nested under this one.
1424    pub fn borrow(&self) -> Option<DynamicManagedRef> {
1425        Some(DynamicManagedRef {
1426            type_hash: self.type_hash,
1427            lifetime: self.lifetime.borrow()?,
1428            data: self.data,
1429        })
1430    }
1431
1432    /// Takes an exclusive handle nested under this one.
1433    pub fn borrow_mut(&mut self) -> Option<DynamicManagedRefMut> {
1434        Some(DynamicManagedRefMut {
1435            type_hash: self.type_hash,
1436            lifetime: self.lifetime.borrow_mut()?,
1437            data: self.data,
1438        })
1439    }
1440
1441    /// Takes an unclaimed handle.
1442    pub fn lazy(&self) -> DynamicManagedLazy {
1443        DynamicManagedLazy {
1444            type_hash: self.type_hash,
1445            lifetime: self.lifetime.lazy(),
1446            data: self.data,
1447        }
1448    }
1449
1450    /// Returns `true` when the value is a `T`.
1451    pub fn is<T>(&self) -> bool {
1452        self.type_hash == TypeHash::of::<T>()
1453    }
1454
1455    /// Guards the value for reading, or returns [`None`] on a type mismatch or
1456    /// while it is written.
1457    pub fn read<T>(&'_ self) -> Option<ValueReadAccess<'_, T>> {
1458        if self.type_hash == TypeHash::of::<T>() {
1459            unsafe { self.lifetime.read_ptr(self.data.cast::<T>()) }
1460        } else {
1461            None
1462        }
1463    }
1464
1465    /// Guards the value for writing, or returns [`None`] on a type mismatch or
1466    /// while it is accessed.
1467    pub fn write<T>(&'_ mut self) -> Option<ValueWriteAccess<'_, T>> {
1468        if self.type_hash == TypeHash::of::<T>() {
1469            unsafe { self.lifetime.write_ptr(self.data.cast::<T>()) }
1470        } else {
1471            None
1472        }
1473    }
1474
1475    /// Narrows this handle down to a part of the value, retyping it to `U`.
1476    ///
1477    /// # Safety
1478    ///
1479    /// `f` must return a reference into the same value, and the owner must
1480    /// still be alive. Returns [`None`] when the value is not a `T`.
1481    pub unsafe fn map<T, U>(self, f: impl FnOnce(&mut T) -> &mut U) -> Option<Self> {
1482        if self.type_hash == TypeHash::of::<T>() {
1483            unsafe {
1484                let data = f(&mut *self.data.cast::<T>());
1485                Some(Self {
1486                    type_hash: TypeHash::of::<U>(),
1487                    lifetime: self.lifetime,
1488                    data: data as *mut U as *mut u8,
1489                })
1490            }
1491        } else {
1492            None
1493        }
1494    }
1495
1496    /// [`DynamicManagedRefMut::map`] that can decline.
1497    ///
1498    /// # Safety
1499    ///
1500    /// Same as [`DynamicManagedRefMut::map`].
1501    pub unsafe fn try_map<T, U>(self, f: impl FnOnce(&mut T) -> Option<&mut U>) -> Option<Self> {
1502        if self.type_hash == TypeHash::of::<T>() {
1503            unsafe {
1504                let data = f(&mut *self.data.cast::<T>())?;
1505                Some(Self {
1506                    type_hash: TypeHash::of::<U>(),
1507                    lifetime: self.lifetime,
1508                    data: data as *mut U as *mut u8,
1509                })
1510            }
1511        } else {
1512            None
1513        }
1514    }
1515
1516    /// Returns a typed pointer while the owner is alive.
1517    ///
1518    /// # Safety
1519    ///
1520    /// The caller takes over checking for conflicting access.
1521    pub unsafe fn as_ptr<T>(&self) -> Option<*const T> {
1522        if self.type_hash == TypeHash::of::<T>() && self.lifetime.exists() {
1523            Some(self.data.cast::<T>())
1524        } else {
1525            None
1526        }
1527    }
1528
1529    /// Returns a typed mutable pointer while the owner is alive.
1530    ///
1531    /// # Safety
1532    ///
1533    /// The caller takes over checking for conflicting access.
1534    pub unsafe fn as_mut_ptr<T>(&mut self) -> Option<*mut T> {
1535        if self.type_hash == TypeHash::of::<T>() && self.lifetime.exists() {
1536            Some(self.data.cast::<T>())
1537        } else {
1538            None
1539        }
1540    }
1541
1542    /// Returns the untyped pointer while the owner is alive.
1543    ///
1544    /// # Safety
1545    ///
1546    /// Neither the type nor conflicting access is checked.
1547    pub unsafe fn as_ptr_raw(&self) -> Option<*const u8> {
1548        if self.lifetime.exists() {
1549            Some(self.data)
1550        } else {
1551            None
1552        }
1553    }
1554
1555    /// Returns the untyped mutable pointer while the owner is alive.
1556    ///
1557    /// # Safety
1558    ///
1559    /// Neither the type nor conflicting access is checked.
1560    pub unsafe fn as_mut_ptr_raw(&mut self) -> Option<*mut u8> {
1561        if self.lifetime.exists() {
1562            Some(self.data)
1563        } else {
1564            None
1565        }
1566    }
1567}
1568
1569impl TryFrom<DynamicManagedValue> for DynamicManagedRefMut {
1570    type Error = ();
1571
1572    fn try_from(value: DynamicManagedValue) -> Result<Self, Self::Error> {
1573        match value {
1574            DynamicManagedValue::RefMut(value) => Ok(value),
1575            _ => Err(()),
1576        }
1577    }
1578}
1579
1580/// Unclaimed handle to a value whose type is only known at runtime.
1581///
1582/// The [`ManagedLazy`] counterpart for script values, and the handle script
1583/// variables usually hold.
1584pub struct DynamicManagedLazy {
1585    type_hash: TypeHash,
1586    lifetime: LifetimeLazy,
1587    data: *mut u8,
1588}
1589
1590unsafe impl Send for DynamicManagedLazy {}
1591unsafe impl Sync for DynamicManagedLazy {}
1592
1593impl Clone for DynamicManagedLazy {
1594    fn clone(&self) -> Self {
1595        Self {
1596            type_hash: self.type_hash,
1597            lifetime: self.lifetime.clone(),
1598            data: self.data,
1599        }
1600    }
1601}
1602
1603impl DynamicManagedLazy {
1604    /// Pairs a mutable reference with an unclaimed handle to its lifetime.
1605    pub fn new<T: ?Sized>(data: &mut T, lifetime: LifetimeLazy) -> Self {
1606        Self {
1607            type_hash: TypeHash::of::<T>(),
1608            lifetime,
1609            data: data as *mut T as *mut u8,
1610        }
1611    }
1612
1613    /// [`DynamicManagedLazy::new`] for a type only known at runtime. A null
1614    /// pointer yields [`None`].
1615    ///
1616    /// # Safety
1617    ///
1618    /// `data` must point at a value of the type named by `type_hash`, and must
1619    /// stay valid for as long as `lifetime` says it does.
1620    pub unsafe fn new_raw(
1621        type_hash: TypeHash,
1622        lifetime: LifetimeLazy,
1623        data: *mut u8,
1624    ) -> Option<Self> {
1625        if data.is_null() {
1626            None
1627        } else {
1628            Some(Self {
1629                type_hash,
1630                lifetime,
1631                data,
1632            })
1633        }
1634    }
1635
1636    /// Builds a handle to a plain mutable reference along with the lifetime that
1637    /// backs it.
1638    pub fn make<T: ?Sized>(data: &mut T) -> (Self, Lifetime) {
1639        let result = Lifetime::default();
1640        (Self::new(data, result.lazy()), result)
1641    }
1642
1643    /// Splits into type, lifetime handle and pointer.
1644    pub fn into_inner(self) -> (TypeHash, LifetimeLazy, *mut u8) {
1645        (self.type_hash, self.lifetime, self.data)
1646    }
1647
1648    /// Recovers the typed handle, or gives `self` back on a type mismatch.
1649    pub fn into_typed<T>(self) -> Result<ManagedLazy<T>, Self> {
1650        if self.type_hash == TypeHash::of::<T>() {
1651            unsafe { Ok(ManagedLazy::new_raw(self.data.cast::<T>(), self.lifetime).unwrap()) }
1652        } else {
1653            Err(self)
1654        }
1655    }
1656
1657    /// Returns the type of the value.
1658    pub fn type_hash(&self) -> &TypeHash {
1659        &self.type_hash
1660    }
1661
1662    /// Returns the lifetime handle.
1663    pub fn lifetime(&self) -> &LifetimeLazy {
1664        &self.lifetime
1665    }
1666
1667    /// Returns `true` when the value is a `T`.
1668    pub fn is<T>(&self) -> bool {
1669        self.type_hash == TypeHash::of::<T>()
1670    }
1671
1672    /// Guards the value for reading, or returns [`None`] on a type mismatch or
1673    /// while it is written.
1674    pub fn read<T>(&'_ self) -> Option<ValueReadAccess<'_, T>> {
1675        if self.type_hash == TypeHash::of::<T>() {
1676            unsafe { self.lifetime.read_ptr(self.data.cast::<T>()) }
1677        } else {
1678            None
1679        }
1680    }
1681
1682    /// Guards the value for writing, or returns [`None`] on a type mismatch or
1683    /// while it is accessed.
1684    ///
1685    /// Takes `&self`, since a lazy handle claims nothing of its own.
1686    pub fn write<T>(&'_ self) -> Option<ValueWriteAccess<'_, T>> {
1687        if self.type_hash == TypeHash::of::<T>() {
1688            unsafe { self.lifetime.write_ptr(self.data.cast::<T>()) }
1689        } else {
1690            None
1691        }
1692    }
1693
1694    /// Upgrades to a shared handle that holds its claim.
1695    pub fn borrow(&self) -> Option<DynamicManagedRef> {
1696        Some(DynamicManagedRef {
1697            type_hash: self.type_hash,
1698            lifetime: self.lifetime.borrow()?,
1699            data: self.data,
1700        })
1701    }
1702
1703    /// Upgrades to an exclusive handle that holds its claim.
1704    pub fn borrow_mut(&mut self) -> Option<DynamicManagedRefMut> {
1705        Some(DynamicManagedRefMut {
1706            type_hash: self.type_hash,
1707            lifetime: self.lifetime.borrow_mut()?,
1708            data: self.data,
1709        })
1710    }
1711
1712    /// Narrows this handle down to a part of the value, retyping it to `U`.
1713    ///
1714    /// # Safety
1715    ///
1716    /// `f` must return a reference into the same value, and the owner must
1717    /// still be alive. Returns [`None`] when the value is not a `T`.
1718    pub unsafe fn map<T, U>(self, f: impl FnOnce(&mut T) -> &mut U) -> Option<Self> {
1719        if self.type_hash == TypeHash::of::<T>() {
1720            unsafe {
1721                let data = f(&mut *self.data.cast::<T>());
1722                Some(Self {
1723                    type_hash: TypeHash::of::<U>(),
1724                    lifetime: self.lifetime,
1725                    data: data as *mut U as *mut u8,
1726                })
1727            }
1728        } else {
1729            None
1730        }
1731    }
1732
1733    /// [`DynamicManagedLazy::map`] that can decline.
1734    ///
1735    /// # Safety
1736    ///
1737    /// Same as [`DynamicManagedLazy::map`].
1738    pub unsafe fn try_map<T, U>(self, f: impl FnOnce(&mut T) -> Option<&mut U>) -> Option<Self> {
1739        if self.type_hash == TypeHash::of::<T>() {
1740            unsafe {
1741                let data = f(&mut *self.data.cast::<T>())?;
1742                Some(Self {
1743                    type_hash: TypeHash::of::<U>(),
1744                    lifetime: self.lifetime,
1745                    data: data as *mut U as *mut u8,
1746                })
1747            }
1748        } else {
1749            None
1750        }
1751    }
1752
1753    /// Returns a typed pointer while the owner is alive.
1754    ///
1755    /// # Safety
1756    ///
1757    /// The caller takes over checking for conflicting access.
1758    pub unsafe fn as_ptr<T>(&self) -> Option<*const T> {
1759        if self.type_hash == TypeHash::of::<T>() && self.lifetime.exists() {
1760            Some(self.data.cast::<T>())
1761        } else {
1762            None
1763        }
1764    }
1765
1766    /// Returns a typed mutable pointer while the owner is alive.
1767    ///
1768    /// # Safety
1769    ///
1770    /// The caller takes over checking for conflicting access.
1771    pub unsafe fn as_mut_ptr<T>(&self) -> Option<*mut T> {
1772        if self.type_hash == TypeHash::of::<T>() && self.lifetime.exists() {
1773            Some(self.data.cast::<T>())
1774        } else {
1775            None
1776        }
1777    }
1778
1779    /// Returns the untyped pointer while the owner is alive.
1780    ///
1781    /// # Safety
1782    ///
1783    /// Neither the type nor conflicting access is checked.
1784    pub unsafe fn as_ptr_raw(&self) -> Option<*const u8> {
1785        if self.lifetime.exists() {
1786            Some(self.data)
1787        } else {
1788            None
1789        }
1790    }
1791
1792    /// Returns the untyped mutable pointer while the owner is alive.
1793    ///
1794    /// # Safety
1795    ///
1796    /// Neither the type nor conflicting access is checked.
1797    pub unsafe fn as_mut_ptr_raw(&mut self) -> Option<*mut u8> {
1798        if self.lifetime.exists() {
1799            Some(self.data)
1800        } else {
1801            None
1802        }
1803    }
1804}
1805
1806impl TryFrom<DynamicManagedValue> for DynamicManagedLazy {
1807    type Error = ();
1808
1809    fn try_from(value: DynamicManagedValue) -> Result<Self, Self::Error> {
1810        match value {
1811            DynamicManagedValue::Lazy(value) => Ok(value),
1812            _ => Err(()),
1813        }
1814    }
1815}
1816
1817#[cfg(test)]
1818mod tests {
1819    use super::*;
1820    use std::any::Any;
1821
1822    fn is_async<T: Send + Sync + ?Sized>() {}
1823
1824    #[test]
1825    fn test_managed() {
1826        is_async::<Managed<()>>();
1827        is_async::<ManagedRef<()>>();
1828        is_async::<ManagedRefMut<()>>();
1829        is_async::<ManagedLazy<()>>();
1830        is_async::<ManagedValue<()>>();
1831
1832        let mut value = Managed::new(42);
1833        let mut value_ref = value.borrow_mut().unwrap();
1834        assert!(value_ref.write().is_some());
1835        let mut value_ref2 = value_ref.borrow_mut().unwrap();
1836        assert!(value_ref.write().is_some());
1837        assert!(value_ref2.write().is_some());
1838        drop(value_ref);
1839        let value_ref = value.borrow().unwrap();
1840        assert!(value.borrow().is_some());
1841        assert!(value.borrow_mut().is_none());
1842        drop(value_ref);
1843        assert!(value.borrow().is_some());
1844        assert!(value.borrow_mut().is_some());
1845        *value.write().unwrap() = 40;
1846        assert_eq!(*value.read().unwrap(), 40);
1847        *value.borrow_mut().unwrap().write().unwrap() = 2;
1848        assert_eq!(*value.read().unwrap(), 2);
1849        let value_ref = value.borrow().unwrap();
1850        let value_ref2 = value_ref.borrow().unwrap();
1851        drop(value_ref);
1852        assert!(value_ref2.read().is_some());
1853        let value_ref = value.borrow().unwrap();
1854        let value_lazy = value.lazy();
1855        assert_eq!(*value_lazy.read().unwrap(), 2);
1856        *value_lazy.write().unwrap() = 42;
1857        assert_eq!(*value_lazy.read().unwrap(), 42);
1858        drop(value);
1859        assert!(value_ref.read().is_none());
1860        assert!(value_ref2.read().is_none());
1861        assert!(value_lazy.read().is_none());
1862    }
1863
1864    #[test]
1865    fn test_dynamic_managed() {
1866        is_async::<DynamicManaged>();
1867        is_async::<DynamicManagedRef>();
1868        is_async::<DynamicManagedRefMut>();
1869        is_async::<DynamicManagedLazy>();
1870        is_async::<DynamicManagedValue>();
1871
1872        let mut value = DynamicManaged::new(42).unwrap();
1873        let mut value_ref = value.borrow_mut().unwrap();
1874        assert!(value_ref.write::<i32>().is_some());
1875        let mut value_ref2 = value_ref.borrow_mut().unwrap();
1876        assert!(value_ref.write::<i32>().is_some());
1877        assert!(value_ref2.write::<i32>().is_some());
1878        drop(value_ref);
1879        let value_ref = value.borrow().unwrap();
1880        assert!(value.borrow().is_some());
1881        assert!(value.borrow_mut().is_none());
1882        drop(value_ref);
1883        assert!(value.borrow().is_some());
1884        assert!(value.borrow_mut().is_some());
1885        *value.write::<i32>().unwrap() = 40;
1886        assert_eq!(*value.read::<i32>().unwrap(), 40);
1887        *value.borrow_mut().unwrap().write::<i32>().unwrap() = 2;
1888        assert_eq!(*value.read::<i32>().unwrap(), 2);
1889        let value_ref = value.borrow().unwrap();
1890        let value_ref2 = value_ref.borrow().unwrap();
1891        drop(value_ref);
1892        assert!(value_ref2.read::<i32>().is_some());
1893        let value_ref = value.borrow().unwrap();
1894        let value_lazy = value.lazy();
1895        assert_eq!(*value_lazy.read::<i32>().unwrap(), 2);
1896        *value_lazy.write::<i32>().unwrap() = 42;
1897        assert_eq!(*value_lazy.read::<i32>().unwrap(), 42);
1898        drop(value);
1899        assert!(value_ref.read::<i32>().is_none());
1900        assert!(value_ref2.read::<i32>().is_none());
1901        assert!(value_lazy.read::<i32>().is_none());
1902        let value = DynamicManaged::new("hello".to_owned()).unwrap();
1903        let value = value.consume::<String>().ok().unwrap();
1904        assert_eq!(value.as_str(), "hello");
1905    }
1906
1907    #[test]
1908    fn test_conversion() {
1909        let value = Managed::new(42);
1910        assert_eq!(*value.read().unwrap(), 42);
1911        let value = value.into_dynamic().ok().unwrap();
1912        assert_eq!(*value.read::<i32>().unwrap(), 42);
1913        let mut value = value.into_typed::<i32>().ok().unwrap();
1914        assert_eq!(*value.read().unwrap(), 42);
1915
1916        let value_ref = value.borrow().unwrap();
1917        assert_eq!(*value.read().unwrap(), 42);
1918        let value_ref = value_ref.into_dynamic();
1919        assert_eq!(*value_ref.read::<i32>().unwrap(), 42);
1920        let value_ref = value_ref.into_typed::<i32>().ok().unwrap();
1921        assert_eq!(*value_ref.read().unwrap(), 42);
1922        drop(value_ref);
1923
1924        let value_ref_mut = value.borrow_mut().unwrap();
1925        assert_eq!(*value.read().unwrap(), 42);
1926        let value_ref_mut = value_ref_mut.into_dynamic();
1927        assert_eq!(*value_ref_mut.read::<i32>().unwrap(), 42);
1928        let value_ref_mut = value_ref_mut.into_typed::<i32>().ok().unwrap();
1929        assert_eq!(*value_ref_mut.read().unwrap(), 42);
1930
1931        let value_lazy = value.lazy();
1932        assert_eq!(*value.read().unwrap(), 42);
1933        let value_lazy = value_lazy.into_dynamic();
1934        assert_eq!(*value_lazy.read::<i32>().unwrap(), 42);
1935        let value_lazy = value_lazy.into_typed::<i32>().ok().unwrap();
1936        assert_eq!(*value_lazy.read().unwrap(), 42);
1937    }
1938
1939    #[test]
1940    fn test_unsized() {
1941        let lifetime = Lifetime::default();
1942        let mut data = 42usize;
1943        {
1944            let foo = ManagedRef::<dyn Any>::new(&data, lifetime.borrow().unwrap());
1945            assert_eq!(
1946                *foo.read().unwrap().downcast_ref::<usize>().unwrap(),
1947                42usize
1948            );
1949        }
1950        {
1951            let mut foo = ManagedRefMut::<dyn Any>::new(&mut data, lifetime.borrow_mut().unwrap());
1952            *foo.write().unwrap().downcast_mut::<usize>().unwrap() = 100;
1953        }
1954        {
1955            let foo = ManagedLazy::<dyn Any>::new(&mut data, lifetime.lazy());
1956            assert_eq!(
1957                *foo.read().unwrap().downcast_ref::<usize>().unwrap(),
1958                100usize
1959            );
1960        }
1961
1962        let lifetime = Lifetime::default();
1963        let mut data = [0, 1, 2, 3];
1964        {
1965            let foo = ManagedRef::<[i32]>::new(&data, lifetime.borrow().unwrap());
1966            assert_eq!(*foo.read().unwrap(), [0, 1, 2, 3]);
1967        }
1968        {
1969            let mut foo = ManagedRefMut::<[i32]>::new(&mut data, lifetime.borrow_mut().unwrap());
1970            foo.write().unwrap().sort_by(|a, b| a.cmp(b).reverse());
1971        }
1972        {
1973            let foo = ManagedLazy::<[i32]>::new(&mut data, lifetime.lazy());
1974            assert_eq!(*foo.read().unwrap(), [3, 2, 1, 0]);
1975        }
1976    }
1977
1978    #[test]
1979    fn test_moves() {
1980        let mut value = Managed::new(42);
1981        assert_eq!(*value.read().unwrap(), 42);
1982        {
1983            let value_ref = value.borrow_mut().unwrap();
1984            Managed::new(1).move_into_ref(value_ref).ok().unwrap();
1985            assert_eq!(*value.read().unwrap(), 1);
1986        }
1987        {
1988            let value_lazy = value.lazy();
1989            Managed::new(2).move_into_lazy(value_lazy).ok().unwrap();
1990            assert_eq!(*value.read().unwrap(), 2);
1991        }
1992
1993        let mut value = DynamicManaged::new(42).unwrap();
1994        assert_eq!(*value.read::<i32>().unwrap(), 42);
1995        {
1996            let value_ref = value.borrow_mut().unwrap();
1997            DynamicManaged::new(1)
1998                .unwrap()
1999                .move_into_ref(value_ref)
2000                .ok()
2001                .unwrap();
2002            assert_eq!(*value.read::<i32>().unwrap(), 1);
2003        }
2004        {
2005            let value_lazy = value.lazy();
2006            DynamicManaged::new(2)
2007                .unwrap()
2008                .move_into_lazy(value_lazy)
2009                .ok()
2010                .unwrap();
2011            assert_eq!(*value.read::<i32>().unwrap(), 2);
2012        }
2013    }
2014
2015    #[test]
2016    fn test_move_invalidation() {
2017        let value = Managed::new(42);
2018        let value_ref = value.borrow().unwrap();
2019        assert_eq!(value.lifetime().tag(), value_ref.lifetime().tag());
2020        assert!(value_ref.lifetime().exists());
2021        let value = Box::new(value);
2022        assert_ne!(value.lifetime().tag(), value_ref.lifetime().tag());
2023        assert!(!value_ref.lifetime().exists());
2024        let value = *value;
2025        assert_ne!(value.lifetime().tag(), value_ref.lifetime().tag());
2026        assert!(!value_ref.lifetime().exists());
2027    }
2028}