gc_api/alloc/
access.rs

1//! # Brainstorming notes for Access
2//!
3//! Access traits need to fit a couple key requirements that make it problematic.
4//!
5//! ## Considerations:
6//!  - Access must be able to return an error if the GC is able to detect any issues.
7//!  - A guard may be necessary if a GC needs to track when an access is in progress. Guard types
8//!    can be generic, but it might not be necessary. It may be easier to implement a GC if there
9//!    was an access end function that was called with a provided accessor. Are there any situations
10//!    where this would this limit the ability of implementors?
11//!  - A handle should be treated similarly to an Arc (or Rc), so access can only be immutable under
12//!    normal circumstances.
13//!  - Some mark words come with mutex functionality (A notable one being Oracle's G1). To make
14//!    this functionality usable, either the mark word needs to be accessible or the access trait
15//!    needs to provide this functionality.
16//!  - How can we differentiate when an object needs to be manually wrapped in a mutex vs can be
17//!    used as-is.
18//!
19//! ## Working Ideas/considerations
20//!  - There needs to be a way to easily initialize types with or without interior mutability.
21//!
22
23use crate::alloc::AllocMut;
24use crate::error::Error;
25use crate::{Alloc, Gc, GcMut};
26use std::ops::{Deref, DerefMut};
27
28pub trait Accessor<T: ?Sized, A>: Sized
29where
30    A: Alloc<T>,
31{
32    // TODO: Should Deref be replaced with Borrow?
33    type Guard<'g>: Deref<Target = T>
34    where
35        Self: 'g;
36
37    /// Get immutable access to
38    #[inline(always)]
39    fn read<'g>(&'g self, object: &'g Gc<T, A>) -> Self::Guard<'g> {
40        self.try_read(object)
41            .unwrap_or_else(|err| failed_access(err))
42    }
43
44    #[inline(always)]
45    fn try_read<'g>(&'g self, object: &'g Gc<T, A>) -> Result<Self::Guard<'g>, Error> {
46        unsafe { self.access(&object.handle) }
47    }
48
49    /// Check if an object is alive. Not all garbage collectors will support performing this check.
50    fn is_alive(&self, _object: &Gc<T, A>) -> Option<bool> {
51        None
52    }
53
54    /// Creates a guard which can be used to read the data associated with this handle.
55    ///
56    /// # Safety
57    /// The handle must corespond to a valid GC object in the heap used by this accessor.
58    unsafe fn access<'g>(
59        &'g self,
60        handle: &'g <A as Alloc<T>>::RawHandle,
61    ) -> Result<Self::Guard<'g>, Error>;
62}
63
64pub trait AccessorMut<T: ?Sized, A>: Accessor<T, A>
65where
66    A: AllocMut<T>,
67{
68    type GuardMut<'g>: DerefMut<Target = T>
69    where
70        Self: 'g;
71
72    /// Get immutable access to
73    #[inline(always)]
74    fn write<'g>(&'g self, object: &'g GcMut<T, A>) -> Self::GuardMut<'g> {
75        self.try_write(object)
76            .unwrap_or_else(|err| failed_access(err))
77    }
78
79    #[inline(always)]
80    fn try_write<'g>(&'g self, object: &'g GcMut<T, A>) -> Result<Self::GuardMut<'g>, Error> {
81        unsafe { self.access_mut(&object.handle) }
82    }
83
84    /// Creates a guard which can be used to read or write data associated with this handle.
85    ///
86    /// # Safety
87    /// The handle must corespond to a valid GC object in the heap used by this accessor.
88    unsafe fn access_mut<'g>(
89        &'g self,
90        handle: &'g <A as Alloc<<A as Alloc<T>>::MutTy>>::RawHandle,
91    ) -> Result<Self::GuardMut<'g>, Error>;
92}
93
94#[inline(never)]
95#[cold]
96fn failed_access(err: Error) -> ! {
97    panic!("Failed to access GC object: {:?}", err)
98}