1use crate::{
2 Allocator, Ephemeron, GcErasedPointer, Tracer, WeakGc, custom_trace, finalizer_safe,
3 internals::{EphemeronBox, GcBox, VTable},
4 trace::{Finalize, Trace},
5};
6use std::{
7 any::TypeId,
8 cmp::Ordering,
9 fmt::{self, Debug, Display},
10 hash::{Hash, Hasher},
11 marker::PhantomData,
12 ops::Deref,
13 ptr::NonNull,
14 rc::Rc,
15};
16
17pub(crate) struct NonTraceable(());
25
26impl Finalize for NonTraceable {
27 fn finalize(&self) {
28 unreachable!()
29 }
30}
31
32unsafe impl Trace for NonTraceable {
33 unsafe fn trace(&self, _tracer: &mut Tracer) {
34 unreachable!()
35 }
36 unsafe fn trace_non_roots(&self) {
37 unreachable!()
38 }
39 fn run_finalizer(&self) {
40 unreachable!()
41 }
42}
43
44impl Drop for NonTraceable {
45 fn drop(&mut self) {
46 unreachable!()
47 }
48}
49
50#[repr(transparent)]
52pub struct GcErased {
53 inner: Gc<NonTraceable>,
54}
55
56impl GcErased {
57 #[inline]
59 #[must_use]
60 pub fn new<T: Trace>(gc: Gc<T>) -> Self {
61 let inner_ptr = gc.inner_ptr;
62 std::mem::forget(gc);
63
64 Self {
65 inner: Gc {
66 inner_ptr: inner_ptr.cast(),
67 marker: PhantomData,
68 },
69 }
70 }
71
72 #[must_use]
74 pub fn ptr_eq(this: &Self, other: &Self) -> bool {
75 Gc::ptr_eq(&this.inner, &other.inner)
76 }
77
78 #[inline]
80 #[must_use]
81 pub fn type_id(&self) -> TypeId {
82 Gc::type_id(&self.inner)
83 }
84
85 #[inline]
87 #[must_use]
88 pub fn is<T: Trace + 'static>(&self) -> bool {
89 Gc::is::<T>(&self.inner)
90 }
91
92 #[inline]
94 #[must_use]
95 pub fn downcast<T: Trace + 'static>(self) -> Option<Gc<T>> {
96 Gc::downcast::<T>(self.inner)
97 }
98
99 #[inline]
105 #[must_use]
106 pub unsafe fn downcast_unchecked<T: Trace + 'static>(self) -> Gc<T> {
107 unsafe { Gc::cast_unchecked::<T>(self.inner) }
109 }
110
111 #[inline]
117 #[must_use]
118 pub unsafe fn downcast_ref_unchecked<T: Trace + 'static>(&self) -> &Gc<T> {
119 unsafe { Gc::cast_ref_unchecked::<T>(&self.inner) }
121 }
122}
123
124impl Debug for GcErased {
125 #[inline]
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 f.debug_struct("GcErased")
128 .field("inner", &self.inner.inner_ptr)
129 .finish()
130 }
131}
132
133impl Finalize for GcErased {
134 fn finalize(&self) {}
135}
136
137unsafe impl Trace for GcErased {
140 custom_trace!(this, mark, {
141 mark(&this.inner);
142 });
143}
144
145impl Clone for GcErased {
146 #[inline]
147 fn clone(&self) -> Self {
148 Self {
149 inner: self.inner.clone(),
150 }
151 }
152}
153
154pub struct Gc<T: Trace + ?Sized + 'static> {
156 pub(crate) inner_ptr: NonNull<GcBox<T>>,
157 pub(crate) marker: PhantomData<Rc<T>>,
158}
159
160impl<T: Trace + ?Sized> Gc<T> {
161 #[must_use]
163 pub fn new(value: T) -> Self
164 where
165 T: Sized,
166 {
167 let inner_ptr = Allocator::alloc_gc(GcBox::new(value));
171
172 Self {
173 inner_ptr,
174 marker: PhantomData,
175 }
176 }
177
178 #[must_use]
185 pub fn new_cyclic<F>(data_fn: F) -> Self
186 where
187 F: FnOnce(&WeakGc<T>) -> T,
188 T: Sized,
189 {
190 let weak = unsafe {
193 Ephemeron::from_raw(Allocator::alloc_ephemeron(EphemeronBox::new_empty())).into()
194 };
195
196 let gc = Self::new(data_fn(&weak));
197
198 unsafe { weak.inner().inner_ptr().as_mut().set(&gc, ()) }
204
205 gc
206 }
207
208 #[must_use]
212 pub fn into_raw(this: Self) -> NonNull<GcBox<T>> {
213 let ptr = this.inner_ptr();
214 std::mem::forget(this);
215 ptr
216 }
217
218 #[must_use]
220 pub fn ptr_eq<U: Trace + ?Sized>(this: &Self, other: &Gc<U>) -> bool {
221 std::ptr::addr_eq(this.inner(), other.inner())
222 }
223
224 #[must_use]
234 pub const unsafe fn from_raw(inner_ptr: NonNull<GcBox<T>>) -> Self {
235 Self {
236 inner_ptr,
237 marker: PhantomData,
238 }
239 }
240
241 pub(crate) fn as_erased_pointer(&self) -> GcErasedPointer {
242 self.inner_ptr.cast()
243 }
244
245 #[inline]
247 #[must_use]
248 pub fn type_id(this: &Self) -> TypeId {
249 this.vtable().type_id()
250 }
251
252 #[inline]
254 #[must_use]
255 pub fn is<U: Trace + 'static>(this: &Self) -> bool {
256 Gc::type_id(this) == TypeId::of::<U>()
257 }
258
259 #[inline]
261 #[must_use]
262 pub fn downcast<U: Trace + 'static>(this: Self) -> Option<Gc<U>> {
263 if !Gc::is::<U>(&this) {
264 return None;
265 }
266
267 Some(unsafe { Gc::cast_unchecked::<U>(this) })
269 }
270
271 #[inline]
277 #[must_use]
278 pub unsafe fn cast_unchecked<U: Trace + 'static>(this: Self) -> Gc<U> {
279 let inner_ptr = this.inner_ptr.cast::<U>();
280 core::mem::forget(this); Gc {
282 inner_ptr: inner_ptr.cast(),
283 marker: PhantomData,
284 }
285 }
286
287 #[inline]
293 #[must_use]
294 pub unsafe fn cast_ref_unchecked<U: Trace + 'static>(this: &Self) -> &Gc<U> {
295 unsafe { &(*(&raw const *this).cast::<Gc<U>>()) }
298 }
299}
300
301impl<T: Trace + ?Sized> Gc<T> {
302 pub(crate) fn vtable(&self) -> &'static VTable {
303 unsafe { self.inner_ptr.as_ref() }.vtable
305 }
306
307 #[inline(always)]
308 #[allow(clippy::inline_always)]
309 pub(crate) fn inner_ptr(&self) -> NonNull<GcBox<T>> {
310 debug_assert!(finalizer_safe());
311 self.inner_ptr
312 }
313
314 fn inner(&self) -> &GcBox<T> {
315 unsafe { self.inner_ptr().as_ref() }
317 }
318}
319
320impl<T: Trace + ?Sized> Finalize for Gc<T> {
321 fn finalize(&self) {
322 unsafe {
325 self.inner_ptr.as_ref().dec_ref_count();
326 }
327 }
328}
329
330unsafe impl<T: Trace + ?Sized> Trace for Gc<T> {
333 unsafe fn trace(&self, tracer: &mut Tracer) {
334 tracer.enqueue(self.as_erased_pointer());
335 }
336
337 unsafe fn trace_non_roots(&self) {
338 self.inner().inc_non_root_count();
339 }
340
341 fn run_finalizer(&self) {
342 Finalize::finalize(self);
343 }
344}
345
346impl<T: Trace + ?Sized> Clone for Gc<T> {
347 fn clone(&self) -> Self {
348 let ptr = self.inner_ptr();
349 unsafe {
353 ptr.as_ref().inc_ref_count();
354 Self::from_raw(ptr)
355 }
356 }
357}
358
359impl<T: Trace + ?Sized> Deref for Gc<T> {
360 type Target = T;
361
362 fn deref(&self) -> &T {
363 self.inner().value()
364 }
365}
366
367impl<T: Trace + ?Sized> Drop for Gc<T> {
368 fn drop(&mut self) {
369 if finalizer_safe() {
370 Finalize::finalize(self);
371 }
372 }
373}
374
375impl<T: Trace + Default> Default for Gc<T> {
376 fn default() -> Self {
377 Self::new(Default::default())
378 }
379}
380
381#[allow(clippy::inline_always)]
382impl<T: Trace + ?Sized + PartialEq> PartialEq for Gc<T> {
383 #[inline(always)]
384 fn eq(&self, other: &Self) -> bool {
385 **self == **other
386 }
387}
388
389impl<T: Trace + ?Sized + Eq> Eq for Gc<T> {}
390
391#[allow(clippy::inline_always)]
392impl<T: Trace + ?Sized + PartialOrd> PartialOrd for Gc<T> {
393 #[inline(always)]
394 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
395 (**self).partial_cmp(&**other)
396 }
397
398 #[inline(always)]
399 fn lt(&self, other: &Self) -> bool {
400 **self < **other
401 }
402
403 #[inline(always)]
404 fn le(&self, other: &Self) -> bool {
405 **self <= **other
406 }
407
408 #[inline(always)]
409 fn gt(&self, other: &Self) -> bool {
410 **self > **other
411 }
412
413 #[inline(always)]
414 fn ge(&self, other: &Self) -> bool {
415 **self >= **other
416 }
417}
418
419impl<T: Trace + ?Sized + Ord> Ord for Gc<T> {
420 fn cmp(&self, other: &Self) -> Ordering {
421 (**self).cmp(&**other)
422 }
423}
424
425impl<T: Trace + ?Sized + Hash> Hash for Gc<T> {
426 fn hash<H: Hasher>(&self, state: &mut H) {
427 (**self).hash(state);
428 }
429}
430
431impl<T: Trace + ?Sized + Display> Display for Gc<T> {
432 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
433 Display::fmt(&**self, f)
434 }
435}
436
437impl<T: Trace + ?Sized + Debug> Debug for Gc<T> {
438 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
439 Debug::fmt(&**self, f)
440 }
441}
442
443impl<T: Trace + ?Sized> fmt::Pointer for Gc<T> {
444 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
445 fmt::Pointer::fmt(&self.inner(), f)
446 }
447}
448
449impl<T: Trace + ?Sized> std::borrow::Borrow<T> for Gc<T> {
450 fn borrow(&self) -> &T {
451 self
452 }
453}
454
455impl<T: Trace + ?Sized> AsRef<T> for Gc<T> {
456 fn as_ref(&self) -> &T {
457 self
458 }
459}