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