ghost_gc/
unique_gc.rs

1use core::{
2    alloc::Layout,
3    mem::MaybeUninit,
4    ops::{Deref, DerefMut},
5    ptr::Pointee,
6};
7use std::fmt::Debug;
8
9use crate::{context::Mutation, gc::Gc, gc_box::GcBox, Collect, Invariant};
10
11/// A thin, garbage collected pointer type, which is guaranteed to be unique.
12pub struct UniqueGc<'b, T: ?Sized>(GcBox<T>, Invariant<'b>);
13
14impl<'b, T> UniqueGc<'b, T> {
15    /// Allocates garbage collected memory on the heap and then places `val`
16    /// into it.
17    ///
18    /// This allocates regardless of if `T` is zero-sized.
19    ///
20    /// # Examples
21    /// ```
22    /// # use ghost_gc::{once_arena, UniqueGc};
23    /// # once_arena(|mt| {
24    /// let five = UniqueGc::new(5, mt);
25    /// # });
26    /// ```
27    pub fn new(val: T, mt: &Mutation<'b>) -> UniqueGc<'b, T>
28    where
29        T: Collect,
30    {
31        let inner = mt.allocate::<T>((), Layout::new::<T>());
32        // .context()
33        // .allocate::<T>((), Layout::new::<T>(), mt.alloc());
34        // Safety: No references exist, as the pointer was just created.
35        unsafe { inner.data_ptr().write(val) };
36        // Safety: The value was just written.
37        unsafe { inner.set_init() };
38
39        UniqueGc(inner, Invariant)
40    }
41
42    /// Constructs a new garbage collected pointer with uninitialized contents.
43    ///
44    /// # Examples
45    /// ```
46    /// # use ghost_gc::{once_arena, UniqueGc};
47    /// # once_arena(|mt| {
48    /// let mut five = UniqueGc::<u32>::new_uninit(mt);
49    ///
50    /// let five = unsafe {
51    ///     five.as_mut_ptr().write(5);
52    ///
53    ///     five.assume_init()
54    /// };
55    ///
56    /// assert_eq!(*five, 5);
57    /// # });
58    /// ```
59    pub fn new_uninit(mt: &Mutation<'b>) -> UniqueGc<'b, MaybeUninit<T>> {
60        UniqueGc::new(MaybeUninit::uninit(), mt)
61    }
62
63    /// Constructs a new garbage collected pointer with uninitialized contents,
64    /// with the memory being filled with `0` bytes.
65    ///
66    /// See [`MaybeUninit::zeroed`] for examples of correct and incorrect usage
67    /// of this method.
68    ///
69    /// # Examples
70    /// ```
71    /// # use ghost_gc::{once_arena, UniqueGc};
72    /// # once_arena(|mt| {
73    /// let zero = UniqueGc::<u32>::new_zeroed(mt);
74    /// let zero = unsafe { zero.assume_init() };
75    ///
76    /// assert_eq!(*zero, 0);
77    /// # });
78    /// ```
79    pub fn new_zeroed(mt: &Mutation<'b>) -> UniqueGc<'b, MaybeUninit<T>> {
80        UniqueGc::new(MaybeUninit::zeroed(), mt)
81    }
82}
83
84impl<'b, T> UniqueGc<'b, [T]> {
85    /// Constructs a new garbage collected slice with uninitialized contents.
86    ///
87    /// # Examples
88    /// ```
89    /// # use ghost_gc::{once_arena, UniqueGc};
90    /// # once_arena(|mt| {
91    /// let mut values = UniqueGc::<[u32]>::new_uninit_slice(3, mt);
92    ///
93    /// let values = unsafe {
94    ///     values[0].as_mut_ptr().write(1);
95    ///     values[1].as_mut_ptr().write(2);
96    ///     values[2].as_mut_ptr().write(3);
97    ///
98    ///     values.assume_init()
99    /// };
100    ///
101    /// assert_eq!(*values, [1, 2, 3]);
102    /// # });
103    /// ```
104    pub fn new_uninit_slice(len: usize, mt: &Mutation<'b>) -> UniqueGc<'b, [MaybeUninit<T>]> {
105        let inner = mt
106            .context()
107            .allocate::<[MaybeUninit<T>]>(len, Layout::array::<T>(len).unwrap());
108
109        unsafe { inner.set_init() };
110
111        UniqueGc(inner, Invariant)
112    }
113
114    /// Constructs a new garbage collected slice with uninitialized contents, with the memory being
115    /// filled with `0` bytes.
116    ///
117    /// See [`MaybeUninit::zeroed`] for examples of correct and incorrect usage of this method.
118    ///
119    /// # Examples
120    /// ```
121    /// # use ghost_gc::{once_arena, UniqueGc};
122    /// # once_arena(|mt| {
123    /// let values = UniqueGc::<[u32]>::new_zeroed_slice(3, mt);
124    /// let values = unsafe { values.assume_init() };
125    ///
126    /// assert_eq!(*values, [0, 0, 0]);
127    /// # });
128    /// ```
129    pub fn new_zeroed_slice(len: usize, mt: &Mutation<'b>) -> UniqueGc<'b, [MaybeUninit<T>]> {
130        let inner = mt
131            .context()
132            .allocate::<[MaybeUninit<T>]>(len, Layout::array::<T>(len).unwrap());
133
134        unsafe { core::ptr::write_bytes(inner.data_ptr().cast::<T>(), 0, len) };
135
136        unsafe { inner.set_init() };
137
138        UniqueGc(inner, Invariant)
139    }
140}
141
142impl<'b> UniqueGc<'b, str> {
143    /// Constructs a new garbage collected string, copied from the passed value.
144    ///
145    /// ```
146    /// # use ghost_gc::{once_arena, UniqueGc};
147    /// # once_arena(|mt| {
148    /// let s = UniqueGc::from_str("Hello, World!", mt);
149    /// assert_eq!(&*s, "Hello, World!");
150    /// # });
151    /// ```
152    pub fn from_str(s: &str, mt: &Mutation<'b>) -> UniqueGc<'b, str> {
153        let mut gc = UniqueGc::<[u8]>::new_uninit_slice(s.len(), mt);
154
155        unsafe { std::ptr::copy_nonoverlapping(s.as_ptr(), gc.as_mut_ptr().cast(), s.len()) };
156
157        unsafe { gc.transmute() }
158    }
159}
160
161impl<'b, T: Collect> UniqueGc<'b, MaybeUninit<T>> {
162    /// Converts to `UniqueGc<'b, T>`.
163    ///
164    /// # Safety
165    /// As with [`MaybeUninit::assume_init`], it is up to the caller to
166    /// guarantee that the value really is in an initialized state. Calling
167    /// this when the content is not yet fully initialized causes immediate
168    /// undefined behaviour.
169    ///
170    /// # Examples
171    /// ```
172    /// # use ghost_gc::{once_arena, UniqueGc};
173    /// # once_arena(|mt| {
174    /// let mut five = UniqueGc::<u32>::new_uninit(mt);
175    ///
176    /// let five = unsafe {
177    ///     five.as_mut_ptr().write(5);
178    ///
179    ///     five.assume_init()
180    /// };
181    ///
182    /// assert_eq!(*five, 5);
183    /// # });
184    /// ```
185    pub unsafe fn assume_init(self) -> UniqueGc<'b, T> {
186        unsafe { self.transmute() }
187    }
188
189    /// Writes the value and converts to `UniqueGc<'b, T>`.
190    ///
191    /// This method converts the pointer similarly to [`UniqueGc::assume_init`],
192    /// but writes `value` into it before the conversion, thus guaranteeing safety.
193    /// In some scenarios use of this method may improve performance because the
194    /// compiler may be able to optimize copying from stack.
195    pub fn write(mut self, value: T) -> UniqueGc<'b, T> {
196        (*self).write(value);
197        unsafe { self.assume_init() }
198    }
199}
200
201impl<'b, T: Collect> UniqueGc<'b, [MaybeUninit<T>]> {
202    /// Converts to `Gc<'b, [T]>`.
203    ///
204    /// # Safety
205    /// As with [`MaybeUninit::assume_init`], it is up to the caller to guarantee that the values
206    /// really are in an initialized state. Calling this when the content is not yet fully
207    /// initialized causes immediate undefined behaviour.
208    ///
209    /// # Examples
210    /// ```
211    /// # use ghost_gc::{once_arena, UniqueGc};
212    /// # once_arena(|mt| {
213    /// let mut values = UniqueGc::<[u32]>::new_uninit_slice(3, mt);
214    ///
215    /// let values = unsafe {
216    ///     values[0].as_mut_ptr().write(1);
217    ///     values[1].as_mut_ptr().write(2);
218    ///     values[2].as_mut_ptr().write(3);
219    ///
220    ///     values.assume_init()
221    /// };
222    ///
223    /// assert_eq!(*values, [1, 2, 3]);
224    /// # });
225    /// ```
226    pub unsafe fn assume_init(self) -> UniqueGc<'b, [T]> {
227        unsafe { self.transmute::<[T]>() }
228    }
229}
230
231impl<'b, T: ?Sized> UniqueGc<'b, T> {
232    /// Converts the `UniqueGc` into a regular [`Gc`].
233    ///
234    /// This consumes the `UniqueGc` and returns a regular [`Gc`] which points to the same data
235    /// as the `UniqueGc`.
236    ///
237    /// # Examples
238    /// ```
239    /// # use ghost_gc::{once_arena, UniqueGc, Gc};
240    /// # once_arena(|mt| {
241    /// let gc: Gc<u32> = UniqueGc::into_gc(UniqueGc::new(5, mt));
242    /// # });
243    /// ```
244    pub fn into_gc(this: Self) -> Gc<'b, T> {
245        unsafe { Gc::from_box(this.0) }
246    }
247
248    pub fn as_ptr(&self) -> *const T {
249        self.0.data_ptr()
250    }
251
252    pub fn as_ptr_mut(&mut self) -> *mut T {
253        self.0.data_ptr()
254    }
255
256    // /// Consumes the `UniqueGc`, returning a raw pointer.
257    // ///
258    // /// The resultant pointer is only guaranteed to point to an allocation for the remainder of
259    // /// [`Arena::view`] closure.
260    // pub(crate) fn into_box(self) -> GcBox<T> {
261    //     self.0
262    // }
263
264    // /// Constructs a `UniqueGc` from a raw pointer.
265    // ///
266    // /// # Safety
267    // /// The pointer must have come from a previous call to [`UniqueGc::into_raw`].
268    // pub(crate) unsafe fn from_box(ptr: GcBox<T>) -> UniqueGc<'b, T> {
269    //     UniqueGc(ptr, PhantomData)
270    // }
271
272    /// # Safety
273    /// Layouts have to match, pointed to data has to match.
274    pub(crate) unsafe fn transmute<U: ?Sized + Collect>(self) -> UniqueGc<'b, U> {
275        debug_assert_eq!(
276            Layout::new::<<T as Pointee>::Metadata>(),
277            Layout::new::<<U as Pointee>::Metadata>(),
278        );
279
280        UniqueGc::<'b, U>(unsafe { self.0.transmute::<U>() }, Invariant)
281    }
282}
283
284impl<T: ?Sized> Deref for UniqueGc<'_, T> {
285    type Target = T;
286
287    fn deref(&self) -> &Self::Target {
288        unsafe { self.0.data() }
289    }
290}
291
292impl<T: ?Sized> DerefMut for UniqueGc<'_, T> {
293    fn deref_mut(&mut self) -> &mut Self::Target {
294        unsafe { self.0.data_mut() }
295    }
296}
297
298unsafe impl<T: ?Sized> Collect for UniqueGc<'_, T> {
299    const NEEDS_TRACE: bool = true;
300
301    fn trace(&self, c: &crate::Collector) {
302        use crate::gc_box::Colour;
303
304        match self.0.colour() {
305            Colour::Gray | Colour::White | Colour::Weak => {
306                unsafe { self.0.set_colour(Colour::Gray) };
307
308                c.context().push_box(self.0.erase());
309            }
310            Colour::Black => {}
311        }
312    }
313}
314
315impl<T: ?Sized + Debug> Debug for UniqueGc<'_, T> {
316    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
317        (**self).fmt(f)
318    }
319}
320
321impl<T: ?Sized + PartialEq> PartialEq for UniqueGc<'_, T> {
322    fn eq(&self, other: &Self) -> bool {
323        (**self) == (**other)
324    }
325}
326
327impl<T: ?Sized + Eq> Eq for UniqueGc<'_, T> {}
328
329impl<T: ?Sized + PartialOrd> PartialOrd for UniqueGc<'_, T> {
330    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
331        (**self).partial_cmp(other)
332    }
333}
334
335impl<T: ?Sized + Ord> Ord for UniqueGc<'_, T> {
336    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
337        (**self).cmp(other)
338    }
339}
340
341impl<T: ?Sized + std::hash::Hash> std::hash::Hash for UniqueGc<'_, T> {
342    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
343        (**self).hash(state);
344    }
345}