Skip to main content

logic_eval_util/
reference.rs

1use std::{marker::PhantomData, ptr::NonNull};
2
3/// A lightweight wrapper around a non-null pointer for a shared reference.
4///
5/// The wrappers are useful when you need a pointer instead of a reference while not degrading usage
6/// and keeping its provenance. For instance, if you make the [`Ref`] from a mutable reference, the
7/// fact the type is made from "mutable" won't be lost, which is an information which some tools,
8/// such as [miri], used for finding pointer safety violations.
9///
10/// [miri]: https://github.com/rust-lang/miri
11#[derive(Debug)]
12pub struct Ref<'a, T: 'a + ?Sized> {
13    ptr: NonNull<T>,
14    _marker: PhantomData<&'a T>,
15}
16
17impl<'a, T: 'a + ?Sized> Ref<'a, T> {
18    pub const fn from_ref(r: &'a T) -> Self {
19        // Safety: A referenfce is non-null
20        let ptr = unsafe { NonNull::new_unchecked(r as *const T as *mut T) };
21        Self {
22            ptr,
23            _marker: PhantomData,
24        }
25    }
26
27    pub fn from_mut(r: &'a mut T) -> Self {
28        // Safety: A referenfce is non-null
29        let ptr = unsafe { NonNull::new_unchecked(r as *mut T) };
30        Self {
31            ptr,
32            _marker: PhantomData,
33        }
34    }
35
36    // Output lifetime is 'a, so we need this method rather than AsRef::as_ref or something like
37    // that.
38    #[allow(clippy::should_implement_trait)]
39    pub fn as_ref(&self) -> &'a T {
40        // Safety: The type actually has the `&'a T`.
41        unsafe { self.ptr.as_ref() }
42    }
43
44    pub const fn as_nonnull(self) -> NonNull<T> {
45        self.ptr
46    }
47
48    pub const fn as_ptr(self) -> *mut T {
49        self.ptr.as_ptr()
50    }
51}
52
53impl<'a, T: 'a + ?Sized> Clone for Ref<'a, T> {
54    fn clone(&self) -> Self {
55        *self
56    }
57}
58
59impl<'a, T: 'a + ?Sized> Copy for Ref<'a, T> {}