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