rune/core/gc/
root.rs

1use super::{
2    super::{cons::Cons, object::Object},
3    GcMoveable, GcState, TracePtr,
4};
5use super::{Block, Context, RootSet, ThreadSafeRootSet, Trace};
6use crate::core::object::{Gc, GcPtr, IntoObject, ObjectType, OptionalFlag, Untag, WithLifetime};
7use rune_core::hashmap::IndexMap;
8use std::hash::{Hash, Hasher};
9use std::slice::SliceIndex;
10use std::{
11    cell::UnsafeCell,
12    fmt,
13    ops::{Deref, DerefMut, Index, IndexMut, RangeBounds},
14};
15use std::{
16    fmt::{Debug, Display},
17    marker::PhantomPinned,
18};
19
20/// Helper trait to break the dependency between an object and the lifetimes of
21/// it's [traceable](Trace) children. If This trait is implemented, then the
22/// object can be traced by the garbage collector. Once it becomes rooted, it as
23/// well as all of it's tracable children will be live until it is unrooted.
24/// This essentially makes any lifetimes of a tracable objects meaningless. They
25/// can be anything, including 'static. When an object is removed from a root it
26/// will be given the proper lifetime again. Care must be taken to ensure that
27/// any lifetimes that are changed only belong to traceable objects. Object can
28/// contain lifetimes parameters for both traceable and untracable children, and
29/// only the traceable children's lifetimes can be changed.
30///
31/// On top of scrubbing the lifetimes, this trait can also do a transformation
32/// of the underlying type for convenience, similar to calling `Into::into`.
33#[diagnostic::on_unimplemented(
34    message = "`{Self}` does not implement `Trace`",
35    label = "cannot be rooted",
36    note = "Use #[derive(Trace)] to make `{Self}` Rootable",
37    note = "If this is a foreign type, implement `Trace` and `IntoRoot` manually"
38)]
39pub(crate) trait IntoRoot<T> {
40    unsafe fn into_root(self) -> T;
41}
42
43impl<'new, T, U> IntoRoot<Slot<U>> for T
44where
45    T: WithLifetime<'new, Out = U> + GcPtr,
46{
47    unsafe fn into_root(self) -> Slot<U> {
48        Slot::new(self.with_lifetime())
49    }
50}
51
52impl<T, U> IntoRoot<Option<U>> for Option<T>
53where
54    T: IntoRoot<U>,
55{
56    unsafe fn into_root(self) -> Option<U> {
57        self.map(|x| x.into_root())
58    }
59}
60
61impl<T, U> IntoRoot<Vec<U>> for Vec<T>
62where
63    T: IntoRoot<U>,
64{
65    unsafe fn into_root(self) -> Vec<U> {
66        let mut new = Vec::with_capacity(self.len());
67        for x in self {
68            new.push(x.into_root());
69        }
70        new
71    }
72}
73
74impl<T, U, Tx, Ux> IntoRoot<(Tx, Ux)> for (T, U)
75where
76    T: IntoRoot<Tx>,
77    U: IntoRoot<Ux>,
78{
79    unsafe fn into_root(self) -> (Tx, Ux) {
80        (self.0.into_root(), self.1.into_root())
81    }
82}
83
84impl<'a, T, U> IntoRoot<Slot<U>> for &Rt<Slot<T>>
85where
86    T: WithLifetime<'a, Out = U> + Copy,
87{
88    unsafe fn into_root(self) -> Slot<U> {
89        Slot::new(self.inner().get().with_lifetime())
90    }
91}
92
93impl<'a> IntoRoot<Slot<Object<'a>>> for bool {
94    unsafe fn into_root(self) -> Slot<Object<'a>> {
95        Slot::new(self.into())
96    }
97}
98
99impl<'a> IntoRoot<Slot<Object<'a>>> for i64 {
100    unsafe fn into_root(self) -> Slot<Object<'a>> {
101        Slot::new(self.into())
102    }
103}
104
105// Represents an object T rooted on the Stack. This will remove the the object
106// from the root set when dropped.
107#[doc(hidden)]
108pub(crate) struct __StackRoot<'rt, T> {
109    data: &'rt mut Rt<T>,
110    root_set: &'rt RootSet,
111}
112
113impl<T> AsMut<Rt<T>> for __StackRoot<'_, T> {
114    fn as_mut(&mut self) -> &mut Rt<T> {
115        self.data
116    }
117}
118
119impl<T: Debug> Debug for __StackRoot<'_, T> {
120    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121        Debug::fmt(self.data, f)
122    }
123}
124
125impl<T: Display> Display for __StackRoot<'_, T> {
126    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
127        Display::fmt(self.data, f)
128    }
129}
130
131// Do not use this function directly. Use the `root` macro instead.
132//
133// SAFETY: An owned StackRoot must never be exposed to the rest of the program.
134// That could result in calling `mem::forget` on the root, which would
135// invalidate the stack property of the root set.
136impl<'rt, T: Trace> __StackRoot<'rt, T> {
137    pub(crate) unsafe fn new(data: &'rt mut T, root_set: &'rt RootSet) -> __StackRoot<'rt, T> {
138        let dyn_ptr = data as &mut dyn Trace as *mut dyn Trace;
139        // We are using this transmute to dissociate the `dyn Trace` from the T.
140        // Otherwise rust tries to require us to add a 'static bound. We don't
141        // need this because stackroot can't outlive data (due to the 'rt
142        // lifetime), and therefore it can't outlive T.
143        let dyn_ptr = std::mem::transmute::<*mut dyn Trace, *mut dyn Trace>(dyn_ptr);
144        let data = &mut *(dyn_ptr.cast::<Rt<T>>());
145        let root = Self { data, root_set };
146        root_set.roots.borrow_mut().push(dyn_ptr);
147        root
148    }
149}
150
151impl<T> Drop for __StackRoot<'_, T> {
152    fn drop(&mut self) {
153        self.root_set.roots.borrow_mut().pop();
154    }
155}
156
157/// Represents an object T rooted on the Heap. Unlike [`__StackRoot`], this type
158/// owns its data via a `Box` and can live beyond a single stack frame. When
159/// dropped, it searches and removes itself from the root set (rather than just
160/// popping like StackRoot).
161///
162/// This is used for rooting objects that need to live in heap-allocated
163/// collections like channels, where stack-based rooting is not possible.
164#[doc(hidden)]
165pub(crate) struct __HeapRoot<T: Trace> {
166    data: Box<Rt<T>>,
167    root_ptr: *const dyn Trace,
168    root_set: &'static ThreadSafeRootSet,
169}
170
171impl<T: Trace> __HeapRoot<T> {
172    pub(crate) fn new(value: T, root_set: &'static ThreadSafeRootSet) -> Self {
173        let mut boxed = Box::new(Rt { inner: value, _aliasable: PhantomPinned });
174        let dyn_ptr = &mut boxed.inner as &mut T as &mut dyn Trace as *mut dyn Trace;
175        // Transmute to dissociate the `dyn Trace` from the T, similar to __StackRoot
176        // The pointer is safe to keep because `Rt` is pinned
177        let dyn_ptr = unsafe { std::mem::transmute::<*mut dyn Trace, *mut dyn Trace>(dyn_ptr) };
178
179        root_set.roots.lock().unwrap().push(dyn_ptr);
180
181        Self { data: boxed, root_ptr: dyn_ptr, root_set }
182    }
183}
184
185impl<T: Trace> Deref for __HeapRoot<T> {
186    type Target = Rt<T>;
187
188    fn deref(&self) -> &Self::Target {
189        &self.data
190    }
191}
192
193impl<T: Trace> DerefMut for __HeapRoot<T> {
194    fn deref_mut(&mut self) -> &mut Self::Target {
195        &mut self.data
196    }
197}
198
199impl<T: Trace> Drop for __HeapRoot<T> {
200    fn drop(&mut self) {
201        // Search and remove our root_ptr from the roots vector
202        let mut roots = self.root_set.roots.lock().unwrap();
203        if let Some(pos) = roots.iter().position(|&ptr| std::ptr::addr_eq(ptr, self.root_ptr)) {
204            roots.swap_remove(pos);
205        }
206    }
207}
208
209// SAFETY: __HeapRoot<T> is Send/Sync because:
210// 1. It owns its data via Box<Rt<T>>, which is heap-allocated and can move between threads
211// 2. The root_ptr is a raw pointer to data inside self.data, so it moves with the HeapRoot
212// 3. The ThreadSafeRootSet synchronizes all modifications to the root set
213// 4. The root_ptr is only dereferenced during GC, which is synchronized by the owner's mutex
214// 5. T: Trace ensures the contained data can be safely traced during GC
215
216unsafe impl<T: Trace> Send for __HeapRoot<T> {}
217unsafe impl<T: Trace> Sync for __HeapRoot<T> {}
218
219impl<T: Trace + Debug> Debug for __HeapRoot<T> {
220    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
221        Debug::fmt(&**self, f)
222    }
223}
224
225impl<T: Trace + Display> Display for __HeapRoot<T> {
226    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
227        Display::fmt(&**self, f)
228    }
229}
230
231/// Trait created to overpass the orphan rule when deriving the
232/// [Trace](`rune_macros::Trace`) derive macro. The derive
233/// macro contains a blanket `Deref` (and `DerefMut`) like this:
234///
235/// ```ignore
236/// unsafe { &*(rt as *const Rt<Self>).cast::<Self::Target>() }
237/// ```
238///
239/// By creating a trait that the functions defined in the main crate
240/// can define, we avoid the orphan rule by implementing `Deref`
241/// on the rooted version of the types: [Rt\<T\>](`self::Rt`).
242pub trait RootedDeref {
243    type Target;
244    fn rooted_deref(rooted: &Rt<Self>) -> &Self::Target;
245    fn rooted_derefmut(rooted: &mut Rt<Self>) -> &mut Self::Target;
246}
247
248impl<T: RootedDeref> Deref for Rt<T> {
249    type Target = <T as RootedDeref>::Target;
250    fn deref(&self) -> &Self::Target {
251        RootedDeref::rooted_deref(self)
252    }
253}
254
255impl<T: RootedDeref> DerefMut for Rt<T> {
256    fn deref_mut(&mut self) -> &mut Self::Target {
257        RootedDeref::rooted_derefmut(self)
258    }
259}
260
261/// A "Root Tracable" type. If a type is wrapped in Rt, it is known to be rooted
262/// and hold items past garbage collection. This type is never used as an owned
263/// type, only a reference. This ensures that underlying data does not move. In
264/// order to access the inner data, use [`Rt::bind_ref`] or [`Rt::bind_mut`]
265/// methods.
266#[repr(transparent)]
267#[derive(PartialEq, Eq)]
268pub struct Rt<T: ?Sized> {
269    _aliasable: PhantomPinned,
270    inner: T,
271}
272
273/// A "Root Tracable Object". This differs from [`Rt`] by wrapping a [`Slot`]
274/// which allows the underlying data to be moved during garbage collection. GC
275/// owned types will always be wrapped in a `Slot` when rooted. To access the
276/// object, use [`Rto::bind`].
277pub type Rto<T> = Rt<Slot<T>>;
278
279/// A moveable pointer to the GC heap. This is used to wrap [Rooted](`Rt`)
280/// [`Object`]'s so that we don't trigger UB when moving types during
281/// collection.
282#[repr(transparent)]
283#[derive(Default)]
284pub struct Slot<T: ?Sized> {
285    inner: UnsafeCell<T>,
286}
287
288impl<T: Clone> Clone for Slot<T> {
289    fn clone(&self) -> Self {
290        Self::new(self.get().clone())
291    }
292}
293
294impl<'new, T: WithLifetime<'new> + Copy> WithLifetime<'new> for Slot<T> {
295    type Out = Slot<<T as WithLifetime<'new>>::Out>;
296
297    unsafe fn with_lifetime(self) -> Self::Out {
298        Slot::new(self.get().with_lifetime())
299    }
300}
301
302impl<T: Hash> Hash for Slot<T> {
303    fn hash<H: Hasher>(&self, state: &mut H) {
304        self.get().hash(state);
305    }
306}
307
308impl<T: PartialEq> PartialEq for Slot<T> {
309    fn eq(&self, other: &Self) -> bool {
310        self.get() == other.get()
311    }
312}
313
314// This type signature is so complex due to lifetime restrictions around
315// invariance. deriving PartialEq will provide T == T. But if the lifetime is
316// invariant than two types with different lifetimes will be different types.
317// Using an UnsafeCell makes the lifetime invariant So we have to use
318// WithLifetime to convert the lifetime to the same invariant lifetime 'a.
319impl<'a, T, U> PartialEq<U> for Slot<T>
320where
321    U: WithLifetime<'a> + Copy,
322    T: PartialEq<<U as WithLifetime<'a>>::Out>,
323{
324    fn eq(&self, other: &U) -> bool {
325        *self.get() == unsafe { other.with_lifetime() }
326    }
327}
328
329impl<T: Eq> Eq for Slot<T> {}
330
331impl<T> Slot<T> {
332    fn get(&self) -> &T {
333        unsafe { &*self.inner.get() }
334    }
335
336    unsafe fn set(&self, new: T) {
337        *self.inner.get() = new
338    }
339
340    pub(crate) fn new(val: T) -> Self {
341        Slot { inner: UnsafeCell::new(val) }
342    }
343}
344
345impl<T> Deref for Slot<T> {
346    type Target = T;
347
348    fn deref(&self) -> &Self::Target {
349        self.get()
350    }
351}
352
353// This is the boundary between the traceable structs, and heap objects. Each
354// heap object that is rooted needs to live in a Slot, so everything below it is
355// also a heap object. We completely trace each object graph before moving to
356// the next slot.
357impl<T> Trace for Slot<T>
358where
359    T: TracePtr + GcMoveable<Value = T>,
360{
361    fn trace(&self, state: &mut GcState) {
362        if let Some((new, moved)) = self.get().move_value(&state.to_space) {
363            unsafe { self.set(new) };
364            if moved {
365                self.get().trace_ptr(state);
366                // finish tracing anything connected to this object. This will
367                // help them be co-located in memory.
368                state.trace_stack();
369            }
370        }
371    }
372}
373
374impl<T: Debug> Debug for Rt<T> {
375    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
376        Debug::fmt(&self.inner(), f)
377    }
378}
379
380impl<T: Display> Display for Rt<T> {
381    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
382        Display::fmt(&self.inner(), f)
383    }
384}
385
386impl<T: Debug> Debug for Slot<T> {
387    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
388        Debug::fmt(self.get(), f)
389    }
390}
391
392impl<T: Display> Display for Slot<T> {
393    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
394        Display::fmt(self.get(), f)
395    }
396}
397
398impl<T, U> PartialEq<U> for Rt<Slot<T>>
399where
400    Slot<T>: PartialEq<U>,
401{
402    fn eq(&self, other: &U) -> bool {
403        self.inner() == other
404    }
405}
406
407impl<T> Hash for Rt<T>
408where
409    T: Hash,
410{
411    fn hash<H: Hasher>(&self, state: &mut H) {
412        self.inner().hash(state);
413    }
414}
415
416impl<T> Rt<T> {
417    fn inner(&self) -> &T {
418        &self.inner
419    }
420
421    fn inner_mut(&mut self) -> &mut T {
422        &mut self.inner
423    }
424
425    fn inner_ptr(&self) -> *const T {
426        &self.inner as *const T
427    }
428
429    fn inner_mut_ptr(&mut self) -> *mut T {
430        &mut self.inner as *mut T
431    }
432
433    pub(crate) fn bind_ref<'a, 'ob>(&'a self, _: &'ob Context) -> &'a <T as WithLifetime<'ob>>::Out
434    where
435        T: WithLifetime<'ob>,
436    {
437        // SAFETY: We are holding a reference to the context
438        unsafe { &*self.inner_ptr().cast::<<T as WithLifetime<'ob>>::Out>() }
439    }
440
441    pub(crate) fn bind_mut<'a, 'ob>(
442        &'a mut self,
443        _: &'ob Context,
444    ) -> &'a mut <T as WithLifetime<'ob>>::Out
445    where
446        T: WithLifetime<'ob>,
447    {
448        // SAFETY: We are holding a reference to the context
449        unsafe { &mut *self.inner_mut_ptr().cast::<<T as WithLifetime<'ob>>::Out>() }
450    }
451
452    pub(crate) fn set<U: IntoRoot<T>>(&mut self, item: U) {
453        // SAFETY: we drop the old type so it never exposed and take the new
454        // rooted type and replace it.
455        unsafe { *self.inner_mut() = item.into_root() }
456    }
457}
458
459impl<T> Rt<Slot<T>> {
460    pub(crate) fn bind<'ob>(&self, _: &'ob Context) -> <T as WithLifetime<'ob>>::Out
461    where
462        T: WithLifetime<'ob> + Copy,
463    {
464        // SAFETY: We are holding a reference to the context
465        unsafe { self.inner().get().with_lifetime() }
466    }
467
468    pub(crate) unsafe fn bind_unchecked<'ob>(&'ob self) -> <T as WithLifetime<'ob>>::Out
469    where
470        T: WithLifetime<'ob> + Copy,
471    {
472        self.inner().get().with_lifetime()
473    }
474
475    /// Get a copy of the inner value without requiring a Context.
476    /// This is useful when you need to access the value but don't have a Context available.
477    pub(crate) fn get_inner(&self) -> T
478    where
479        T: Copy,
480    {
481        *self.inner().get()
482    }
483
484    pub(crate) fn bind_slice<'brw, 'ob, U>(
485        slice: &'brw [Rt<Slot<Gc<T>>>],
486        _: &'ob Context,
487    ) -> &'brw [Gc<U>]
488    where
489        Gc<T>: WithLifetime<'ob, Out = Gc<U>>,
490        Gc<U>: 'ob,
491    {
492        // SAFETY: Gc<T> does not have any niche optimizations, so it is safe to
493        // cast from a Rt<Slot>
494        unsafe { &*(slice as *const [Rt<Slot<Gc<T>>>] as *const [Gc<U>]) }
495    }
496}
497
498impl<T> Rt<Slot<Gc<T>>> {
499    /// Calls [untag](Untag::untag_erased) on the tagged Gc pointer
500    pub(crate) fn untag<'ob, U>(&self, cx: &'ob Context) -> U
501    where
502        Gc<T>: WithLifetime<'ob, Out = Gc<U>> + Copy,
503        Gc<U>: Untag<U>,
504    {
505        cx.bind(*self.inner().get()).untag_erased()
506    }
507
508    /// Like `try_into`, but needed to due no specialization
509    pub(crate) fn try_as<U, E>(&self) -> Result<&Rt<Slot<Gc<U>>>, E>
510    where
511        Gc<T>: TryInto<Gc<U>, Error = E> + Copy,
512    {
513        let _: Gc<U> = (*self.inner().get()).try_into()?;
514        // SAFETY: This is safe because all Gc types have the same representation
515        unsafe { Ok(&*((self as *const Self).cast::<Rt<Slot<Gc<U>>>>())) }
516    }
517}
518
519impl TryFrom<&Rt<Slot<Object<'_>>>> for usize {
520    type Error = anyhow::Error;
521
522    fn try_from(value: &Rt<Slot<Object>>) -> Result<Self, Self::Error> {
523        (*value.inner().get()).try_into()
524    }
525}
526
527impl<T> Rt<Slot<Gc<T>>> {
528    /// Like `try_into().bind(cx)`, but needed to due no specialization
529    pub(crate) fn bind_as<'ob, U, E>(&self, _cx: &'ob Context) -> Result<U, E>
530    where
531        Gc<T>: WithLifetime<'ob> + Copy,
532        <Gc<T> as WithLifetime<'ob>>::Out: TryInto<U, Error = E> + Copy,
533    {
534        unsafe { self.inner().get().with_lifetime().try_into() }
535    }
536
537    /// Like `Into`, but needed to due no specialization
538    pub(crate) fn cast<U>(&self) -> &Rt<Slot<Gc<U>>>
539    where
540        Gc<T>: Into<Gc<U>> + Copy,
541    {
542        // SAFETY: This is safe because all Gc types have the same representation
543        unsafe { &*((self as *const Self).cast::<Rt<Slot<Gc<U>>>>()) }
544    }
545
546    // TODO: Find a way to remove this method. We should never need to guess
547    // if something is cons
548    pub(crate) fn as_cons(&self) -> &Rt<Slot<Gc<&Cons>>> {
549        match self.inner().as_obj().untag() {
550            crate::core::object::ObjectType::Cons(_) => unsafe {
551                &*(self as *const Self).cast::<Rt<Slot<Gc<&Cons>>>>()
552            },
553            x => panic!("attempt to convert type that was not cons: {x}"),
554        }
555    }
556}
557
558impl From<&Rt<Slot<Object<'_>>>> for OptionalFlag {
559    fn from(value: &Rt<Slot<Object<'_>>>) -> Self {
560        value.inner().is_nil().then_some(())
561    }
562}
563
564impl<'a> Rt<Slot<Object<'a>>> {
565    pub(crate) fn try_as_option<T, E>(&self) -> Result<Option<&Rt<Slot<Gc<T>>>>, E>
566    where
567        Object<'a>: TryInto<Gc<T>, Error = E>,
568    {
569        if self.inner().is_nil() {
570            Ok(None)
571        } else {
572            let _: Gc<T> = (*self.inner().get()).try_into()?;
573            unsafe { Ok(Some(&*((self as *const Self).cast::<Rt<Slot<Gc<T>>>>()))) }
574        }
575    }
576}
577
578impl IntoObject for &Rt<Slot<Object<'_>>> {
579    type Out<'ob> = ObjectType<'ob>;
580
581    fn into_obj<const C: bool>(self, _block: &Block<C>) -> Gc<Self::Out<'_>> {
582        unsafe { self.inner().get().with_lifetime() }
583    }
584}
585
586impl IntoObject for Slot<Object<'_>> {
587    type Out<'ob> = ObjectType<'ob>;
588
589    fn into_obj<const C: bool>(self, _block: &Block<C>) -> Gc<Self::Out<'_>> {
590        unsafe { self.get().with_lifetime() }
591    }
592}
593
594impl IntoObject for &mut Rt<Slot<Object<'_>>> {
595    type Out<'ob> = ObjectType<'ob>;
596
597    fn into_obj<const C: bool>(self, _block: &Block<C>) -> Gc<Self::Out<'_>> {
598        unsafe { self.inner().get().with_lifetime() }
599    }
600}
601
602impl Rt<Slot<&Cons>> {
603    pub(crate) fn car<'ob>(&self, cx: &'ob Context) -> Object<'ob> {
604        self.bind(cx).car()
605    }
606
607    pub(crate) fn cdr<'ob>(&self, cx: &'ob Context) -> Object<'ob> {
608        self.bind(cx).cdr()
609    }
610}
611
612impl<T, U> Deref for Rt<(T, U)> {
613    type Target = (Rt<T>, Rt<U>);
614
615    fn deref(&self) -> &Self::Target {
616        unsafe { &*(self as *const Self).cast::<(Rt<T>, Rt<U>)>() }
617    }
618}
619
620impl<T, U> DerefMut for Rt<(T, U)> {
621    fn deref_mut(&mut self) -> &mut Self::Target {
622        unsafe { &mut *(self as *mut Rt<(T, U)>).cast::<(Rt<T>, Rt<U>)>() }
623    }
624}
625
626// Can't implement [`DerefMut`] because it would allow you to call
627// [`Option::take`] which would return an owned Rt and break the chain of
628// traceability
629impl<T> Deref for Rt<Option<T>> {
630    type Target = Option<Rt<T>>;
631    fn deref(&self) -> &Self::Target {
632        unsafe { &*self.inner_ptr().cast::<Self::Target>() }
633    }
634}
635
636impl<T, I, const N: usize> Index<I> for Rt<[T; N]>
637where
638    [Rt<T>]: Index<I>,
639{
640    type Output = <[Rt<T>] as Index<I>>::Output;
641
642    fn index(&self, index: I) -> &Self::Output {
643        let slice = unsafe { &*self.inner_ptr().cast::<[Rt<T>; N]>() };
644        Index::index(slice, index)
645    }
646}
647
648impl<T, I, const N: usize> IndexMut<I> for Rt<[T; N]>
649where
650    [Rt<T>]: IndexMut<I>,
651{
652    fn index_mut(&mut self, index: I) -> &mut Self::Output {
653        let slice = unsafe { &mut *self.inner_mut_ptr().cast::<[Rt<T>; N]>() };
654        IndexMut::index_mut(slice, index)
655    }
656}
657
658impl<T, const N: usize> AsRef<[Rt<T>]> for Rt<[T; N]> {
659    fn as_ref(&self) -> &[Rt<T>] {
660        unsafe { &*self.inner_ptr().cast::<[Rt<T>; N]>() }
661    }
662}
663
664impl<T> Rt<Vec<T>> {
665    // This is not safe to expose pub(crate) because you could call pop and get
666    // an owned Rt
667    fn as_mut_ref(&mut self) -> &mut Vec<Rt<T>> {
668        // SAFETY: `Rt<T>` has the same memory layout as `T`.
669        unsafe { &mut *(self as *mut Self).cast::<Vec<Rt<T>>>() }
670    }
671
672    pub(crate) fn push<U: IntoRoot<T>>(&mut self, item: U) {
673        self.inner_mut().push(unsafe { item.into_root() });
674    }
675
676    pub(crate) fn truncate(&mut self, len: usize) {
677        self.inner_mut().truncate(len);
678    }
679
680    pub(crate) fn pop(&mut self) {
681        self.inner_mut().pop();
682    }
683
684    pub(crate) fn swap_remove(&mut self, index: usize) {
685        self.inner_mut().swap_remove(index);
686    }
687
688    pub(crate) fn reserve(&mut self, additional: usize) {
689        self.inner_mut().reserve(additional);
690    }
691
692    pub(crate) fn capacity(&self) -> usize {
693        self.inner().capacity()
694    }
695}
696
697impl<T> Rt<Vec<T>> {
698    pub(crate) fn extend_from_slice<U: IntoRoot<T> + Copy>(&mut self, src: &[U]) {
699        // TODO: Slot fix extend_from_slice
700        let inner = self.inner_mut();
701        for x in src {
702            inner.push(unsafe { x.into_root() })
703        }
704    }
705}
706
707impl<T: Clone> Rt<Vec<T>> {
708    pub(crate) fn extend_from_within(&mut self, src: impl RangeBounds<usize>) {
709        self.inner_mut().extend_from_within(src);
710    }
711}
712
713impl<T> Deref for Rt<Vec<T>> {
714    type Target = [Rt<T>];
715    fn deref(&self) -> &Self::Target {
716        // SAFETY: `Rt<T>` has the same memory layout as `T`.
717        unsafe { &*(self as *const Self).cast::<Vec<Rt<T>>>() }
718    }
719}
720
721impl<T> DerefMut for Rt<Vec<T>> {
722    fn deref_mut(&mut self) -> &mut Self::Target {
723        // SAFETY: `Rt<T>` has the same memory layout as `T`.
724        unsafe { &mut *(self as *mut Self).cast::<Vec<Rt<T>>>() }
725    }
726}
727
728impl<T, I: SliceIndex<[Rt<T>]>> Index<I> for Rt<Vec<T>> {
729    type Output = I::Output;
730
731    fn index(&self, index: I) -> &Self::Output {
732        let slice: &[Rt<T>] = self;
733        Index::index(slice, index)
734    }
735}
736
737impl<T, I: SliceIndex<[Rt<T>]>> IndexMut<I> for Rt<Vec<T>> {
738    fn index_mut(&mut self, index: I) -> &mut Self::Output {
739        IndexMut::index_mut(self.as_mut_ref(), index)
740    }
741}
742
743#[derive(Debug)]
744#[repr(transparent)]
745/// A HashMap that can hold values past garbage collection.
746///
747/// This type is needed because Garbage Collection can move keys, which changes
748/// their hash value. `ObjectMap` will rehash the keys after collection.
749// It is not safe to Deref into the inner IndexMap type because we will be
750// constructing a mutable reference during garbage collection. So we have to
751// ensure that there cannot exist a &IndexMap to the same location.
752pub(crate) struct ObjectMap<K, V>(UnsafeCell<IndexMap<K, V>>);
753
754impl<K, V> Default for ObjectMap<K, V> {
755    fn default() -> Self {
756        Self(UnsafeCell::new(Default::default()))
757    }
758}
759
760impl<K, V> Rt<ObjectMap<K, V>>
761where
762    K: Eq + Hash,
763{
764    // inner function that should not be exposed
765    fn as_ref(&self) -> &IndexMap<K, V> {
766        unsafe { &*self.inner().0.get() }
767    }
768
769    // inner function that should not be exposed
770    fn as_mut(&mut self) -> &mut IndexMap<K, V> {
771        unsafe { &mut *self.inner_mut().0.get() }
772    }
773
774    pub(crate) fn insert<Kx: IntoRoot<K>, Vx: IntoRoot<V>>(&mut self, k: Kx, v: Vx) {
775        unsafe {
776            self.as_mut().insert(k.into_root(), v.into_root());
777        }
778    }
779
780    pub(crate) fn get<Q: IntoRoot<K>>(&self, k: Q) -> Option<&Rt<V>> {
781        use std::ptr::from_ref;
782        let inner = unsafe { &*from_ref(self.as_ref()).cast::<IndexMap<K, Rt<V>>>() };
783        let root = unsafe { k.into_root() };
784        inner.get(&root)
785    }
786
787    pub(crate) fn get_mut<Q: IntoRoot<K>>(&mut self, k: Q) -> Option<&mut Rt<V>> {
788        use std::ptr::from_mut;
789        let inner = unsafe { &mut *from_mut(self.as_mut()).cast::<IndexMap<K, Rt<V>>>() };
790        let root = unsafe { k.into_root() };
791        inner.get_mut(&root)
792    }
793
794    pub(crate) fn remove<Q: IntoRoot<K>>(&mut self, k: Q) {
795        let root = unsafe { k.into_root() };
796        self.as_mut().swap_remove(&root);
797    }
798}
799
800impl<K, V> Trace for ObjectMap<K, V>
801where
802    K: Trace + Hash + Eq,
803    V: Trace,
804{
805    fn trace(&self, state: &mut GcState) {
806        let map = unsafe { &mut *self.0.get() };
807        map.rehash_keys(|key, val| {
808            key.trace(state);
809            val.trace(state);
810        });
811    }
812}
813
814#[cfg(test)]
815mod test {
816    use crate::core::object::NIL;
817    use rune_core::macros::root;
818
819    use super::*;
820
821    #[test]
822    fn mem_swap() {
823        let root = &RootSet::default();
824        let cx = &mut Context::new(root);
825        let outer = cx.add("outer");
826        root!(outer, cx);
827        {
828            let inner = cx.add("inner");
829            root!(inner, cx);
830            std::mem::swap(outer, inner);
831        }
832        cx.garbage_collect(true);
833        assert_eq!(outer.bind(cx), "inner");
834    }
835
836    #[test]
837    fn indexing() {
838        let root = &RootSet::default();
839        let cx = &Context::new(root);
840        let mut vec = Rt { inner: vec![], _aliasable: PhantomPinned };
841
842        vec.push(NIL);
843        assert_eq!(vec[0], NIL);
844        let str1 = cx.add("str1");
845        let str2 = cx.add("str2");
846        vec.push(str1);
847        vec.push(str2);
848        assert_eq!(vec.bind_ref(cx)[0..3], vec![NIL, str1, str2]);
849    }
850
851    #[test]
852    fn test_object_map() {
853        type Map<'a> = ObjectMap<Slot<Object<'a>>, Slot<Object<'a>>>;
854        let root = &RootSet::default();
855        let cx = &mut Context::new(root);
856        root!(map, new(Map), cx);
857        let key = cx.add("key");
858
859        map.insert(key, cx.add("val"));
860        root!(key, cx);
861        cx.garbage_collect(true);
862        let val = map.get(key.bind(cx)).unwrap().bind(cx);
863        assert_eq!(val, "val");
864    }
865}