Skip to main content

dumpster/sync/
mod.rs

1/*
2    dumpster, a cycle-tracking garbage collector for Rust.    Copyright (C) 2023 Clayton Ramsey.
3
4    This Source Code Form is subject to the terms of the Mozilla Public
5    License, v. 2.0. If a copy of the MPL was not distributed with this
6    file, You can obtain one at http://mozilla.org/MPL/2.0/.
7*/
8
9//! Thread-safe shared garbage collection.
10//!
11//! Most users of this module will be interested in using [`Gc`] directly out of the box - this will
12//! just work.
13//! Those with more particular needs (such as benchmarking) should turn toward
14//! [`set_collect_condition`] in order to tune exactly when the garbage collector does cleanups.
15//!
16//! # Examples
17//!
18//! ```
19//! use dumpster::sync::Gc;
20//!
21//! let my_gc = Gc::new(100);
22//! let other_gc = my_gc.clone();
23//!
24//! drop(my_gc);
25//! drop(other_gc);
26//!
27//! // contents of the Gc are automatically freed
28//! ```
29
30mod cell;
31mod collect;
32#[cfg(loom)]
33mod loom_ext;
34#[cfg(all(loom, test))]
35mod loom_tests;
36#[cfg(all(test, not(loom)))]
37mod tests;
38
39use std::{
40    alloc::{dealloc, handle_alloc_error, Layout},
41    any::TypeId,
42    borrow::{Borrow, Cow},
43    fmt::Debug,
44    mem::{self, ManuallyDrop, MaybeUninit},
45    num::NonZeroUsize,
46    ops::Deref,
47    ptr::{self, addr_of, addr_of_mut, copy_nonoverlapping, drop_in_place, NonNull},
48    slice,
49};
50
51#[cfg(loom)]
52use loom::{
53    lazy_static,
54    sync::atomic::{fence, AtomicUsize, Ordering},
55};
56#[cfg(not(loom))]
57use std::sync::atomic::{fence, AtomicUsize, Ordering};
58
59use crate::{
60    contains_gcs, panic_deref_of_collected_object,
61    ptr::Nullable,
62    sync::{
63        cell::UCell,
64        collect::{Dfs, PrepareForDestruction},
65    },
66    Trace, TraceWith, Visitor,
67};
68
69use self::collect::{
70    collect_all_await, mark_clean, mark_dirty, n_gcs_dropped, n_gcs_existing, notify_created_gc,
71    notify_dropped_gc,
72};
73
74/// A soft limit on the amount of references that may be made to a `Gc`.
75///
76/// Going above this limit will abort your program (although not
77/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references.
78///
79/// See comment in `Gc::clone`.
80const MAX_STRONG_COUNT: usize = (isize::MAX) as usize;
81
82/// Allows tracing with all sync visitors.
83#[expect(private_bounds)]
84pub(crate) trait TraceSync:
85    for<'a> TraceWith<Dfs<'a>> + for<'a> TraceWith<PrepareForDestruction<'a>> + TraceWith<Rehydrate>
86{
87}
88
89impl<T> TraceSync for T where
90    T: ?Sized
91        + for<'a> TraceWith<Dfs<'a>>
92        + for<'a> TraceWith<PrepareForDestruction<'a>>
93        + TraceWith<Rehydrate>
94{
95}
96
97/// A thread-safe garbage-collected pointer.
98///
99/// This pointer can be duplicated and then shared across threads.
100/// Garbage collection is performed concurrently.
101///
102/// # Examples
103///
104/// ```
105/// use dumpster::sync::Gc;
106/// use std::sync::atomic::{AtomicUsize, Ordering};
107///
108/// let shared = Gc::new(AtomicUsize::new(0));
109///
110/// std::thread::scope(|s| {
111///     s.spawn(|| {
112///         let other_gc = shared.clone();
113///         other_gc.store(1, Ordering::Relaxed);
114///     });
115///
116///     shared.store(2, Ordering::Relaxed);
117/// });
118///
119/// println!("{}", shared.load(Ordering::Relaxed));
120/// ```
121///
122/// # Interaction with `Drop`
123///
124/// While collecting cycles, it's possible for a `Gc` to exist that points to some deallocated
125/// object.
126/// To prevent undefined behavior, these `Gc`s are marked as dead during collection and rendered
127/// inaccessible.
128/// Dereferencing or cloning a `Gc` during the `Drop` implementation of a `Trace` type could
129/// result in the program panicking to keep the program from accessing memory after freeing it.
130/// If you're accessing a `Gc` during a `Drop` implementation, make sure to use the fallible
131/// operations [`Gc::try_deref`] and [`Gc::try_clone`].
132pub struct Gc<T: Trace + Send + Sync + ?Sized + 'static> {
133    /// The pointer to the allocation.
134    ptr: UCell<Nullable<GcBox<T>>>,
135    /// The tag information of this pointer, used for mutation detection when marking.
136    tag: AtomicUsize,
137}
138
139#[cfg(not(loom))]
140/// The tag of the current sweep operation.
141/// All new allocations are minted with the current tag.
142static CURRENT_TAG: AtomicUsize = AtomicUsize::new(0);
143
144#[cfg(loom)]
145lazy_static! {
146    static ref CURRENT_TAG: AtomicUsize = AtomicUsize::new(0);
147}
148
149#[repr(C)]
150// This is only public to make the `sync_coerce_gc` macro work.
151#[doc(hidden)]
152/// The backing allocation for a [`Gc`].
153pub struct GcBox<T>
154where
155    T: Trace + Send + Sync + ?Sized,
156{
157    /// The "strong" count, which is the number of extant `Gc`s to this allocation.
158    /// If the strong count is zero, a value contained in the allocation may be dropped, but the
159    /// allocation itself must still be valid.
160    strong: AtomicUsize,
161    /// The "weak" count, which is the number of references to this allocation stored in to-collect
162    /// buffers by the collection algorithm.
163    /// If the weak count is zero, the allocation may be destroyed.
164    weak: AtomicUsize,
165    /// The current generation number of the allocation.
166    /// The generation number is assigned to the global generation every time a strong reference is
167    /// created or destroyed or a `Gc` pointing to this allocation is dereferenced.
168    generation: AtomicUsize,
169    /// The actual data stored in the allocation.
170    value: T,
171}
172
173unsafe impl<T> Send for Gc<T> where T: Trace + Send + Sync + ?Sized {}
174unsafe impl<T> Sync for Gc<T> where T: Trace + Send + Sync + ?Sized {}
175
176/// Begin a collection operation of the allocations on the heap.
177///
178/// Due to concurrency issues, this might not collect every single unreachable allocation that
179/// currently exists, but often calling `collect()` will get allocations made by this thread.
180///
181/// # Examples
182///
183/// ```
184/// use dumpster::sync::{collect, Gc};
185///
186/// let gc = Gc::new(vec![1, 2, 3]);
187/// drop(gc);
188///
189/// collect(); // the vector originally in `gc` _might_ be dropped now, but could be dropped later
190/// ```
191pub fn collect() {
192    collect_all_await();
193}
194
195#[derive(Debug)]
196/// Information passed to a [`CollectCondition`] used to determine whether the garbage collector
197/// should start collecting.
198///
199/// A `CollectInfo` is exclusively created by being passed as an argument to the collection
200/// condition.
201/// To set a custom collection condition, refer to [`set_collect_condition`].
202///
203/// # Examples
204///
205/// ```
206/// use dumpster::sync::{set_collect_condition, CollectInfo};
207///
208/// fn my_collect_condition(info: &CollectInfo) -> bool {
209///     (info.n_gcs_dropped_since_last_collect() + info.n_gcs_existing()) % 2 == 0
210/// }
211///
212/// set_collect_condition(my_collect_condition);
213/// ```
214pub struct CollectInfo {
215    /// Dummy value so this is a private structure.
216    _private: (),
217}
218
219/// A function which determines whether the garbage collector should start collecting.
220/// This type primarily exists so that it can be used with [`set_collect_condition`].
221///
222/// # Examples
223///
224/// ```rust
225/// use dumpster::sync::{set_collect_condition, CollectInfo};
226///
227/// fn always_collect(_: &CollectInfo) -> bool {
228///     true
229/// }
230///
231/// set_collect_condition(always_collect);
232/// ```
233pub type CollectCondition = fn(&CollectInfo) -> bool;
234
235#[must_use]
236/// The default collection condition used by the garbage collector.
237///
238/// There are no guarantees about what this function returns, other than that it will return `true`
239/// with sufficient frequency to ensure that all `Gc` operations are amortized _O(1)_ in runtime.
240///
241/// This function isn't really meant to be called by users, but rather it's supposed to be handed
242/// off to [`set_collect_condition`] to return to the default operating mode of the library.
243///
244/// This collection condition applies globally, i.e. to every thread.
245///
246/// # Examples
247///
248/// ```rust
249/// use dumpster::sync::{default_collect_condition, set_collect_condition, CollectInfo};
250///
251/// fn other_collect_condition(info: &CollectInfo) -> bool {
252///     info.n_gcs_existing() >= 25 || default_collect_condition(info)
253/// }
254///
255/// // Use my custom collection condition.
256/// set_collect_condition(other_collect_condition);
257///
258/// // I'm sick of the custom collection condition.
259/// // Return to the original.
260/// set_collect_condition(default_collect_condition);
261/// ```
262pub fn default_collect_condition(info: &CollectInfo) -> bool {
263    info.n_gcs_dropped_since_last_collect() > info.n_gcs_existing()
264}
265
266pub use collect::set_collect_condition;
267
268impl<T> Gc<T>
269where
270    T: Trace + Send + Sync + ?Sized,
271{
272    /// Construct a new garbage-collected value.
273    ///
274    /// # Examples
275    ///
276    /// ```
277    /// use dumpster::sync::Gc;
278    ///
279    /// let _ = Gc::new(0);
280    /// ```
281    pub fn new(value: T) -> Gc<T>
282    where
283        T: Sized,
284    {
285        notify_created_gc();
286        Gc {
287            ptr: UCell::new(Nullable::new(NonNull::from(Box::leak(Box::new(GcBox {
288                strong: AtomicUsize::new(1),
289                weak: AtomicUsize::new(0),
290                generation: AtomicUsize::new(CURRENT_TAG.load(Ordering::Acquire)),
291                value,
292            }))))),
293            tag: AtomicUsize::new(0),
294        }
295    }
296
297    /// Construct a self-referencing `Gc`.
298    ///
299    /// `new_cyclic` first allocates memory for `T`, then constructs a dead `Gc`.
300    ///  The dead `Gc` is then passed to `data_fn` to construct a value of `T`, which
301    /// is stored in the allocation. Finally, `new_cyclic` will update the dead self-referential
302    /// `Gc`s and rehydrate them to produce the final value.
303    ///
304    /// # Panics
305    ///
306    /// If `data_fn` panics, the panic is propagated to the caller.
307    /// The allocation is cleaned up normally.
308    ///
309    /// Additionally, if, when attempting to rehydrate the `Gc` members of `F`, the visitor fails to
310    /// reach a `Gc`, this function will panic and reserve the allocation to be cleaned up
311    /// later.
312    ///
313    /// # Notes on safety
314    ///
315    /// Incorrect implementations of `data_fn` may have unusual or strange results.
316    /// Although `dumpster` guarantees that it will be safe, and will do its best to ensure correct
317    /// results, it is generally unwise to allow dead `Gc`s to exist for long.
318    /// If you implement `data_fn` wrong, this may cause panics later on inside of the collection
319    /// process.
320    ///
321    /// # Examples
322    ///
323    /// ```
324    /// use dumpster::{sync::Gc, Trace};
325    ///
326    /// #[derive(Trace)]
327    /// struct Cycle {
328    ///     this: Gc<Self>,
329    /// }
330    ///
331    /// let gc = Gc::new_cyclic(|this| Cycle { this });
332    /// assert!(Gc::ptr_eq(&gc, &gc.this));
333    /// ```
334    pub fn new_cyclic<F: FnOnce(Self) -> T>(data_fn: F) -> Self
335    where
336        T: Sized,
337    {
338        /// A struct containing an uninitialized value of `T`.
339        /// May only be used inside `new_cyclic`.
340        #[repr(transparent)]
341        struct Uninitialized<T>(MaybeUninit<T>);
342
343        unsafe impl<V: Visitor, T> TraceWith<V> for Uninitialized<T> {
344            fn accept(&self, _: &mut V) -> Result<(), ()> {
345                Ok(())
346            }
347        }
348
349        /// Data structure for cleaning up the allocation in case we panic along the way.
350        struct CleanUp<T: Trace + Send + Sync + 'static> {
351            /// Is `true` if the [`GcBox::value`] is initialized.
352            initialized: bool,
353            /// Pointer to the `GcBox` with a maybe uninitialized value.
354            ptr: NonNull<GcBox<T>>,
355        }
356
357        impl<T: Trace + Send + Sync + 'static> Drop for CleanUp<T> {
358            fn drop(&mut self) {
359                if self.initialized {
360                    // push this `Gc` into the destruction queue
361                    unsafe { mark_dirty(self.ptr) };
362                } else {
363                    // deallocate because this `Gc` is not initialized
364                    unsafe {
365                        dealloc(
366                            self.ptr.as_ptr().cast::<u8>(),
367                            Layout::for_value(self.ptr.as_ref()),
368                        );
369                    }
370                }
371            }
372        }
373
374        // make an uninitialized allocation
375        notify_created_gc();
376        let mut gcbox = NonNull::from(Box::leak(Box::new(GcBox {
377            strong: AtomicUsize::new(1),
378            weak: AtomicUsize::new(0),
379            generation: AtomicUsize::new(CURRENT_TAG.load(Ordering::Acquire)),
380            value: Uninitialized(MaybeUninit::<T>::uninit()),
381        })));
382        let mut cleanup = CleanUp {
383            ptr: gcbox,
384            initialized: false,
385        };
386
387        // nilgc is a dead Gc
388        let nilgc = Gc {
389            tag: AtomicUsize::new(0),
390            ptr: UCell::new(Nullable::new(gcbox.cast::<GcBox<T>>()).as_null()),
391        };
392        assert!(Gc::is_dead(&nilgc));
393        unsafe {
394            // SAFETY: `gcbox` is a valid pointer to an uninitialized datum that we have allocated.
395            gcbox.as_mut().value = Uninitialized(MaybeUninit::new(data_fn(nilgc)));
396        }
397        cleanup.initialized = true;
398
399        let gcbox = gcbox.cast::<GcBox<T>>();
400        let res = unsafe {
401            // SAFETY: the above unsafe block correctly constructed the Uninitialized value, so it
402            // is safe to cast `gcbox` and then construct a reference.
403            gcbox.as_ref().value.accept(&mut Rehydrate {
404                ptr: Nullable::new(gcbox.cast()),
405                type_id: TypeId::of::<T>(),
406            })
407        };
408
409        assert!(
410            res.is_ok(),
411            "visitor must be able to access all Gc fields of structure when rehydrating dead Gcs"
412        );
413        let gc = Gc {
414            ptr: UCell::new(Nullable::new(gcbox)),
415            tag: AtomicUsize::new(CURRENT_TAG.load(Ordering::Acquire)),
416        };
417
418        let _ = ManuallyDrop::new(cleanup);
419        gc
420    }
421
422    /// Attempt to dereference this `Gc`.
423    ///
424    /// This function will return `None` if `self` is a "dead" `Gc`, which points to an
425    /// already-deallocated object.
426    /// This can only occur if a `Gc` is accessed during the `Drop` implementation of a
427    /// [`Trace`] object.
428    ///
429    /// For a version which panics instead of returning `None`, consider using [`Deref`].
430    ///
431    /// # Examples
432    ///
433    /// For a still-living `Gc`, this always returns `Some`.
434    ///
435    /// ```
436    /// use dumpster::sync::Gc;
437    ///
438    /// let gc1 = Gc::new(0);
439    /// assert!(Gc::try_deref(&gc1).is_some());
440    /// ```
441    ///
442    /// The only way to get a `Gc` that fails on `try_deref` is by accessing a `Gc` during its
443    /// `Drop` implementation.
444    ///
445    /// ```
446    /// use dumpster::{sync::Gc, Trace};
447    /// use std::sync::Mutex;
448    ///
449    /// #[derive(Trace)]
450    /// struct Cycle(Mutex<Option<Gc<Self>>>);
451    ///
452    /// impl Drop for Cycle {
453    ///     fn drop(&mut self) {
454    ///         let guard = self.0.lock().unwrap();
455    ///         let maybe_ref = Gc::try_deref(guard.as_ref().unwrap());
456    ///         assert!(maybe_ref.is_none());
457    ///     }
458    /// }
459    ///
460    /// let gc1 = Gc::new(Cycle(Mutex::new(None)));
461    /// *gc1.0.lock().unwrap() = Some(gc1.clone());
462    /// # drop(gc1);
463    /// # dumpster::sync::collect();
464    /// ```
465    pub fn try_deref(gc: &Gc<T>) -> Option<&T> {
466        unsafe { (!gc.ptr.get().is_null()).then(|| &**gc) }
467    }
468
469    /// Attempt to clone this `Gc`.
470    ///
471    /// This function will return `None` if `self` is a "dead" `Gc`, which does not point to an
472    /// existing object. For details on dead `Gc`s, refer to [`Gc::is_dead`].
473    ///
474    /// For a version that simply clones the dead `Gc`, use [`Clone`].
475    ///
476    /// # Examples
477    ///
478    /// For a still-living `Gc`, this always returns `Some`.
479    ///
480    /// ```
481    /// use dumpster::sync::Gc;
482    ///
483    /// let gc1 = Gc::new(0);
484    /// let gc2 = Gc::try_clone(&gc1).unwrap();
485    /// ```
486    ///
487    /// The only way to get a `Gc` which fails on `try_clone` is by accessing a `Gc` during its
488    /// `Drop` implementation.
489    ///
490    /// ```
491    /// use dumpster::{sync::Gc, Trace};
492    ///
493    /// #[derive(Trace)]
494    /// struct Cycle(Gc<Self>);
495    ///
496    /// impl Drop for Cycle {
497    ///     fn drop(&mut self) {
498    ///         let cloned = Gc::try_clone(&self.0);
499    ///         assert!(cloned.is_none());
500    ///     }
501    /// }
502    ///
503    /// let gc1 = Gc::new_cyclic(|gc| Cycle(gc));
504    /// # drop(gc1);
505    /// # dumpster::sync::collect();
506    /// ```
507    pub fn try_clone(gc: &Gc<T>) -> Option<Gc<T>> {
508        unsafe { (!gc.ptr.get().is_null()).then(|| gc.clone()) }
509    }
510
511    /// Provides a raw pointer to the data.
512    ///
513    /// Panics if `self` is a "dead" `Gc`,
514    /// which points to an already-deallocated object.
515    /// This can only occur if a `Gc` is accessed during the `Drop` implementation of a
516    /// [`Trace`] object.
517    ///
518    /// # Examples
519    ///
520    /// ```
521    /// use dumpster::sync::Gc;
522    /// let x = Gc::new("hello".to_owned());
523    /// let y = Gc::clone(&x);
524    /// let x_ptr = Gc::as_ptr(&x);
525    /// assert_eq!(x_ptr, Gc::as_ptr(&x));
526    /// assert_eq!(unsafe { &*x_ptr }, "hello");
527    /// ```
528    pub fn as_ptr(gc: &Gc<T>) -> *const T {
529        unsafe {
530            let ptr = NonNull::as_ptr(gc.ptr.get().unwrap());
531            addr_of_mut!((*ptr).value)
532        }
533    }
534
535    /// Determine whether two `Gc`s are equivalent by reference.
536    /// Returns `true` if both `this` and `other` point to the same value, in the same style as
537    /// [`std::ptr::eq`].
538    ///
539    /// # Examples
540    ///
541    /// ```
542    /// use dumpster::sync::Gc;
543    ///
544    /// let gc1 = Gc::new(0);
545    /// let gc2 = Gc::clone(&gc1); // points to same spot as `gc1`
546    /// let gc3 = Gc::new(0); // same value, but points to a different object than `gc1`
547    ///
548    /// assert!(Gc::ptr_eq(&gc1, &gc2));
549    /// assert!(!Gc::ptr_eq(&gc1, &gc3));
550    /// ```
551    pub fn ptr_eq(this: &Gc<T>, other: &Gc<T>) -> bool {
552        unsafe { this.ptr.get() }.as_option() == unsafe { other.ptr.get() }.as_option()
553    }
554
555    /// Get the number of references to the value pointed to by this `Gc`.
556    ///
557    /// This does not include internal references generated by the garbage collector.
558    ///
559    /// # Panics
560    ///
561    /// This function may panic if the `Gc` whose reference count we are loading is "dead" (i.e.
562    /// generated through a `Drop` implementation). For further reference, take a look at
563    /// [`Gc::is_dead`].
564    ///
565    /// # Examples
566    ///
567    /// ```
568    /// use dumpster::sync::Gc;
569    ///
570    /// let gc = Gc::new(());
571    /// assert_eq!(Gc::ref_count(&gc).get(), 1);
572    /// let gc2 = gc.clone();
573    /// assert_eq!(Gc::ref_count(&gc).get(), 2);
574    /// drop(gc);
575    /// drop(gc2);
576    /// ```
577    pub fn ref_count(gc: &Self) -> NonZeroUsize {
578        let box_ptr = unsafe { gc.ptr.get() }.expect(
579            "Attempt to dereference Gc to already-collected object. \
580    This means a Gc escaped from a Drop implementation, likely implying a bug in your code.",
581        );
582        let box_ref = unsafe { box_ptr.as_ref() };
583        NonZeroUsize::new(box_ref.strong.load(Ordering::Relaxed))
584            .expect("strong count to a GcBox may never be zero while a Gc to it exists")
585    }
586
587    /// Determine whether this is a dead `Gc`.
588    ///
589    /// A `Gc` is dead if it is not usable as a reference to any value.
590    /// Currently, a dead `Gc` may only be produced by accessing a `Gc` inside of the `Drop`
591    /// implementation of a garbage-collected value or by using the `Gc` provided to the
592    /// construction function in [`Gc::new_cyclic`].
593    ///
594    /// # Examples
595    ///
596    /// ```
597    /// use dumpster::{sync::Gc, Trace};
598    ///
599    /// #[derive(Trace)]
600    /// struct Cycle(Gc<Self>);
601    ///
602    /// impl Drop for Cycle {
603    ///     fn drop(&mut self) {
604    ///         assert!(Gc::is_dead(&self.0));
605    ///     }
606    /// }
607    ///
608    /// let gc1 = Gc::new_cyclic(|gc| Cycle(gc));
609    /// # drop(gc1);
610    /// # dumpster::sync::collect();
611    /// ```
612    #[inline]
613    pub fn is_dead(gc: &Self) -> bool {
614        unsafe { gc.ptr.get() }.is_null()
615    }
616
617    /// Consumes the `Gc<T>`, returning the inner `GcBox<T>` pointer and tag.
618    #[inline]
619    #[must_use]
620    fn into_ptr(this: Self) -> (*const GcBox<T>, usize) {
621        let this = ManuallyDrop::new(this);
622        let tag = &raw const this.tag;
623        let ptr = unsafe { this.ptr.get().as_ptr() };
624        let tag = unsafe { tag.read() }.into_inner();
625        (ptr, tag)
626    }
627
628    /// Constructs a `Gc<T>` from the innner `GcBox<T>` pointer and tag.
629    #[inline]
630    #[must_use]
631    unsafe fn from_ptr(ptr: *const GcBox<T>, tag: usize) -> Self {
632        Self {
633            ptr: UCell::new(Nullable::from_ptr(ptr.cast_mut())),
634            tag: AtomicUsize::new(tag),
635        }
636    }
637
638    /// Kill this `Gc`, making it dead.
639    ///
640    /// # Safety
641    ///
642    /// The caller is responsible for making sure that no other code can access this `Gc` while
643    /// `kill` is running.
644    unsafe fn kill(&self) {
645        self.ptr.set(self.ptr.get().as_null());
646    }
647
648    /// Exists solely for the [`coerce_gc`] macro.
649    #[inline]
650    #[must_use]
651    #[doc(hidden)]
652    pub fn __private_into_ptr(this: Self) -> (*const GcBox<T>, usize) {
653        Self::into_ptr(this)
654    }
655
656    /// Exists solely for the [`coerce_gc`] macro.
657    #[inline]
658    #[must_use]
659    #[doc(hidden)]
660    pub unsafe fn __private_from_ptr(ptr: *const GcBox<T>, tag: usize) -> Self {
661        Self::from_ptr(ptr, tag)
662    }
663}
664
665/// A struct for converting dead `Gc`s into live ones.
666///
667/// This is used in [`Gc::new_cyclic`].
668pub(super) struct Rehydrate {
669    /// The pointer to the currently hydrating [`GcBox`].
670    ptr: Nullable<GcBox<()>>,
671    /// The [`TypeId`] of `T` in `Gc<T>` to be hydrated.
672    type_id: TypeId,
673}
674
675impl Visitor for Rehydrate {
676    fn visit_sync<T>(&mut self, gc: &Gc<T>)
677    where
678        T: Trace + Send + Sync + ?Sized,
679    {
680        if Gc::is_dead(gc) && TypeId::of::<T>() == self.type_id {
681            unsafe {
682                // SAFETY: it is safe to transmute these pointers because we have checked
683                // that they are of the same type.
684                // Additionally, the `GcBox` has been fully initialized, so it is safe to
685                // create a reference here.
686                let cell_ptr = (&raw const gc.ptr).cast::<UCell<Nullable<GcBox<()>>>>();
687                (*cell_ptr).set(self.ptr);
688
689                let box_ref = &*self.ptr.as_ptr();
690                let old_strong = box_ref.strong.fetch_add(1, Ordering::Relaxed);
691                // Check for overflow. See implementation of clone for details.
692                if old_strong > MAX_STRONG_COUNT {
693                    std::process::abort();
694                }
695                box_ref
696                    .generation
697                    .store(CURRENT_TAG.load(Ordering::Acquire), Ordering::Release);
698                notify_created_gc();
699            }
700        }
701    }
702
703    fn visit_unsync<T>(&mut self, _: &crate::unsync::Gc<T>)
704    where
705        T: Trace + ?Sized,
706    {
707    }
708}
709
710impl<T: Trace + Send + Sync + Clone> Gc<T> {
711    /// Makes a mutable reference to the given `Gc`.
712    ///
713    /// If there are other `Gc` pointers to the same allocation, then `make_mut` will
714    /// [`clone`] the inner value to a new allocation to ensure unique ownership. This is also
715    /// referred to as clone-on-write.
716    ///
717    /// [`clone`]: Clone::clone
718    ///
719    /// # Panics
720    ///
721    /// This function may panic if the `Gc` whose reference count we are loading is "dead" (i.e.
722    /// generated through a `Drop` implementation). For further reference, take a look at
723    /// [`Gc::is_dead`].
724    ///
725    /// # Examples
726    ///
727    /// ```
728    /// use dumpster::sync::Gc;
729    ///
730    /// let mut data = Gc::new(5);
731    ///
732    /// *Gc::make_mut(&mut data) += 1; // Won't clone anything
733    /// let mut other_data = Gc::clone(&data); // Won't clone inner data
734    /// *Gc::make_mut(&mut data) += 1; // Clones inner data
735    /// *Gc::make_mut(&mut data) += 1; // Won't clone anything
736    /// *Gc::make_mut(&mut other_data) *= 2; // Won't clone anything
737    ///
738    /// // Now `data` and `other_data` point to different allocations.
739    /// assert_eq!(*data, 8);
740    /// assert_eq!(*other_data, 12);
741    /// ```
742    #[inline]
743    pub fn make_mut(this: &mut Self) -> &mut T {
744        if Gc::is_dead(this) {
745            panic_deref_of_collected_object();
746        }
747
748        // SAFETY: we checked above that the object is alive (not null)
749        let box_ref = unsafe { this.ptr.get().unwrap_unchecked().as_ref() };
750
751        let strong = box_ref.strong.load(Ordering::Acquire);
752        let weak = box_ref.weak.load(Ordering::Acquire);
753
754        if strong != 1 || weak != 0 {
755            // We don't have unique access to the value so we need to clone it.
756            *this = Gc::new(box_ref.value.clone());
757        }
758
759        // SAFETY: we have exclusive access to this `GcBox` because we ensured
760        // that we hold the only reference to this allocation.
761        // No other `Gc`s point to this allocation because the strong count is 1, and there are no
762        // loose pointers internal to the collector because the weak count is 0.
763        unsafe { &mut (*this.ptr.get().as_ptr()).value }
764    }
765}
766
767/// Allows coercing `T` of [`Gc<T>`](Gc).
768///
769/// This means that you can convert a `Gc` containing a strictly-sized type (such as `[T; N]`) into
770/// a `Gc` containing its unsized version (such as `[T]`), all without using nightly-only features.
771///
772/// This is one of two easy ways to create a `Gc<[T]>`; the other method is to use [`FromIterator`].
773///
774/// # Examples
775///
776/// ```
777/// use dumpster::sync::{coerce_gc, Gc};
778///
779/// let gc1: Gc<[u8; 3]> = Gc::new([7, 8, 9]);
780/// let gc2: Gc<[u8]> = coerce_gc!(gc1);
781/// assert_eq!(&gc2[..], &[7, 8, 9]);
782/// ```
783///
784/// Note that although this macro allows for type conversion, it _cannot_ be used for converting
785/// between incompatible types.
786///
787/// ```compile_fail
788/// // This program is incorrect!
789/// use dumpster::sync::{Gc, coerce_gc};
790///
791/// let gc1: Gc<u8> = Gc::new(1);
792/// let gc2: Gc<i8> = coerce_gc!(gc1);
793/// ```
794#[doc(hidden)]
795#[macro_export]
796macro_rules! __sync_coerce_gc {
797    ($gc:expr) => {{
798        // Temporarily convert the `Gc` into a raw pointer to allow for coercion to occur.
799        let (ptr, tag): (*const _, usize) = $crate::sync::Gc::__private_into_ptr($gc);
800        unsafe { $crate::sync::Gc::__private_from_ptr(ptr, tag) }
801    }};
802}
803
804#[doc(inline)]
805pub use crate::__sync_coerce_gc as coerce_gc;
806
807impl<T> Clone for Gc<T>
808where
809    T: Trace + Send + Sync + ?Sized,
810{
811    /// Clone a garbage-collected reference.
812    /// This does not clone the underlying data.
813    /// If this `Gc` is [dead](`Gc::is_dead`), this will produce another dead `Gc`.
814    ///
815    /// For a fallible version, refer to [`Gc::try_clone`].
816    ///
817    /// # Examples
818    ///
819    /// ```
820    /// use dumpster::sync::Gc;
821    /// use std::sync::atomic::{AtomicU8, Ordering};
822    ///
823    /// let gc1 = Gc::new(AtomicU8::new(0));
824    /// let gc2 = gc1.clone();
825    ///
826    /// gc1.store(1, Ordering::Relaxed);
827    /// assert_eq!(gc2.load(Ordering::Relaxed), 1);
828    /// ```
829    ///
830    /// Note that you can also clone a dead `Gc`.
831    ///
832    /// ```
833    /// use dumpster::{sync::Gc, Trace};
834    /// use std::sync::Mutex;
835    ///
836    /// #[derive(Trace)]
837    /// struct Cycle(Gc<Self>);
838    ///
839    /// impl Drop for Cycle {
840    ///     fn drop(&mut self) {
841    ///         let gc = self.0.clone();
842    ///         assert!(Gc::is_dead(&gc));
843    ///     }
844    /// }
845    ///
846    /// let gc1 = Gc::new_cyclic(|gc| Cycle(gc));
847    /// # drop(gc1);
848    /// # dumpster::sync::collect();
849    /// ```
850    fn clone(&self) -> Gc<T> {
851        if Gc::is_dead(self) {
852            // Clone dead Gcs by doing a naive copy.
853            return unsafe { ptr::read(self) };
854        }
855        let box_ref = unsafe { self.ptr.get().unwrap().as_ref() };
856
857        // increment strong count before generation to ensure cleanup never underestimates ref count
858        let old_strong = box_ref.strong.fetch_add(1, Ordering::Acquire);
859
860        // We need to guard against massive refcounts in case someone is `mem::forget`ing
861        // Gcs. If we don't do this the count can overflow and users will use-after free. This
862        // branch will never be taken in any realistic program. We abort because such a program is
863        // incredibly degenerate, and we don't care to support it.
864        //
865        // This check is not 100% water-proof: we error when the refcount grows beyond `isize::MAX`.
866        // But we do that check *after* having done the increment, so there is a chance here that
867        // the worst already happened and we actually do overflow the `usize` counter. However, that
868        // requires the counter to grow from `isize::MAX` to `usize::MAX` between the increment
869        // above and the `abort` below, which seems exceedingly unlikely.
870        if old_strong > MAX_STRONG_COUNT {
871            std::process::abort();
872        }
873
874        box_ref
875            .generation
876            .store(CURRENT_TAG.load(Ordering::Acquire), Ordering::Release);
877
878        notify_created_gc();
879        // mark_clean(box_ref); // causes performance drops
880
881        Gc {
882            ptr: UCell::new(unsafe { self.ptr.get() }),
883            tag: AtomicUsize::new(CURRENT_TAG.load(Ordering::Acquire)),
884        }
885    }
886}
887
888impl<T> Drop for Gc<T>
889where
890    T: Trace + Send + Sync + ?Sized,
891{
892    fn drop(&mut self) {
893        let Some(mut ptr) = unsafe { self.ptr.get() }.as_option() else {
894            return;
895        };
896        let box_ref = unsafe { ptr.as_ref() };
897        box_ref.weak.fetch_add(1, Ordering::AcqRel); // ensures that this allocation wasn't freed
898                                                     // while we weren't looking
899        box_ref
900            .generation
901            .store(CURRENT_TAG.load(Ordering::Relaxed), Ordering::Release);
902        match box_ref.strong.fetch_sub(1, Ordering::AcqRel) {
903            0 => unreachable!("strong cannot reach zero while a Gc to it exists"),
904            1 => {
905                mark_clean(box_ref);
906                if box_ref.weak.fetch_sub(1, Ordering::Release) == 1 {
907                    // destroyed the last weak reference! we can safely deallocate this
908                    let layout = Layout::for_value(box_ref);
909                    fence(Ordering::Acquire);
910                    unsafe {
911                        drop_in_place(ptr.as_mut());
912                        dealloc(ptr.as_ptr().cast(), layout);
913                    }
914                }
915            }
916            _ => {
917                if contains_gcs(&box_ref.value).unwrap_or(true) {
918                    // SAFETY: `ptr` is convertible to a reference
919                    // We don't use `box_ref` here because that pointer
920                    // only has `SharedReadOnly` permissions under the stacked borrows model
921                    // when we need `Unique` for the `TrashCan`.
922                    unsafe { mark_dirty(ptr) };
923                }
924                box_ref.weak.fetch_sub(1, Ordering::Release);
925            }
926        }
927        notify_dropped_gc();
928    }
929}
930
931impl CollectInfo {
932    #[must_use]
933    /// Get the number of times that a [`Gc`] has been dropped since the last time a collection
934    /// operation was performed.
935    ///
936    /// # Examples
937    ///
938    /// ```
939    /// use dumpster::sync::{set_collect_condition, CollectInfo};
940    ///
941    /// // Collection condition for whether many Gc's have been dropped.
942    /// fn have_many_gcs_dropped(info: &CollectInfo) -> bool {
943    ///     info.n_gcs_dropped_since_last_collect() > 100
944    /// }
945    ///
946    /// set_collect_condition(have_many_gcs_dropped);
947    /// ```
948    pub fn n_gcs_dropped_since_last_collect(&self) -> usize {
949        n_gcs_dropped()
950    }
951
952    #[must_use]
953    /// Get the total number of [`Gc`]s which currently exist.
954    ///
955    /// # Examples
956    ///
957    /// ```
958    /// use dumpster::sync::{set_collect_condition, CollectInfo};
959    ///
960    /// // Collection condition for whether many Gc's currently exist.
961    /// fn do_many_gcs_exist(info: &CollectInfo) -> bool {
962    ///     info.n_gcs_existing() > 100
963    /// }
964    ///
965    /// set_collect_condition(do_many_gcs_exist);
966    /// ```
967    pub fn n_gcs_existing(&self) -> usize {
968        n_gcs_existing()
969    }
970}
971
972impl<T: Trace + Send + Sync + ?Sized> Gc<T> {
973    /// Allocates an `GcBox<T>` with sufficient space for
974    /// a value of the provided layout.
975    ///
976    /// The function `mem_to_gc_box` is called with the data pointer
977    /// and must return back a pointer for the `GcBox<T>`.
978    unsafe fn allocate_for_layout(
979        value_layout: Layout,
980        mem_to_gc_box: impl FnOnce(*mut u8) -> *mut GcBox<T>,
981    ) -> *mut GcBox<T> {
982        let layout = Layout::new::<GcBox<()>>()
983            .extend(value_layout)
984            .unwrap()
985            .0
986            .pad_to_align();
987
988        Self::allocate_for_layout_of_box(layout, mem_to_gc_box)
989    }
990
991    /// Allocates an `GcBox<T>` with the given layout.
992    ///
993    /// The function `mem_to_gc_box` is called with the data pointer
994    /// and must return back a pointer for the `GcBox<T>`.
995    unsafe fn allocate_for_layout_of_box(
996        layout: Layout,
997        mem_to_gc_box: impl FnOnce(*mut u8) -> *mut GcBox<T>,
998    ) -> *mut GcBox<T> {
999        // SAFETY: layout has non-zero size because of the `ref_count` field
1000        let ptr = unsafe { std::alloc::alloc(layout) };
1001
1002        if ptr.is_null() {
1003            handle_alloc_error(layout);
1004        }
1005
1006        let inner = mem_to_gc_box(ptr);
1007
1008        unsafe {
1009            (&raw mut (*inner).strong).write(AtomicUsize::new(1));
1010            (&raw mut (*inner).weak).write(AtomicUsize::new(0));
1011            (&raw mut (*inner).generation).write(AtomicUsize::new(0));
1012        }
1013
1014        inner
1015    }
1016}
1017
1018impl<T: Trace + Send + Sync> Gc<[T]> {
1019    /// Allocates an `GcBox<[T]>` with the given length.
1020    fn allocate_for_slice(len: usize) -> *mut GcBox<[T]> {
1021        unsafe {
1022            Self::allocate_for_layout(Layout::array::<T>(len).unwrap(), |mem| {
1023                ptr::slice_from_raw_parts_mut(mem.cast::<T>(), len) as *mut GcBox<[T]>
1024            })
1025        }
1026    }
1027}
1028
1029unsafe impl<V: Visitor, T: Trace + Send + Sync + ?Sized> TraceWith<V> for Gc<T> {
1030    fn accept(&self, visitor: &mut V) -> Result<(), ()> {
1031        visitor.visit_sync(self);
1032        Ok(())
1033    }
1034}
1035
1036impl<T: Trace + Send + Sync + ?Sized> Deref for Gc<T> {
1037    type Target = T;
1038
1039    /// Dereference this pointer, creating a reference to the contained value `T`.
1040    ///
1041    /// # Panics
1042    ///
1043    /// This function may panic if it is called from within the implementation of `std::ops::Drop`
1044    /// of its owning value, since returning such a reference could cause a use-after-free.
1045    /// It is not guaranteed to panic.
1046    ///
1047    /// # Examples
1048    ///
1049    /// The following is a correct time to dereference a `Gc`.
1050    ///
1051    /// ```
1052    /// use dumpster::sync::Gc;
1053    ///
1054    /// let my_gc = Gc::new(0u8);
1055    /// let my_ref: &u8 = &my_gc;
1056    /// ```
1057    ///
1058    /// Dereferencing a `Gc` while dropping is not correct.
1059    ///
1060    /// ```should_panic
1061    /// // This is wrong!
1062    /// use dumpster::{sync::Gc, Trace};
1063    /// use std::sync::Mutex;
1064    ///
1065    /// #[derive(Trace)]
1066    /// struct Bad {
1067    ///     s: String,
1068    ///     cycle: Mutex<Option<Gc<Bad>>>,
1069    /// }
1070    ///
1071    /// impl Drop for Bad {
1072    ///     fn drop(&mut self) {
1073    ///         println!("{}", self.cycle.lock().unwrap().as_ref().unwrap().s)
1074    ///     }
1075    /// }
1076    ///
1077    /// let foo = Gc::new(Bad {
1078    ///     s: "foo".to_string(),
1079    ///     cycle: Mutex::new(None),
1080    /// });
1081    /// ```
1082    fn deref(&self) -> &Self::Target {
1083        let box_ref = unsafe {
1084            self.ptr.get().expect(
1085            "Attempting to dereference Gc to already-deallocated object.\
1086            This is caused by accessing a Gc during a Drop implementation, likely implying a bug in your code."
1087        ).as_ref()
1088        };
1089        let current_tag = CURRENT_TAG.load(Ordering::Acquire);
1090        self.tag.store(current_tag, Ordering::Release);
1091        box_ref.generation.store(current_tag, Ordering::Release);
1092        &box_ref.value
1093    }
1094}
1095
1096impl<T> PartialEq<Gc<T>> for Gc<T>
1097where
1098    T: Trace + Send + Sync + ?Sized + PartialEq,
1099{
1100    /// Test for equality on two `Gc`s.
1101    ///
1102    /// Two `Gc`s are equal if their inner values are equal, even if they are stored in different
1103    /// allocations.
1104    /// Because `PartialEq` does not imply reflexivity, and there is no current path for trait
1105    /// specialization, this function does not do a "fast-path" check for reference equality.
1106    /// Therefore, if two `Gc`s point to the same allocation, the implementation of `eq` will still
1107    /// require a direct call to `eq` on the values.
1108    ///
1109    /// # Panics
1110    ///
1111    /// This function may panic if it is called from within the implementation of `std::ops::Drop`
1112    /// of its owning value, since returning such a reference could cause a use-after-free.
1113    /// It is not guaranteed to panic.
1114    /// Additionally, if this `Gc` is moved out of an allocation during a `Drop` implementation, it
1115    /// could later cause a panic.
1116    /// For further details, refer to the main documentation for `Gc`.
1117    ///
1118    /// ```
1119    /// use dumpster::sync::Gc;
1120    ///
1121    /// let gc = Gc::new(6);
1122    /// assert!(gc == Gc::new(6));
1123    /// ```
1124    fn eq(&self, other: &Gc<T>) -> bool {
1125        self.as_ref() == other.as_ref()
1126    }
1127}
1128
1129impl<T> Eq for Gc<T> where T: Trace + Send + Sync + ?Sized + PartialEq {}
1130
1131impl<T: Trace + Send + Sync + ?Sized> AsRef<T> for Gc<T> {
1132    fn as_ref(&self) -> &T {
1133        self
1134    }
1135}
1136
1137impl<T: Trace + Send + Sync + ?Sized> Borrow<T> for Gc<T> {
1138    fn borrow(&self) -> &T {
1139        self
1140    }
1141}
1142
1143impl<T: Trace + Send + Sync + Default> Default for Gc<T> {
1144    fn default() -> Self {
1145        Gc::new(T::default())
1146    }
1147}
1148
1149impl<T: Trace + Send + Sync + ?Sized> std::fmt::Pointer for Gc<T> {
1150    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1151        std::fmt::Pointer::fmt(&addr_of!(**self), f)
1152    }
1153}
1154
1155#[cfg(not(loom))]
1156#[cfg(feature = "coerce-unsized")]
1157impl<T, U> std::ops::CoerceUnsized<Gc<U>> for Gc<T>
1158where
1159    T: std::marker::Unsize<U> + Trace + Send + Sync + ?Sized,
1160    U: Trace + Send + Sync + ?Sized,
1161{
1162}
1163
1164impl<T: Trace + Send + Sync + ?Sized> Debug for Gc<T> {
1165    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1166        write!(
1167            f,
1168            "Gc({:?}, {})",
1169            self.ptr,
1170            self.tag.load(Ordering::Acquire)
1171        )
1172    }
1173}
1174
1175impl<T: Trace + Send + Sync> From<T> for Gc<T> {
1176    /// Converts a generic type `T` into an `Gc<T>`
1177    ///
1178    /// The conversion allocates on the heap and moves `t`
1179    /// from the stack into it.
1180    ///
1181    /// # Example
1182    /// ```rust
1183    /// # use dumpster::sync::Gc;
1184    /// let x = 5;
1185    /// let rc = Gc::new(5);
1186    ///
1187    /// assert_eq!(Gc::from(x), rc);
1188    /// ```
1189    fn from(value: T) -> Self {
1190        Gc::new(value)
1191    }
1192}
1193
1194impl<T: Trace + Send + Sync, const N: usize> From<[T; N]> for Gc<[T]> {
1195    /// Converts a [`[T; N]`](prim@array) into an `Gc<[T]>`.
1196    ///
1197    /// The conversion moves the array into a newly allocated `Gc`.
1198    ///
1199    /// # Example
1200    ///
1201    /// ```
1202    /// # use dumpster::sync::Gc;
1203    /// let original: [i32; 3] = [1, 2, 3];
1204    /// let shared: Gc<[i32]> = Gc::from(original);
1205    /// assert_eq!(&[1, 2, 3], &shared[..]);
1206    /// ```
1207    #[inline]
1208    fn from(v: [T; N]) -> Gc<[T]> {
1209        coerce_gc!(Gc::<[T; N]>::from(v))
1210    }
1211}
1212
1213impl<T: Trace + Send + Sync + Clone> From<&[T]> for Gc<[T]> {
1214    /// Allocates a garbage-collected slice and fills it by cloning `slice`'s items.
1215    ///
1216    /// # Example
1217    ///
1218    /// ```
1219    /// # use dumpster::sync::Gc;
1220    /// let original: &[i32] = &[1, 2, 3];
1221    /// let shared: Gc<[i32]> = Gc::from(original);
1222    /// assert_eq!(&[1, 2, 3], &shared[..]);
1223    /// ```
1224    #[inline]
1225    fn from(slice: &[T]) -> Gc<[T]> {
1226        // Panic guard while cloning T elements.
1227        // In the event of a panic, elements that have been written
1228        // into the new GcBox will be dropped, then the memory freed.
1229        struct Guard<T> {
1230            /// pointer to `GcBox` to deallocate on panic
1231            mem: *mut u8,
1232            /// layout of the `GcBox` to deallocate on panic
1233            layout: Layout,
1234            /// pointer to the `GcBox`'s value
1235            elems: *mut T,
1236            /// the number of elements cloned so far
1237            n_elems: usize,
1238        }
1239
1240        impl<T> Drop for Guard<T> {
1241            fn drop(&mut self) {
1242                unsafe {
1243                    let slice = slice::from_raw_parts_mut(self.elems, self.n_elems);
1244                    ptr::drop_in_place(slice);
1245
1246                    dealloc(self.mem, self.layout);
1247                }
1248            }
1249        }
1250
1251        unsafe {
1252            let value_layout = Layout::array::<T>(slice.len()).unwrap();
1253
1254            let layout = Layout::new::<GcBox<()>>()
1255                .extend(value_layout)
1256                .unwrap()
1257                .0
1258                .pad_to_align();
1259
1260            let ptr = Self::allocate_for_layout_of_box(layout, |mem| {
1261                ptr::slice_from_raw_parts_mut(mem.cast::<T>(), slice.len()) as *mut GcBox<[T]>
1262            });
1263
1264            // Pointer to first element
1265            let elems = (&raw mut (*ptr).value).cast::<T>();
1266
1267            let mut guard = Guard {
1268                mem: ptr.cast::<u8>(),
1269                layout,
1270                elems,
1271                n_elems: 0,
1272            };
1273
1274            for (i, item) in slice.iter().enumerate() {
1275                ptr::write(elems.add(i), item.clone());
1276                guard.n_elems += 1;
1277            }
1278
1279            // All clear. Forget the guard so it doesn't free the new GcBox.
1280            mem::forget(guard);
1281
1282            notify_created_gc();
1283
1284            Self {
1285                ptr: UCell::new(Nullable::from_ptr(ptr)),
1286                tag: AtomicUsize::new(0),
1287            }
1288        }
1289    }
1290}
1291
1292impl<T: Trace + Send + Sync + Clone> From<&mut [T]> for Gc<[T]> {
1293    /// Allocates a garbage-collected slice and fills it by cloning `v`'s items.
1294    ///
1295    /// # Example
1296    ///
1297    /// ```
1298    /// # use dumpster::sync::Gc;
1299    /// let mut original = [1, 2, 3];
1300    /// let original: &mut [i32] = &mut original;
1301    /// let shared: Gc<[i32]> = Gc::from(original);
1302    /// assert_eq!(&[1, 2, 3], &shared[..]);
1303    /// ```
1304    #[inline]
1305    fn from(value: &mut [T]) -> Self {
1306        Gc::from(&*value)
1307    }
1308}
1309
1310impl From<&str> for Gc<str> {
1311    /// Allocates a garbage-collected string slice and copies `v` into it.
1312    ///
1313    /// # Example
1314    ///
1315    /// ```
1316    /// # use dumpster::sync::Gc;
1317    /// let shared: Gc<str> = Gc::from("statue");
1318    /// assert_eq!("statue", &shared[..]);
1319    /// ```
1320    #[inline]
1321    fn from(v: &str) -> Self {
1322        let bytes = Gc::<[u8]>::from(v.as_bytes());
1323        let (ptr, tag) = Gc::into_ptr(bytes);
1324        unsafe { Gc::from_ptr(ptr as *const GcBox<str>, tag) }
1325    }
1326}
1327
1328impl From<&mut str> for Gc<str> {
1329    /// Allocates a garbage-collected string slice and copies `v` into it.
1330    ///
1331    /// # Example
1332    ///
1333    /// ```
1334    /// # use dumpster::sync::Gc;
1335    /// let mut original = String::from("statue");
1336    /// let original: &mut str = &mut original;
1337    /// let shared: Gc<str> = Gc::from(original);
1338    /// assert_eq!("statue", &shared[..]);
1339    /// ```
1340    #[inline]
1341    fn from(v: &mut str) -> Self {
1342        Gc::from(&*v)
1343    }
1344}
1345
1346impl From<Gc<str>> for Gc<[u8]> {
1347    /// Converts a garbage-collected string slice into a byte slice.
1348    ///
1349    /// # Example
1350    ///
1351    /// ```
1352    /// # use dumpster::sync::Gc;
1353    /// let string: Gc<str> = Gc::from("eggplant");
1354    /// let bytes: Gc<[u8]> = Gc::from(string);
1355    /// assert_eq!("eggplant".as_bytes(), bytes.as_ref());
1356    /// ```
1357    #[inline]
1358    fn from(value: Gc<str>) -> Self {
1359        let (ptr, tag) = Gc::into_ptr(value);
1360        unsafe { Gc::from_ptr(ptr as *const GcBox<[u8]>, tag) }
1361    }
1362}
1363
1364impl From<String> for Gc<str> {
1365    /// Allocates a garbage-collected string slice and copies `v` into it.
1366    ///
1367    /// # Example
1368    ///
1369    /// ```
1370    /// # use dumpster::sync::Gc;
1371    /// let original: String = "statue".to_owned();
1372    /// let shared: Gc<str> = Gc::from(original);
1373    /// assert_eq!("statue", &shared[..]);
1374    /// ```
1375    #[inline]
1376    fn from(value: String) -> Self {
1377        Self::from(&value[..])
1378    }
1379}
1380
1381impl<T: Trace + Send + Sync> From<Box<T>> for Gc<T> {
1382    /// Move a boxed object to a new, garbage collected, allocation.
1383    ///
1384    /// # Example
1385    ///
1386    /// ```
1387    /// # use dumpster::sync::Gc;
1388    /// let original: Box<i32> = Box::new(1);
1389    /// let shared: Gc<i32> = Gc::from(original);
1390    /// assert_eq!(1, *shared);
1391    /// ```
1392    #[inline]
1393    fn from(src: Box<T>) -> Self {
1394        unsafe {
1395            let layout = Layout::for_value(&*src);
1396            let gc_ptr = Gc::allocate_for_layout(layout, <*mut u8>::cast::<GcBox<T>>);
1397
1398            // Copy value as bytes
1399            ptr::copy_nonoverlapping(
1400                (&raw const *src).cast::<u8>(),
1401                (&raw mut (*gc_ptr).value).cast::<u8>(),
1402                layout.size(),
1403            );
1404
1405            // Free the allocation without dropping its contents
1406            let bptr = Box::into_raw(src);
1407            let src = Box::from_raw(bptr.cast::<mem::ManuallyDrop<T>>());
1408            drop(src);
1409
1410            notify_created_gc();
1411            Self::from_ptr(gc_ptr, 0)
1412        }
1413    }
1414}
1415
1416impl<T: Trace + Send + Sync> From<Vec<T>> for Gc<[T]> {
1417    /// Allocates a garbage-collected slice and moves `vec`'s items into it.
1418    ///
1419    /// # Example
1420    ///
1421    /// ```
1422    /// # use dumpster::sync::Gc;
1423    /// let unique: Vec<i32> = vec![1, 2, 3];
1424    /// let shared: Gc<[i32]> = Gc::from(unique);
1425    /// assert_eq!(&[1, 2, 3], &shared[..]);
1426    /// ```
1427    #[inline]
1428    fn from(vec: Vec<T>) -> Self {
1429        let mut vec = ManuallyDrop::new(vec);
1430        let vec_cap = vec.capacity();
1431        let vec_len = vec.len();
1432        let vec_ptr = vec.as_mut_ptr();
1433
1434        let gc_ptr = Self::allocate_for_slice(vec_len);
1435
1436        unsafe {
1437            let dst_ptr = (&raw mut (*gc_ptr).value).cast::<T>();
1438            ptr::copy_nonoverlapping(vec_ptr, dst_ptr, vec_len);
1439
1440            let _ = Vec::from_raw_parts(vec_ptr, 0, vec_cap);
1441
1442            notify_created_gc();
1443            Self::from_ptr(gc_ptr, 0)
1444        }
1445    }
1446}
1447
1448impl<'a, B: Trace + Send + Sync> From<Cow<'a, B>> for Gc<B>
1449where
1450    B: ToOwned + ?Sized,
1451    Gc<B>: From<&'a B> + From<B::Owned>,
1452{
1453    /// Creates a garbage-collected pointer from a clone-on-write pointer by
1454    /// copying its content.
1455    ///
1456    /// # Example
1457    ///
1458    /// ```rust
1459    /// # use dumpster::sync::Gc;
1460    /// # use std::borrow::Cow;
1461    /// let cow: Cow<'_, str> = Cow::Borrowed("eggplant");
1462    /// let shared: Gc<str> = Gc::from(cow);
1463    /// assert_eq!("eggplant", &shared[..]);
1464    /// ```
1465    #[inline]
1466    fn from(cow: Cow<'a, B>) -> Gc<B> {
1467        match cow {
1468            Cow::Borrowed(s) => Gc::from(s),
1469            Cow::Owned(s) => Gc::from(s),
1470        }
1471    }
1472}
1473
1474impl<T> FromIterator<T> for Gc<[T]>
1475where
1476    T: Trace + Send + Sync,
1477{
1478    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
1479        // Collect into a `Vec` for O(n) performance.
1480        // TODO: this could be slightly optimized by using the `Gc<[]>` layout for perf, but this is
1481        // a later problem.
1482        let mut t_vec = iter.into_iter().collect::<Vec<_>>();
1483        let n = t_vec.len();
1484        // if allocation fails, t_vec will be dropped
1485        let box_ptr = Gc::allocate_for_slice(n);
1486        let gc = unsafe {
1487            copy_nonoverlapping(t_vec.as_ptr(), (*box_ptr).value.as_mut_ptr(), n);
1488            t_vec.set_len(0); // forget old values
1489            Gc::from_ptr(box_ptr, CURRENT_TAG.load(Ordering::Acquire))
1490        };
1491
1492        notify_created_gc();
1493
1494        gc
1495    }
1496}