-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathptr.rs
131 lines (115 loc) · 3.38 KB
/
ptr.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! Persistent Pointer
use super::{pool::PoolHandle, Collectable, GarbageCollection};
use std::marker::PhantomData;
/// NULL identifier of relative address
const NULL_OFFSET: usize = 0;
/// Pointer to an object belonging to the pool
/// - It has an offset from the starting address of the pool.
/// - When referencing, refer to the absolute address of the pool start address plus the offset
#[derive(Debug, Default)]
pub struct PPtr<T: ?Sized> {
offset: usize,
_marker: PhantomData<T>,
}
impl<T: ?Sized> Clone for PPtr<T> {
fn clone(&self) -> Self {
Self {
offset: self.offset,
_marker: PhantomData,
}
}
}
impl<T: Collectable> Collectable for PPtr<T> {
fn filter(ptr: &mut Self, tid: usize, gc: &mut GarbageCollection, pool: &mut PoolHandle) {
if !ptr.is_null() {
let t_ref = unsafe { ptr.deref_mut(pool) };
T::mark(t_ref, tid, gc);
}
}
}
impl<T: ?Sized> Copy for PPtr<T> {}
impl<T: ?Sized> PPtr<T> {
/// Return a null pointer
pub const fn null() -> Self {
Self {
offset: NULL_OFFSET,
_marker: PhantomData,
}
}
/// Convert to offset
///
/// # Example
///
/// Required to convert the `PPtr` that comes out when allocated to the pool into an Atomic Pointer.
/// - `POwned::from_usize(ptr.into_offset())`
pub fn into_offset(self) -> usize {
self.offset
}
/// Check for null pointer
pub fn is_null(self) -> bool {
self.offset == NULL_OFFSET
}
}
impl<T> PPtr<T> {
/// Refer by absolute address
///
/// # Safety
///
/// When multiple pools are opened at the same time, the ptr of pool1 should not use the starting address of pool2.
pub unsafe fn deref(self, pool: &PoolHandle) -> &'_ T {
let addr = pool.start() + self.offset;
debug_assert!(
self != PPtr::null() && pool.valid(addr),
"offset: {}",
self.offset
);
&*(addr as *const T)
}
/// Refer mutably by absolute address
///
/// # Safety
///
/// When multiple pools are opened at the same time, the ptr of pool1 should not use the starting address of pool2.
#[allow(clippy::mut_from_ref)]
pub unsafe fn deref_mut(self, pool: &PoolHandle) -> &'_ mut T {
let addr = pool.start() + self.offset;
debug_assert!(
self != PPtr::null() && pool.valid(addr),
"offset: {}",
self.offset
);
&mut *(addr as *mut T)
}
}
/// Convert reference to persistent ptr
pub trait AsPPtr {
/// Convert reference to persistent ptr
///
/// # Safety
///
/// object must be a reference in `pool`
unsafe fn as_pptr(&self, pool: &PoolHandle) -> PPtr<Self>;
}
impl<T> AsPPtr for T {
unsafe fn as_pptr(&self, pool: &PoolHandle) -> PPtr<Self> {
PPtr {
offset: self as *const T as usize - pool.start(),
_marker: PhantomData,
}
}
}
impl<T> From<usize> for PPtr<T> {
/// Regard the given offset as the starting address of T obj and returns a pointer referencing it.
fn from(off: usize) -> Self {
Self {
offset: off,
_marker: PhantomData,
}
}
}
impl<T> PartialEq<PPtr<T>> for PPtr<T> {
fn eq(&self, other: &Self) -> bool {
self.offset == other.offset
}
}
impl<T> Eq for PPtr<T> {}