boot_services/
c_ptr.rs

1use alloc::boxed::Box;
2use core::{
3    ffi::c_void,
4    marker::PhantomData,
5    mem::{self, ManuallyDrop},
6    ops::Deref,
7    ptr,
8};
9
10#[derive(Clone, Copy)]
11// Ptr metadata is a struct that hold everything to rebuild the original pointer from this metadata.
12pub struct PtrMetadata<'a, T> {
13    pub ptr_value: usize,
14    _container: PhantomData<&'a T>,
15}
16
17impl<'a, R: CPtr<'a, Type = T>, T> PtrMetadata<'a, R> {
18    pub unsafe fn into_original_ptr(self) -> R {
19        mem::transmute_copy(&self.ptr_value)
20    }
21}
22
23// Trait for type that can be used as pointer.
24pub unsafe trait CPtr<'a>: Sized {
25    type Type: Sized;
26
27    fn as_ptr(&self) -> *const Self::Type;
28
29    fn into_ptr(self) -> *const Self::Type {
30        let this = ManuallyDrop::new(self);
31        this.as_ptr()
32    }
33
34    fn metadata(&self) -> PtrMetadata<'a, Self> {
35        PtrMetadata { ptr_value: self.as_ptr() as usize, _container: PhantomData }
36    }
37}
38
39// Trait for type that can be used as mutable pointer.
40pub unsafe trait CMutPtr<'a>: CPtr<'a> {
41    fn as_mut_ptr(&mut self) -> *mut Self::Type {
42        <Self as CPtr>::as_ptr(self) as *mut _
43    }
44
45    fn into_mut_ptr(self) -> *mut Self::Type {
46        let mut this = ManuallyDrop::new(self);
47        this.as_mut_ptr()
48    }
49}
50
51// Trait for type that can be used as pointer and that can not be null.
52pub unsafe trait CRef<'a>: CPtr<'a> {
53    fn as_ref(&self) -> &Self::Type {
54        unsafe { self.as_ptr().as_ref().unwrap() }
55    }
56}
57
58// Trait for type that can be used as mutable pointer and that can not be null.
59pub unsafe trait CMutRef<'a>: CRef<'a> + CMutPtr<'a> {
60    fn as_mut(&mut self) -> &mut Self::Type {
61        unsafe { self.as_mut_ptr().as_mut().unwrap() }
62    }
63}
64
65// &T
66unsafe impl<'a, T> CPtr<'a> for &'a T {
67    type Type = T;
68
69    fn as_ptr(&self) -> *const Self::Type {
70        *self as *const _
71    }
72}
73unsafe impl<'a, T> CRef<'a> for &'a T {}
74
75// &mut T
76unsafe impl<'a, T> CPtr<'a> for &'a mut T {
77    type Type = T;
78
79    fn as_ptr(&self) -> *const Self::Type {
80        *self as *const _
81    }
82}
83unsafe impl<'a, T> CRef<'a> for &'a mut T {}
84unsafe impl<'a, T> CMutPtr<'a> for &'a mut T {}
85unsafe impl<'a, T> CMutRef<'a> for &'a mut T {}
86
87// Box<T>
88unsafe impl<'a, T> CPtr<'a> for Box<T> {
89    type Type = T;
90
91    fn as_ptr(&self) -> *const Self::Type {
92        AsRef::as_ref(self) as *const _
93    }
94}
95unsafe impl<'a, T> CRef<'a> for Box<T> {}
96unsafe impl<'a, T> CMutPtr<'a> for Box<T> {}
97unsafe impl<'a, T> CMutRef<'a> for Box<T> {}
98
99// ()
100unsafe impl CPtr<'static> for () {
101    type Type = c_void;
102
103    fn as_ptr(&self) -> *const Self::Type {
104        ptr::null()
105    }
106}
107
108unsafe impl CMutPtr<'static> for () {
109    fn as_mut_ptr(&mut self) -> *mut Self::Type {
110        ptr::null_mut()
111    }
112}
113
114// Option<T>
115unsafe impl<'a, R: CPtr<'a, Type = T>, T> CPtr<'a> for Option<R> {
116    type Type = T;
117
118    fn as_ptr(&self) -> *const Self::Type {
119        self.as_ref().map_or(ptr::null(), |p| p.as_ptr())
120    }
121}
122unsafe impl<'a, R: CMutPtr<'a, Type = T>, T> CMutPtr<'a> for Option<R> {}
123
124// ManuallyDrop<T>
125unsafe impl<'a, R: CPtr<'a, Type = T>, T> CPtr<'a> for ManuallyDrop<R> {
126    type Type = T;
127
128    fn as_ptr(&self) -> *const Self::Type {
129        <R as CPtr>::as_ptr(self.deref())
130    }
131}
132unsafe impl<'a, R: CMutPtr<'a, Type = T>, T> CMutPtr<'a> for ManuallyDrop<R> {}
133unsafe impl<'a, R: CRef<'a, Type = T>, T> CRef<'a> for ManuallyDrop<R> {}
134unsafe impl<'a, R: CMutRef<'a, Type = T>, T> CMutRef<'a> for ManuallyDrop<R> {}
135
136#[cfg(test)]
137mod test {
138    use core::ptr;
139
140    use super::*;
141
142    #[test]
143    fn test_ref() {
144        let mut foo = 10;
145        let ptr = ptr::addr_of!(foo);
146
147        assert_eq!(ptr, (&foo).as_ptr());
148        assert_eq!(ptr, (&mut foo).as_mut_ptr());
149
150        assert_eq!(ptr, (&foo).as_ref() as *const _);
151        assert_eq!(ptr, (&mut foo).as_mut() as *const _);
152
153        assert_eq!(ptr, (&mut foo).into_ptr());
154        let mut foo = 10;
155        let ptr = ptr::addr_of!(foo);
156        assert_eq!(ptr, (&mut foo).into_mut_ptr());
157    }
158
159    #[test]
160    fn test_box() {
161        let b = Box::new(10);
162        let b_ptr = ptr::from_ref(<Box<_> as AsRef<_>>::as_ref(&b));
163
164        assert_eq!(b_ptr, CPtr::as_ptr(&b));
165        assert_eq!(b_ptr, CPtr::into_ptr(b));
166
167        // Box should leak with into_ptr
168        let mut b = unsafe { Box::from_raw(b_ptr as *mut i32) };
169        assert_eq!(&10, <Box<_> as AsRef<_>>::as_ref(&b));
170
171        assert_eq!(b_ptr, CMutPtr::as_mut_ptr(&mut b));
172        assert_eq!(b_ptr, CMutPtr::into_mut_ptr(b));
173    }
174
175    #[test]
176    fn test_unit_type() {
177        assert_eq!(ptr::null(), ().as_ptr());
178        assert_eq!(ptr::null_mut(), ().as_mut_ptr());
179    }
180
181    #[test]
182    fn test_option() {
183        assert_eq!(ptr::null(), (Option::<Box<i32>>::None).as_ptr());
184        assert_eq!(ptr::null_mut(), (Option::<Box<i32>>::None).as_mut_ptr());
185
186        let b = Box::new(10);
187        let ptr = b.as_ptr();
188        assert_eq!(ptr, Some(b).as_ptr());
189
190        let b = Box::new(10);
191        let ptr = b.as_ptr();
192        assert_eq!(ptr, Some(b).as_mut_ptr());
193
194        let b = Box::new(10);
195        let ptr = b.as_ptr();
196        assert_eq!(ptr, Some(b).into_ptr());
197
198        let b = Box::new(10);
199        let ptr = b.as_ptr();
200        assert_eq!(ptr, Some(b).into_mut_ptr());
201    }
202
203    #[test]
204    fn test_manually_drop() {
205        let b = Box::new(10);
206        let ptr = b.as_ptr();
207        let mut mdb = ManuallyDrop::new(b);
208        assert_eq!(ptr, mdb.as_ptr());
209        assert_eq!(ptr, mdb.as_mut_ptr());
210        assert_eq!(ptr, mdb.into_ptr());
211
212        let mdb = ManuallyDrop::new(unsafe { Box::from_raw(ptr as *mut i32) });
213        assert_eq!(ptr, mdb.into_mut_ptr());
214
215        assert_eq!(ptr::null(), ManuallyDrop::new(()).as_ptr());
216        assert_eq!(ptr::null_mut(), ManuallyDrop::new(()).as_mut_ptr());
217    }
218}