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> Gc<T> {
321 #[inline]
331 pub unsafe fn release_outside_collection(this: Self) {
332 let this = std::mem::ManuallyDrop::new(this);
333 unsafe { this.inner_ptr.as_ref().dec_ref_count() };
335 }
336}
337
338impl<T: Trace + ?Sized> Finalize for Gc<T> {
339 fn finalize(&self) {
340 unsafe {
343 self.inner_ptr.as_ref().dec_ref_count();
344 }
345 }
346}
347
348unsafe impl<T: Trace + ?Sized> Trace for Gc<T> {
351 unsafe fn trace(&self, tracer: &mut Tracer) {
352 tracer.enqueue(self.as_erased_pointer());
353 }
354
355 unsafe fn trace_non_roots(&self) {
356 self.inner().inc_non_root_count();
357 }
358
359 fn run_finalizer(&self) {
360 Finalize::finalize(self);
361 }
362}
363
364impl<T: Trace + ?Sized> Clone for Gc<T> {
365 fn clone(&self) -> Self {
366 let ptr = self.inner_ptr();
367 unsafe {
371 ptr.as_ref().inc_ref_count();
372 Self::from_raw(ptr)
373 }
374 }
375}
376
377impl<T: Trace + ?Sized> Deref for Gc<T> {
378 type Target = T;
379
380 fn deref(&self) -> &T {
381 self.inner().value()
382 }
383}
384
385impl<T: Trace + ?Sized> Drop for Gc<T> {
386 fn drop(&mut self) {
387 if finalizer_safe() {
388 Finalize::finalize(self);
389 }
390 }
391}
392
393impl<T: Trace + Default> Default for Gc<T> {
394 fn default() -> Self {
395 Self::new(Default::default())
396 }
397}
398
399#[allow(clippy::inline_always)]
400impl<T: Trace + ?Sized + PartialEq> PartialEq for Gc<T> {
401 #[inline(always)]
402 fn eq(&self, other: &Self) -> bool {
403 **self == **other
404 }
405}
406
407impl<T: Trace + ?Sized + Eq> Eq for Gc<T> {}
408
409#[allow(clippy::inline_always)]
410impl<T: Trace + ?Sized + PartialOrd> PartialOrd for Gc<T> {
411 #[inline(always)]
412 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
413 (**self).partial_cmp(&**other)
414 }
415
416 #[inline(always)]
417 fn lt(&self, other: &Self) -> bool {
418 **self < **other
419 }
420
421 #[inline(always)]
422 fn le(&self, other: &Self) -> bool {
423 **self <= **other
424 }
425
426 #[inline(always)]
427 fn gt(&self, other: &Self) -> bool {
428 **self > **other
429 }
430
431 #[inline(always)]
432 fn ge(&self, other: &Self) -> bool {
433 **self >= **other
434 }
435}
436
437impl<T: Trace + ?Sized + Ord> Ord for Gc<T> {
438 fn cmp(&self, other: &Self) -> Ordering {
439 (**self).cmp(&**other)
440 }
441}
442
443impl<T: Trace + ?Sized + Hash> Hash for Gc<T> {
444 fn hash<H: Hasher>(&self, state: &mut H) {
445 (**self).hash(state);
446 }
447}
448
449impl<T: Trace + ?Sized + Display> Display for Gc<T> {
450 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
451 Display::fmt(&**self, f)
452 }
453}
454
455impl<T: Trace + ?Sized + Debug> Debug for Gc<T> {
456 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
457 Debug::fmt(&**self, f)
458 }
459}
460
461impl<T: Trace + ?Sized> fmt::Pointer for Gc<T> {
462 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
463 fmt::Pointer::fmt(&self.inner(), f)
464 }
465}
466
467impl<T: Trace + ?Sized> std::borrow::Borrow<T> for Gc<T> {
468 fn borrow(&self) -> &T {
469 self
470 }
471}
472
473impl<T: Trace + ?Sized> AsRef<T> for Gc<T> {
474 fn as_ref(&self) -> &T {
475 self
476 }
477}