1use crate::{
2 Finalize,
3 lifetime::{Lifetime, LifetimeLazy, ValueReadAccess, ValueWriteAccess},
4 managed::{
5 DynamicManagedLazy, DynamicManagedRef, DynamicManagedRefMut, ManagedLazy, ManagedRef,
6 ManagedRefMut,
7 },
8 non_zero_alloc, non_zero_dealloc,
9 type_hash::TypeHash,
10};
11use std::{
12 alloc::{Layout, handle_alloc_error},
13 marker::PhantomData,
14 mem::MaybeUninit,
15};
16
17enum Kind<T> {
18 Owned {
19 lifetime: Lifetime,
20 data: *mut T,
21 },
22 Referenced {
23 lifetime: LifetimeLazy,
24 data: *mut T,
25 },
26}
27
28pub enum ManagedGcLifetime<'a> {
29 Owned(&'a Lifetime),
30 Referenced(&'a LifetimeLazy),
31}
32
33pub struct ManagedGc<T> {
34 dynamic: DynamicManagedGc,
35 _phantom: PhantomData<fn() -> T>,
36}
37
38unsafe impl<T> Send for ManagedGc<T> {}
39unsafe impl<T> Sync for ManagedGc<T> {}
40
41impl<T: Default> Default for ManagedGc<T> {
42 fn default() -> Self {
43 Self::new(T::default())
44 }
45}
46
47impl<T> ManagedGc<T> {
48 pub fn new(data: T) -> Self {
49 Self {
50 dynamic: DynamicManagedGc::new(data),
51 _phantom: PhantomData,
52 }
53 }
54
55 pub fn consume(self) -> Result<T, Self> {
56 self.dynamic.consume().map_err(|value| Self {
57 dynamic: value,
58 _phantom: PhantomData,
59 })
60 }
61
62 pub fn into_dynamic(self) -> DynamicManagedGc {
63 self.dynamic
64 }
65
66 pub fn renew(&mut self) {
67 self.dynamic.renew();
68 }
69
70 pub fn type_hash(&self) -> TypeHash {
71 self.dynamic.type_hash()
72 }
73
74 pub fn lifetime(&self) -> ManagedGcLifetime<'_> {
75 self.dynamic.lifetime()
76 }
77
78 pub fn exists(&self) -> bool {
79 self.dynamic.exists()
80 }
81
82 pub fn is_owning(&self) -> bool {
83 self.dynamic.is_owning()
84 }
85
86 pub fn is_referencing(&self) -> bool {
87 self.dynamic.is_referencing()
88 }
89
90 pub fn is_owned_by(&self, other: &Self) -> bool {
91 self.dynamic.is_owned_by(&other.dynamic)
92 }
93
94 pub fn read<const LOCKING: bool>(&'_ self) -> ValueReadAccess<'_, T> {
95 self.dynamic.read::<LOCKING, T>()
96 }
97
98 pub fn write<const LOCKING: bool>(&'_ mut self) -> ValueWriteAccess<'_, T> {
99 self.dynamic.write::<LOCKING, T>()
100 }
101
102 pub fn borrow<const LOCKING: bool>(&self) -> ManagedRef<T> {
103 self.dynamic
104 .borrow::<LOCKING>()
105 .into_typed()
106 .ok()
107 .expect("ManagedGc cannot be immutably borrowed")
108 }
109
110 pub fn borrow_mut<const LOCKING: bool>(&mut self) -> ManagedRefMut<T> {
111 self.dynamic
112 .borrow_mut::<LOCKING>()
113 .into_typed()
114 .ok()
115 .expect("ManagedGc cannot be mutably borrowed")
116 }
117
118 pub fn lazy(&self) -> ManagedLazy<T> {
119 self.dynamic
120 .lazy()
121 .into_typed()
122 .ok()
123 .expect("ManagedGc cannot be lazily borrowed")
124 }
125
126 pub unsafe fn as_ptr(&self) -> *const T {
128 unsafe { self.dynamic.as_ptr_raw().cast::<T>() }
129 }
130
131 pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
133 unsafe { self.dynamic.as_mut_ptr_raw().cast::<T>() }
134 }
135}
136
137impl<T> Clone for ManagedGc<T> {
138 fn clone(&self) -> Self {
139 Self {
140 dynamic: self.dynamic.clone(),
141 _phantom: PhantomData,
142 }
143 }
144}
145
146pub struct DynamicManagedGc {
147 type_hash: TypeHash,
148 kind: Kind<u8>,
149 layout: Layout,
150 finalizer: unsafe fn(*mut ()),
151 drop: bool,
152}
153
154unsafe impl Send for DynamicManagedGc {}
155unsafe impl Sync for DynamicManagedGc {}
156
157impl Drop for DynamicManagedGc {
158 fn drop(&mut self) {
159 if let Kind::Owned { data, .. } = self.kind
160 && self.drop
161 {
162 unsafe {
163 if data.is_null() {
164 return;
165 }
166 (self.finalizer)(data.cast::<()>());
167 non_zero_dealloc(data, self.layout);
168 }
169 }
170 }
171}
172
173impl DynamicManagedGc {
174 pub fn new<T: Finalize>(data: T) -> Self {
175 let layout = Layout::new::<T>().pad_to_align();
176 unsafe {
177 let memory = non_zero_alloc(layout) as *mut T;
178 if memory.is_null() {
179 handle_alloc_error(layout);
180 }
181 memory.cast::<T>().write(data);
182 Self {
183 type_hash: TypeHash::of::<T>(),
184 kind: Kind::Owned {
185 lifetime: Default::default(),
186 data: memory.cast::<u8>(),
187 },
188 layout,
189 finalizer: T::finalize_raw,
190 drop: true,
191 }
192 }
193 }
194
195 pub fn new_raw(
196 type_hash: TypeHash,
197 lifetime: Lifetime,
198 memory: *mut u8,
199 layout: Layout,
200 finalizer: unsafe fn(*mut ()),
201 ) -> Self {
202 if memory.is_null() {
203 handle_alloc_error(layout);
204 }
205 Self {
206 type_hash,
207 kind: Kind::Owned {
208 lifetime,
209 data: memory,
210 },
211 layout,
212 finalizer,
213 drop: true,
214 }
215 }
216
217 pub fn new_uninitialized(
218 type_hash: TypeHash,
219 layout: Layout,
220 finalizer: unsafe fn(*mut ()),
221 ) -> Self {
222 let memory = unsafe { non_zero_alloc(layout) };
223 if memory.is_null() {
224 handle_alloc_error(layout);
225 }
226 Self {
227 type_hash,
228 kind: Kind::Owned {
229 lifetime: Default::default(),
230 data: memory,
231 },
232 layout,
233 finalizer,
234 drop: true,
235 }
236 }
237
238 pub fn consume<T>(mut self) -> Result<T, Self> {
239 if let Kind::Owned { lifetime, data } = &mut self.kind {
240 if self.type_hash == TypeHash::of::<T>() && !lifetime.state().is_in_use() {
241 if data.is_null() {
242 return Err(self);
243 }
244 self.drop = false;
245 let mut result = MaybeUninit::<T>::uninit();
246 unsafe {
247 result.as_mut_ptr().copy_from(data.cast::<T>(), 1);
248 non_zero_dealloc(*data, self.layout);
249 Ok(result.assume_init())
250 }
251 } else {
252 Err(self)
253 }
254 } else {
255 Err(self)
256 }
257 }
258
259 pub fn into_typed<T>(self) -> ManagedGc<T> {
260 ManagedGc {
261 dynamic: self,
262 _phantom: PhantomData,
263 }
264 }
265
266 pub fn renew(&mut self) {
267 if let Kind::Owned { lifetime, .. } = &mut self.kind {
268 *lifetime = Default::default();
269 }
270 }
271
272 pub fn type_hash(&self) -> TypeHash {
273 self.type_hash
274 }
275
276 pub fn lifetime(&self) -> ManagedGcLifetime<'_> {
277 match &self.kind {
278 Kind::Owned { lifetime, .. } => ManagedGcLifetime::Owned(lifetime),
279 Kind::Referenced { lifetime, .. } => ManagedGcLifetime::Referenced(lifetime),
280 }
281 }
282
283 pub fn exists(&self) -> bool {
284 match &self.kind {
285 Kind::Owned { .. } => true,
286 Kind::Referenced { lifetime, .. } => lifetime.exists(),
287 }
288 }
289
290 pub fn is_owning(&self) -> bool {
291 matches!(self.kind, Kind::Owned { .. })
292 }
293
294 pub fn is_referencing(&self) -> bool {
295 matches!(self.kind, Kind::Referenced { .. })
296 }
297
298 pub fn is_owned_by(&self, other: &Self) -> bool {
299 if let (Kind::Referenced { lifetime: l1, .. }, Kind::Owned { lifetime: l2, .. }) =
300 (&self.kind, &other.kind)
301 {
302 l1.state().is_owned_by(l2.state())
303 } else {
304 false
305 }
306 }
307
308 pub fn is<T>(&self) -> bool {
309 self.type_hash == TypeHash::of::<T>()
310 }
311
312 pub fn read<const LOCKING: bool, T>(&'_ self) -> ValueReadAccess<'_, T> {
313 if !self.is::<T>() {
314 panic!("DynamicManagedGc is not of the requested type");
315 }
316 unsafe {
317 if LOCKING {
318 match &self.kind {
319 Kind::Owned { lifetime, data } => loop {
320 let data = data
321 .cast::<T>()
322 .as_ref()
323 .expect("DynamicManagedGc data pointer is null");
324 if let Some(access) = lifetime.read(data) {
325 return access;
326 }
327 std::hint::spin_loop();
328 },
329 Kind::Referenced { lifetime, data } => loop {
330 let data = data
331 .cast::<T>()
332 .as_ref()
333 .expect("DynamicManagedGc data pointer is null");
334 if let Some(access) = lifetime.read(data) {
335 return access;
336 }
337 std::hint::spin_loop();
338 },
339 }
340 } else {
341 match &self.kind {
342 Kind::Owned { lifetime, data } => {
343 let data = data
344 .cast::<T>()
345 .as_ref()
346 .expect("DynamicManagedGc data pointer is null");
347 lifetime
348 .read(data)
349 .expect("DynamicManagedGc is inaccessible for reading")
350 }
351 Kind::Referenced { lifetime, data } => {
352 let data = data
353 .cast::<T>()
354 .as_ref()
355 .expect("DynamicManagedGc data pointer is null");
356 lifetime
357 .read(data)
358 .expect("DynamicManagedGc is inaccessible for reading")
359 }
360 }
361 }
362 }
363 }
364
365 pub fn write<const LOCKING: bool, T>(&'_ mut self) -> ValueWriteAccess<'_, T> {
366 if !self.is::<T>() {
367 panic!("DynamicManagedGc is not of the requested type");
368 }
369 unsafe {
370 if LOCKING {
371 match &self.kind {
372 Kind::Owned { lifetime, data } => loop {
373 let data = data
374 .cast::<T>()
375 .as_mut()
376 .expect("DynamicManagedGc data pointer is null");
377 if let Some(access) = lifetime.write(data) {
378 return access;
379 }
380 std::hint::spin_loop();
381 },
382 Kind::Referenced { lifetime, data } => loop {
383 let data = data
384 .cast::<T>()
385 .as_mut()
386 .expect("DynamicManagedGc data pointer is null");
387 if let Some(access) = lifetime.write(data) {
388 return access;
389 }
390 std::hint::spin_loop();
391 },
392 }
393 } else {
394 match &self.kind {
395 Kind::Owned { lifetime, data } => {
396 let data = data
397 .cast::<T>()
398 .as_mut()
399 .expect("DynamicManagedGc data pointer is null");
400 lifetime
401 .write(data)
402 .expect("DynamicManagedGc is inaccessible for writing")
403 }
404 Kind::Referenced { lifetime, data } => {
405 let data = data
406 .cast::<T>()
407 .as_mut()
408 .expect("DynamicManagedGc data pointer is null");
409 lifetime
410 .write(data)
411 .expect("DynamicManagedGc is inaccessible for writing")
412 }
413 }
414 }
415 }
416 }
417
418 pub fn borrow<const LOCKING: bool>(&self) -> DynamicManagedRef {
419 unsafe {
420 if LOCKING {
421 match &self.kind {
422 Kind::Owned { lifetime, data } => loop {
423 if let Some(lifetime) = lifetime.borrow() {
424 return DynamicManagedRef::new_raw(self.type_hash, lifetime, *data)
425 .expect("DynamicManagedGc cannot be immutably borrowed");
426 }
427 std::hint::spin_loop();
428 },
429 Kind::Referenced { lifetime, data } => loop {
430 if let Some(lifetime) = lifetime.borrow() {
431 return DynamicManagedRef::new_raw(self.type_hash, lifetime, *data)
432 .expect("DynamicManagedGc cannot be immutably borrowed");
433 }
434 std::hint::spin_loop();
435 },
436 }
437 } else {
438 match &self.kind {
439 Kind::Owned { lifetime, data } => DynamicManagedRef::new_raw(
440 self.type_hash,
441 lifetime
442 .borrow()
443 .expect("DynamicManagedGc is inaccessible for immutable borrowing"),
444 *data,
445 )
446 .expect("DynamicManagedGc cannot be immutably borrowed"),
447 Kind::Referenced { lifetime, data } => DynamicManagedRef::new_raw(
448 self.type_hash,
449 lifetime
450 .borrow()
451 .expect("DynamicManagedGc is inaccessible for immutable borrowing"),
452 *data,
453 )
454 .expect("DynamicManagedGc cannot be immutably borrowed"),
455 }
456 }
457 }
458 }
459
460 pub fn borrow_mut<const LOCKING: bool>(&mut self) -> DynamicManagedRefMut {
461 unsafe {
462 if LOCKING {
463 match &self.kind {
464 Kind::Owned { lifetime, data } => loop {
465 if let Some(lifetime) = lifetime.borrow_mut() {
466 return DynamicManagedRefMut::new_raw(self.type_hash, lifetime, *data)
467 .expect("DynamicManagedGc cannot be mutably borrowed");
468 }
469 std::hint::spin_loop();
470 },
471 Kind::Referenced { lifetime, data } => loop {
472 if let Some(lifetime) = lifetime.borrow_mut() {
473 return DynamicManagedRefMut::new_raw(self.type_hash, lifetime, *data)
474 .expect("DynamicManagedGc cannot be mutably borrowed");
475 }
476 std::hint::spin_loop();
477 },
478 }
479 } else {
480 match &self.kind {
481 Kind::Owned { lifetime, data } => DynamicManagedRefMut::new_raw(
482 self.type_hash,
483 lifetime
484 .borrow_mut()
485 .expect("DynamicManagedGc is inaccessible for mutable borrowing"),
486 *data,
487 )
488 .expect("DynamicManagedGc cannot be mutably borrowed"),
489 Kind::Referenced { lifetime, data } => DynamicManagedRefMut::new_raw(
490 self.type_hash,
491 lifetime
492 .borrow_mut()
493 .expect("DynamicManagedGc is inaccessible for mutable borrowing"),
494 *data,
495 )
496 .expect("DynamicManagedGc cannot be mutably borrowed"),
497 }
498 }
499 }
500 }
501
502 pub fn lazy(&self) -> DynamicManagedLazy {
503 unsafe {
504 match &self.kind {
505 Kind::Owned { lifetime, data } => {
506 DynamicManagedLazy::new_raw(self.type_hash, lifetime.lazy(), *data)
507 .expect("DynamicManagedGc cannot be lazily borrowed")
508 }
509 Kind::Referenced { lifetime, data } => {
510 DynamicManagedLazy::new_raw(self.type_hash, lifetime.clone(), *data)
511 .expect("DynamicManagedGc cannot be lazily borrowed")
512 }
513 }
514 }
515 }
516
517 pub unsafe fn as_ptr_raw(&self) -> *const u8 {
519 match &self.kind {
520 Kind::Owned { data, .. } => *data as *const u8,
521 Kind::Referenced { data, .. } => *data as *const u8,
522 }
523 }
524
525 pub unsafe fn as_mut_ptr_raw(&mut self) -> *mut u8 {
527 match &self.kind {
528 Kind::Owned { data, .. } => *data,
529 Kind::Referenced { data, .. } => *data,
530 }
531 }
532}
533
534impl Clone for DynamicManagedGc {
535 fn clone(&self) -> Self {
536 match &self.kind {
537 Kind::Owned { lifetime, data } => Self {
538 type_hash: self.type_hash,
539 kind: Kind::Referenced {
540 lifetime: lifetime.lazy(),
541 data: *data,
542 },
543 layout: self.layout,
544 finalizer: self.finalizer,
545 drop: true,
546 },
547 Kind::Referenced { lifetime, data } => Self {
548 type_hash: self.type_hash,
549 kind: Kind::Referenced {
550 lifetime: lifetime.clone(),
551 data: *data,
552 },
553 layout: self.layout,
554 finalizer: self.finalizer,
555 drop: true,
556 },
557 }
558 }
559}
560
561#[cfg(test)]
562mod tests {
563 use super::*;
564
565 #[test]
566 fn test_is_async() {
567 fn is_async<T: Send + Sync>() {}
568
569 is_async::<ManagedGc<()>>();
570 is_async::<DynamicManagedGc>();
571 }
572
573 #[test]
574 fn test_managed_gc() {
575 let mut managed = ManagedGc::new(42);
576 {
577 let read_access = managed.read::<true>();
578 assert_eq!(*read_access, 42);
579 }
580 {
581 let mut write_access = managed.write::<true>();
582 *write_access = 100;
583 }
584 {
585 let read_access = managed.read::<true>();
586 assert_eq!(*read_access, 100);
587 }
588 }
589
590 #[test]
591 fn test_managed_gc_cycles() {
592 #[derive(Default)]
593 struct Foo {
594 other: Option<ManagedGc<Self>>,
595 }
596
597 {
598 let mut a = ManagedGc::<Foo>::default();
599 let mut b = ManagedGc::<Foo>::default();
600 a.write::<true>().other = Some(b.clone());
601 b.write::<true>().other = Some(a.clone());
602
603 assert!(a.exists());
604 assert!(a.is_owning());
605 assert!(a.read::<true>().other.as_ref().unwrap().is_referencing());
606 assert!(a.read::<true>().other.as_ref().unwrap().is_owned_by(&b));
607
608 assert!(b.exists());
609 assert!(b.is_owning());
610 assert!(b.read::<true>().other.as_ref().unwrap().is_referencing());
611 assert!(b.read::<true>().other.as_ref().unwrap().is_owned_by(&a));
612
613 drop(b);
614 assert!(!a.read::<true>().other.as_ref().unwrap().exists());
615 }
616
617 {
618 let mut a = ManagedGc::<Foo>::default();
619 a.write::<true>().other = Some(a.clone());
620
621 assert!(a.exists());
622 assert!(a.is_owning());
623 assert!(a.read::<true>().other.as_ref().unwrap().is_referencing());
624 assert!(a.read::<true>().other.as_ref().unwrap().is_owned_by(&a));
625 }
626 }
627
628 #[test]
629 fn test_dynamic_managed_gc() {
630 let mut managed = DynamicManagedGc::new(42);
631 {
632 let read_access = managed.read::<true, i32>();
633 assert_eq!(*read_access, 42);
634 }
635 {
636 let mut write_access = managed.write::<true, i32>();
637 *write_access = 100;
638 }
639 {
640 let read_access = managed.read::<true, i32>();
641 assert_eq!(*read_access, 100);
642 }
643 }
644
645 #[test]
646 fn test_dynamic_managed_gc_cycles() {
647 #[derive(Default)]
648 struct Foo {
649 other: Option<DynamicManagedGc>,
650 }
651
652 {
653 let mut a = DynamicManagedGc::new(Foo::default());
654 let mut b = DynamicManagedGc::new(Foo::default());
655 a.write::<true, Foo>().other = Some(b.clone());
656 b.write::<true, Foo>().other = Some(a.clone());
657
658 assert!(a.exists());
659 assert!(a.is_owning());
660 assert!(
661 a.read::<true, Foo>()
662 .other
663 .as_ref()
664 .unwrap()
665 .is_referencing()
666 );
667 assert!(
668 a.read::<true, Foo>()
669 .other
670 .as_ref()
671 .unwrap()
672 .is_owned_by(&b)
673 );
674
675 assert!(b.exists());
676 assert!(b.is_owning());
677 assert!(
678 b.read::<true, Foo>()
679 .other
680 .as_ref()
681 .unwrap()
682 .is_referencing()
683 );
684 assert!(
685 b.read::<true, Foo>()
686 .other
687 .as_ref()
688 .unwrap()
689 .is_owned_by(&a)
690 );
691
692 drop(b);
693 assert!(!a.read::<true, Foo>().other.as_ref().unwrap().exists());
694 }
695
696 {
697 let mut a = DynamicManagedGc::new(Foo::default());
698 a.write::<true, Foo>().other = Some(a.clone());
699
700 assert!(a.exists());
701 assert!(a.is_owning());
702 assert!(
703 a.read::<true, Foo>()
704 .other
705 .as_ref()
706 .unwrap()
707 .is_referencing()
708 );
709 assert!(
710 a.read::<true, Foo>()
711 .other
712 .as_ref()
713 .unwrap()
714 .is_owned_by(&a)
715 );
716 }
717 }
718
719 #[test]
720 fn test_gc_conversions() {
721 let managed = ManagedGc::new(42);
722 assert_eq!(*managed.read::<true>(), 42);
723
724 let mut dynamic = managed.into_dynamic();
725 *dynamic.write::<true, i32>() = 100;
726
727 let managed = dynamic.into_typed::<i32>();
728 assert_eq!(*managed.read::<true>(), 100);
729 }
730}