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 {
18 Owned {
19 lifetime: Box<Lifetime>,
20 data: *mut u8,
21 },
22 Referenced {
23 lifetime: LifetimeLazy,
24 data: *mut u8,
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 unsafe fn new_cyclic(f: impl FnOnce(Self) -> T) -> Self {
57 Self {
58 dynamic: unsafe { DynamicManagedGc::new_cyclic(|dynamic| f(dynamic.into_typed())) },
59 _phantom: PhantomData,
60 }
61 }
62
63 pub fn reference(&self) -> Self {
64 Self {
65 dynamic: self.dynamic.reference(),
66 _phantom: PhantomData,
67 }
68 }
69
70 pub fn consume(self) -> Result<T, Self> {
71 self.dynamic.consume().map_err(|value| Self {
72 dynamic: value,
73 _phantom: PhantomData,
74 })
75 }
76
77 pub fn into_dynamic(self) -> DynamicManagedGc {
78 self.dynamic
79 }
80
81 pub fn renew(&mut self) {
82 self.dynamic.renew();
83 }
84
85 pub fn type_hash(&self) -> TypeHash {
86 self.dynamic.type_hash()
87 }
88
89 pub fn lifetime(&self) -> ManagedGcLifetime<'_> {
90 self.dynamic.lifetime()
91 }
92
93 pub fn exists(&self) -> bool {
94 self.dynamic.exists()
95 }
96
97 pub fn is_owning(&self) -> bool {
98 self.dynamic.is_owning()
99 }
100
101 pub fn is_referencing(&self) -> bool {
102 self.dynamic.is_referencing()
103 }
104
105 pub fn is_owned_by(&self, other: &Self) -> bool {
106 self.dynamic.is_owned_by(&other.dynamic)
107 }
108
109 pub fn try_read(&'_ self) -> Option<ValueReadAccess<'_, T>> {
110 self.dynamic.try_read::<T>()
111 }
112
113 pub fn try_write(&'_ mut self) -> Option<ValueWriteAccess<'_, T>> {
114 self.dynamic.try_write::<T>()
115 }
116
117 pub fn read<const LOCKING: bool>(&'_ self) -> ValueReadAccess<'_, T> {
118 self.dynamic.read::<LOCKING, T>()
119 }
120
121 pub fn write<const LOCKING: bool>(&'_ mut self) -> ValueWriteAccess<'_, T> {
122 self.dynamic.write::<LOCKING, T>()
123 }
124
125 pub fn borrow<const LOCKING: bool>(&self) -> ManagedRef<T> {
126 self.dynamic
127 .borrow::<LOCKING>()
128 .into_typed()
129 .ok()
130 .expect("ManagedGc cannot be immutably borrowed")
131 }
132
133 pub fn borrow_mut<const LOCKING: bool>(&mut self) -> ManagedRefMut<T> {
134 self.dynamic
135 .borrow_mut::<LOCKING>()
136 .into_typed()
137 .ok()
138 .expect("ManagedGc cannot be mutably borrowed")
139 }
140
141 pub fn lazy(&self) -> ManagedLazy<T> {
142 self.dynamic
143 .lazy()
144 .into_typed()
145 .ok()
146 .expect("ManagedGc cannot be lazily borrowed")
147 }
148
149 pub unsafe fn as_ptr(&self) -> *const T {
151 unsafe { self.dynamic.as_ptr_raw().cast::<T>() }
152 }
153
154 pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
156 unsafe { self.dynamic.as_mut_ptr_raw().cast::<T>() }
157 }
158}
159
160pub struct DynamicManagedGc {
161 type_hash: TypeHash,
162 kind: Kind,
163 layout: Layout,
164 finalizer: unsafe fn(*mut ()),
165 drop: bool,
166}
167
168unsafe impl Send for DynamicManagedGc {}
169unsafe impl Sync for DynamicManagedGc {}
170
171impl Drop for DynamicManagedGc {
172 fn drop(&mut self) {
173 if let Kind::Owned { lifetime, data } = &mut self.kind
174 && self.drop
175 {
176 while lifetime.state().is_in_use() {
177 std::hint::spin_loop();
178 }
179 lifetime.invalidate();
180 unsafe {
181 if data.is_null() {
182 return;
183 }
184 (self.finalizer)(data.cast::<()>());
185 non_zero_dealloc(*data, self.layout);
186 }
187 }
188 }
189}
190
191impl DynamicManagedGc {
192 pub fn new<T: Finalize>(data: T) -> Self {
193 let layout = Layout::new::<T>().pad_to_align();
194 unsafe {
195 let memory = non_zero_alloc(layout) as *mut T;
196 if memory.is_null() {
197 handle_alloc_error(layout);
198 }
199 memory.cast::<T>().write(data);
200 Self {
201 type_hash: TypeHash::of::<T>(),
202 kind: Kind::Owned {
203 lifetime: Default::default(),
204 data: memory.cast::<u8>(),
205 },
206 layout,
207 finalizer: T::finalize_raw,
208 drop: true,
209 }
210 }
211 }
212
213 pub unsafe fn new_cyclic<T: Finalize>(f: impl FnOnce(Self) -> T) -> Self {
215 let layout = Layout::new::<T>().pad_to_align();
216 unsafe {
217 let memory = non_zero_alloc(layout) as *mut T;
218 if memory.is_null() {
219 handle_alloc_error(layout);
220 }
221 let result = Self {
222 type_hash: TypeHash::of::<T>(),
223 kind: Kind::Owned {
224 lifetime: Default::default(),
225 data: memory.cast::<u8>(),
226 },
227 layout,
228 finalizer: T::finalize_raw,
229 drop: true,
230 };
231 let data = f(result.reference());
232 memory.cast::<T>().write(data);
233 result
234 }
235 }
236
237 pub fn new_raw(
238 type_hash: TypeHash,
239 lifetime: Lifetime,
240 memory: *mut u8,
241 layout: Layout,
242 finalizer: unsafe fn(*mut ()),
243 ) -> Self {
244 if memory.is_null() {
245 handle_alloc_error(layout);
246 }
247 Self {
248 type_hash,
249 kind: Kind::Owned {
250 lifetime: Box::new(lifetime),
251 data: memory,
252 },
253 layout,
254 finalizer,
255 drop: true,
256 }
257 }
258
259 pub fn new_uninitialized(
260 type_hash: TypeHash,
261 layout: Layout,
262 finalizer: unsafe fn(*mut ()),
263 ) -> Self {
264 let memory = unsafe { non_zero_alloc(layout) };
265 if memory.is_null() {
266 handle_alloc_error(layout);
267 }
268 Self {
269 type_hash,
270 kind: Kind::Owned {
271 lifetime: Default::default(),
272 data: memory,
273 },
274 layout,
275 finalizer,
276 drop: true,
277 }
278 }
279
280 pub fn reference(&self) -> Self {
281 match &self.kind {
282 Kind::Owned { lifetime, data } => Self {
283 type_hash: self.type_hash,
284 kind: Kind::Referenced {
285 lifetime: lifetime.lazy(),
286 data: *data,
287 },
288 layout: self.layout,
289 finalizer: self.finalizer,
290 drop: true,
291 },
292 Kind::Referenced { lifetime, data } => Self {
293 type_hash: self.type_hash,
294 kind: Kind::Referenced {
295 lifetime: lifetime.clone(),
296 data: *data,
297 },
298 layout: self.layout,
299 finalizer: self.finalizer,
300 drop: true,
301 },
302 }
303 }
304
305 pub fn consume<T>(mut self) -> Result<T, Self> {
306 if let Kind::Owned { lifetime, data } = &mut self.kind {
307 if self.type_hash == TypeHash::of::<T>() && !lifetime.state().is_in_use() {
308 if data.is_null() {
309 return Err(self);
310 }
311 self.drop = false;
312 let mut result = MaybeUninit::<T>::uninit();
313 unsafe {
314 result.as_mut_ptr().copy_from(data.cast::<T>(), 1);
315 non_zero_dealloc(*data, self.layout);
316 Ok(result.assume_init())
317 }
318 } else {
319 Err(self)
320 }
321 } else {
322 Err(self)
323 }
324 }
325
326 pub fn into_typed<T>(self) -> ManagedGc<T> {
327 ManagedGc {
328 dynamic: self,
329 _phantom: PhantomData,
330 }
331 }
332
333 pub fn renew(&mut self) {
334 if let Kind::Owned { lifetime, .. } = &mut self.kind {
335 **lifetime = Default::default();
336 }
337 }
338
339 pub fn type_hash(&self) -> TypeHash {
340 self.type_hash
341 }
342
343 pub fn lifetime(&self) -> ManagedGcLifetime<'_> {
344 match &self.kind {
345 Kind::Owned { lifetime, .. } => ManagedGcLifetime::Owned(lifetime),
346 Kind::Referenced { lifetime, .. } => ManagedGcLifetime::Referenced(lifetime),
347 }
348 }
349
350 pub fn layout(&self) -> &Layout {
351 &self.layout
352 }
353
354 pub fn finalizer(&self) -> unsafe fn(*mut ()) {
355 self.finalizer
356 }
357
358 pub unsafe fn memory(&self) -> &[u8] {
360 let memory = match &self.kind {
361 Kind::Owned { data, .. } => *data,
362 Kind::Referenced { data, .. } => *data,
363 };
364 unsafe { std::slice::from_raw_parts(memory, self.layout.size()) }
365 }
366
367 pub unsafe fn memory_mut(&mut self) -> &mut [u8] {
369 let memory = match &mut self.kind {
370 Kind::Owned { data, .. } => *data,
371 Kind::Referenced { data, .. } => *data,
372 };
373 unsafe { std::slice::from_raw_parts_mut(memory, self.layout.size()) }
374 }
375
376 pub fn exists(&self) -> bool {
377 match &self.kind {
378 Kind::Owned { .. } => true,
379 Kind::Referenced { lifetime, .. } => lifetime.exists(),
380 }
381 }
382
383 pub fn is_owning(&self) -> bool {
384 matches!(self.kind, Kind::Owned { .. })
385 }
386
387 pub fn is_referencing(&self) -> bool {
388 matches!(self.kind, Kind::Referenced { .. })
389 }
390
391 pub fn is_owned_by(&self, other: &Self) -> bool {
392 if let (Kind::Referenced { lifetime: l1, .. }, Kind::Owned { lifetime: l2, .. }) =
393 (&self.kind, &other.kind)
394 {
395 l1.state().is_owned_by(l2.state())
396 } else {
397 false
398 }
399 }
400
401 pub fn is<T>(&self) -> bool {
402 self.type_hash == TypeHash::of::<T>()
403 }
404
405 pub fn try_read<T>(&'_ self) -> Option<ValueReadAccess<'_, T>> {
406 if !self.is::<T>() {
407 panic!(
408 "DynamicManagedGc is not of the requested type: {}",
409 std::any::type_name::<T>()
410 );
411 }
412 unsafe {
413 match &self.kind {
414 Kind::Owned { lifetime, data } => {
415 let data = data.cast::<T>().as_ref()?;
416 lifetime.read(data)
417 }
418 Kind::Referenced { lifetime, data } => {
419 if lifetime.exists() {
420 let data = data.cast::<T>().as_ref()?;
421 lifetime.read(data)
422 } else {
423 None
424 }
425 }
426 }
427 }
428 }
429
430 pub fn try_write<T>(&'_ mut self) -> Option<ValueWriteAccess<'_, T>> {
431 if !self.is::<T>() {
432 panic!(
433 "DynamicManagedGc is not of the requested type: {}",
434 std::any::type_name::<T>()
435 );
436 }
437 unsafe {
438 match &self.kind {
439 Kind::Owned { lifetime, data } => {
440 let data = data.cast::<T>().as_mut()?;
441 lifetime.write(data)
442 }
443 Kind::Referenced { lifetime, data } => {
444 if lifetime.exists() {
445 let data = data.cast::<T>().as_mut()?;
446 lifetime.write(data)
447 } else {
448 None
449 }
450 }
451 }
452 }
453 }
454
455 pub fn read<const LOCKING: bool, T>(&'_ self) -> ValueReadAccess<'_, T> {
456 if !self.is::<T>() {
457 panic!(
458 "DynamicManagedGc is not of the requested type: {}",
459 std::any::type_name::<T>()
460 );
461 }
462 unsafe {
463 if LOCKING {
464 match &self.kind {
465 Kind::Owned { lifetime, data } => loop {
466 let data = data
467 .cast::<T>()
468 .as_ref()
469 .expect("DynamicManagedGc data pointer is null");
470 if let Some(access) = lifetime.read(data) {
471 return access;
472 }
473 std::hint::spin_loop();
474 },
475 Kind::Referenced { lifetime, data } => loop {
476 if !lifetime.exists() {
477 panic!("DynamicManagedGc owner is dead");
478 }
479 let data = data
480 .cast::<T>()
481 .as_ref()
482 .expect("DynamicManagedGc data pointer is null");
483 if let Some(access) = lifetime.read(data) {
484 return access;
485 }
486 std::hint::spin_loop();
487 },
488 }
489 } else {
490 match &self.kind {
491 Kind::Owned { lifetime, data } => {
492 let data = data
493 .cast::<T>()
494 .as_ref()
495 .expect("DynamicManagedGc data pointer is null");
496 lifetime
497 .read(data)
498 .expect("DynamicManagedGc is inaccessible for reading")
499 }
500 Kind::Referenced { lifetime, data } => {
501 let data = data
502 .cast::<T>()
503 .as_ref()
504 .expect("DynamicManagedGc data pointer is null");
505 lifetime
506 .read(data)
507 .expect("DynamicManagedGc is inaccessible for reading")
508 }
509 }
510 }
511 }
512 }
513
514 pub fn write<const LOCKING: bool, T>(&'_ mut self) -> ValueWriteAccess<'_, T> {
515 if !self.is::<T>() {
516 panic!(
517 "DynamicManagedGc is not of the requested type: {}",
518 std::any::type_name::<T>()
519 );
520 }
521 unsafe {
522 if LOCKING {
523 match &self.kind {
524 Kind::Owned { lifetime, data } => loop {
525 let data = data
526 .cast::<T>()
527 .as_mut()
528 .expect("DynamicManagedGc data pointer is null");
529 if let Some(access) = lifetime.write(data) {
530 return access;
531 }
532 std::hint::spin_loop();
533 },
534 Kind::Referenced { lifetime, data } => loop {
535 if !lifetime.exists() {
536 panic!("DynamicManagedGc owner is dead");
537 }
538 let data = data
539 .cast::<T>()
540 .as_mut()
541 .expect("DynamicManagedGc data pointer is null");
542 if let Some(access) = lifetime.write(data) {
543 return access;
544 }
545 std::hint::spin_loop();
546 },
547 }
548 } else {
549 match &self.kind {
550 Kind::Owned { lifetime, data } => {
551 let data = data
552 .cast::<T>()
553 .as_mut()
554 .expect("DynamicManagedGc data pointer is null");
555 lifetime
556 .write(data)
557 .expect("DynamicManagedGc is inaccessible for writing")
558 }
559 Kind::Referenced { lifetime, data } => {
560 let data = data
561 .cast::<T>()
562 .as_mut()
563 .expect("DynamicManagedGc data pointer is null");
564 lifetime
565 .write(data)
566 .expect("DynamicManagedGc is inaccessible for writing")
567 }
568 }
569 }
570 }
571 }
572
573 pub fn borrow<const LOCKING: bool>(&self) -> DynamicManagedRef {
574 unsafe {
575 if LOCKING {
576 match &self.kind {
577 Kind::Owned { lifetime, data } => loop {
578 if let Some(lifetime) = lifetime.borrow() {
579 return DynamicManagedRef::new_raw(self.type_hash, lifetime, *data)
580 .expect("DynamicManagedGc cannot be immutably borrowed");
581 }
582 std::hint::spin_loop();
583 },
584 Kind::Referenced { lifetime, data } => loop {
585 if !lifetime.exists() {
586 panic!("DynamicManagedGc owner is dead");
587 }
588 if let Some(lifetime) = lifetime.borrow() {
589 return DynamicManagedRef::new_raw(self.type_hash, lifetime, *data)
590 .expect("DynamicManagedGc cannot be immutably borrowed");
591 }
592 std::hint::spin_loop();
593 },
594 }
595 } else {
596 match &self.kind {
597 Kind::Owned { lifetime, data } => DynamicManagedRef::new_raw(
598 self.type_hash,
599 lifetime
600 .borrow()
601 .expect("DynamicManagedGc is inaccessible for immutable borrowing"),
602 *data,
603 )
604 .expect("DynamicManagedGc cannot be immutably borrowed"),
605 Kind::Referenced { lifetime, data } => DynamicManagedRef::new_raw(
606 self.type_hash,
607 lifetime
608 .borrow()
609 .expect("DynamicManagedGc is inaccessible for immutable borrowing"),
610 *data,
611 )
612 .expect("DynamicManagedGc cannot be immutably borrowed"),
613 }
614 }
615 }
616 }
617
618 pub fn borrow_mut<const LOCKING: bool>(&mut self) -> DynamicManagedRefMut {
619 unsafe {
620 if LOCKING {
621 match &self.kind {
622 Kind::Owned { lifetime, data } => loop {
623 if let Some(lifetime) = lifetime.borrow_mut() {
624 return DynamicManagedRefMut::new_raw(self.type_hash, lifetime, *data)
625 .expect("DynamicManagedGc cannot be mutably borrowed");
626 }
627 std::hint::spin_loop();
628 },
629 Kind::Referenced { lifetime, data } => loop {
630 if !lifetime.exists() {
631 panic!("DynamicManagedGc owner is dead");
632 }
633 if let Some(lifetime) = lifetime.borrow_mut() {
634 return DynamicManagedRefMut::new_raw(self.type_hash, lifetime, *data)
635 .expect("DynamicManagedGc cannot be mutably borrowed");
636 }
637 std::hint::spin_loop();
638 },
639 }
640 } else {
641 match &self.kind {
642 Kind::Owned { lifetime, data } => DynamicManagedRefMut::new_raw(
643 self.type_hash,
644 lifetime
645 .borrow_mut()
646 .expect("DynamicManagedGc is inaccessible for mutable borrowing"),
647 *data,
648 )
649 .expect("DynamicManagedGc cannot be mutably borrowed"),
650 Kind::Referenced { lifetime, data } => DynamicManagedRefMut::new_raw(
651 self.type_hash,
652 lifetime
653 .borrow_mut()
654 .expect("DynamicManagedGc is inaccessible for mutable borrowing"),
655 *data,
656 )
657 .expect("DynamicManagedGc cannot be mutably borrowed"),
658 }
659 }
660 }
661 }
662
663 pub fn lazy(&self) -> DynamicManagedLazy {
664 unsafe {
665 match &self.kind {
666 Kind::Owned { lifetime, data } => {
667 DynamicManagedLazy::new_raw(self.type_hash, lifetime.lazy(), *data)
668 .expect("DynamicManagedGc cannot be lazily borrowed")
669 }
670 Kind::Referenced { lifetime, data } => {
671 DynamicManagedLazy::new_raw(self.type_hash, lifetime.clone(), *data)
672 .expect("DynamicManagedGc cannot be lazily borrowed")
673 }
674 }
675 }
676 }
677
678 pub unsafe fn as_ptr_raw(&self) -> *const u8 {
680 match &self.kind {
681 Kind::Owned { data, .. } => *data as *const u8,
682 Kind::Referenced { data, .. } => *data as *const u8,
683 }
684 }
685
686 pub unsafe fn as_mut_ptr_raw(&mut self) -> *mut u8 {
688 match &self.kind {
689 Kind::Owned { data, .. } => *data,
690 Kind::Referenced { data, .. } => *data,
691 }
692 }
693}
694
695#[cfg(test)]
696mod tests {
697 use super::*;
698
699 #[test]
700 fn test_is_async() {
701 fn is_async<T: Send + Sync>() {}
702
703 is_async::<ManagedGc<()>>();
704 is_async::<DynamicManagedGc>();
705 }
706
707 #[test]
708 fn test_managed_gc() {
709 let mut managed = ManagedGc::new(42);
710 {
711 let read_access = managed.read::<true>();
712 assert_eq!(*read_access, 42);
713 }
714 {
715 let mut write_access = managed.write::<true>();
716 *write_access = 100;
717 }
718 {
719 let read_access = managed.read::<true>();
720 assert_eq!(*read_access, 100);
721 }
722 }
723
724 #[test]
725 #[allow(unused)]
726 fn test_managed_gc_lifetimes() {
727 struct Car {
728 gear: i32,
729 engine: Option<ManagedGc<Engine>>,
730 }
731
732 struct Engine {
733 owning_car: Option<ManagedGc<Car>>,
734 horsepower: i32,
735 }
736
737 let mut car = ManagedGc::new(Car {
738 gear: 1,
739 engine: None,
740 });
741 let engine = ManagedGc::new(Engine {
742 owning_car: Some(car.reference()),
743 horsepower: 200,
744 });
745 let engine2 = engine.reference();
746 car.write::<true>().engine = Some(engine);
747
748 assert!(car.exists());
749 assert!(car.is_owning());
750 assert!(engine2.exists());
751 assert!(engine2.is_referencing());
752 assert!(engine2.is_owned_by(car.read::<true>().engine.as_ref().unwrap()));
753
754 let car2 = car.reference();
755 assert!(car2.exists());
756 assert!(car2.is_referencing());
757
758 drop(car);
759 assert!(!car2.exists());
760 assert!(car2.try_read().is_none());
761 assert!(!engine2.exists());
762 assert!(engine2.try_read().is_none());
763 }
764
765 #[test]
766 fn test_managed_gc_cycles() {
767 #[derive(Default)]
768 struct Foo {
769 other: Option<ManagedGc<Self>>,
770 }
771
772 {
773 let mut a = ManagedGc::<Foo>::default();
774 let mut b = ManagedGc::<Foo>::default();
775 a.write::<true>().other = Some(b.reference());
776 b.write::<true>().other = Some(a.reference());
777
778 assert!(a.exists());
779 assert!(a.is_owning());
780 assert!(a.read::<true>().other.as_ref().unwrap().is_referencing());
781 assert!(a.read::<true>().other.as_ref().unwrap().is_owned_by(&b));
782
783 assert!(b.exists());
784 assert!(b.is_owning());
785 assert!(b.read::<true>().other.as_ref().unwrap().is_referencing());
786 assert!(b.read::<true>().other.as_ref().unwrap().is_owned_by(&a));
787
788 drop(b);
789 assert!(!a.read::<true>().other.as_ref().unwrap().exists());
790 }
791
792 {
793 let mut a = ManagedGc::<Foo>::default();
794 a.write::<true>().other = Some(a.reference());
795
796 assert!(a.exists());
797 assert!(a.is_owning());
798 assert!(a.read::<true>().other.as_ref().unwrap().is_referencing());
799 assert!(a.read::<true>().other.as_ref().unwrap().is_owned_by(&a));
800 }
801 }
802
803 #[test]
804 fn test_dynamic_managed_gc() {
805 let mut managed = DynamicManagedGc::new(42);
806 {
807 let read_access = managed.read::<true, i32>();
808 assert_eq!(*read_access, 42);
809 }
810 {
811 let mut write_access = managed.write::<true, i32>();
812 *write_access = 100;
813 }
814 {
815 let read_access = managed.read::<true, i32>();
816 assert_eq!(*read_access, 100);
817 }
818 }
819
820 #[test]
821 fn test_dynamic_managed_gc_cycles() {
822 #[derive(Default)]
823 struct Foo {
824 other: Option<DynamicManagedGc>,
825 }
826
827 {
828 let mut a = DynamicManagedGc::new(Foo::default());
829 let mut b = DynamicManagedGc::new(Foo::default());
830 a.write::<true, Foo>().other = Some(b.reference());
831 b.write::<true, Foo>().other = Some(a.reference());
832
833 assert!(a.exists());
834 assert!(a.is_owning());
835 assert!(
836 a.read::<true, Foo>()
837 .other
838 .as_ref()
839 .unwrap()
840 .is_referencing()
841 );
842 assert!(
843 a.read::<true, Foo>()
844 .other
845 .as_ref()
846 .unwrap()
847 .is_owned_by(&b)
848 );
849
850 assert!(b.exists());
851 assert!(b.is_owning());
852 assert!(
853 b.read::<true, Foo>()
854 .other
855 .as_ref()
856 .unwrap()
857 .is_referencing()
858 );
859 assert!(
860 b.read::<true, Foo>()
861 .other
862 .as_ref()
863 .unwrap()
864 .is_owned_by(&a)
865 );
866
867 drop(b);
868 assert!(!a.read::<true, Foo>().other.as_ref().unwrap().exists());
869 }
870
871 {
872 let mut a = DynamicManagedGc::new(Foo::default());
873 a.write::<true, Foo>().other = Some(a.reference());
874
875 assert!(a.exists());
876 assert!(a.is_owning());
877 assert!(
878 a.read::<true, Foo>()
879 .other
880 .as_ref()
881 .unwrap()
882 .is_referencing()
883 );
884 assert!(
885 a.read::<true, Foo>()
886 .other
887 .as_ref()
888 .unwrap()
889 .is_owned_by(&a)
890 );
891 }
892 }
893
894 #[test]
895 fn test_managed_gc_conversions() {
896 let managed = ManagedGc::new(42);
897 assert_eq!(*managed.read::<true>(), 42);
898
899 let mut dynamic = managed.into_dynamic();
900 *dynamic.write::<true, i32>() = 100;
901
902 let managed = dynamic.into_typed::<i32>();
903 assert_eq!(*managed.read::<true>(), 100);
904 }
905
906 #[test]
907 fn test_managed_gc_dead_owner() {
908 let a = ManagedGc::new(42);
909 let mut b = a.reference();
910
911 assert!(a.exists());
912 assert!(b.exists());
913 assert_eq!(*b.read::<true>(), 42);
914
915 drop(a);
916 assert!(!b.exists());
917 assert!(b.try_write().is_none());
918 }
919
920 #[test]
921 #[should_panic]
922 fn test_managed_gc_dead_owner_panic() {
923 let a = ManagedGc::new(42);
924 let mut b = a.reference();
925
926 assert!(a.exists());
927 assert!(b.exists());
928 assert_eq!(*b.read::<true>(), 42);
929
930 drop(a);
931 assert!(!b.exists());
932 assert_eq!(*b.write::<true>(), 42);
933 }
934
935 #[test]
936 fn test_managed_gc_cyclic() {
937 struct SelfReferencial {
938 value: i32,
939 this: ManagedGc<SelfReferencial>,
940 }
941
942 let v = unsafe { ManagedGc::new_cyclic(|this| SelfReferencial { value: 42, this }) };
943 assert_eq!(v.read::<true>().value, 42);
944 let this = v.read::<true>().this.reference();
945 assert_eq!(this.read::<true>().value, 42);
946 }
947}