out_reference/
lib.rs

1#![forbid(missing_docs)]
2#![cfg_attr(not(feature = "std"), no_std)]
3#![cfg_attr(feature = "nightly", feature(coerce_unsized, unsize))]
4
5//! This crate brings out references to Rust, this crate has `no_std` support
6//! Out reference *never* read values behind the reference
7//!
8//! ```rust
9//! use out_reference::*;
10//!
11//! let mut x = 0;
12//!
13//! let mut out_x: Out<'_, u32> = x.out();
14//! out_x.set(10);
15//!
16//! assert_eq!(x, 10);
17//! ```
18//!
19//! Note that setting a value does not drop the old value,
20//! as that would require at least 1 read of the value behind the pointer
21//!
22//! So, the code below leaks the vector
23//! ```rust
24//! use out_reference::*;
25//!
26//! let mut x = vec![0, 1, 2];
27//!
28//! let mut out_x: Out<'_, Vec<u32>> = x.out();
29//! out_x.set(vec![]);
30//!
31//! assert_eq!(x, vec![]);
32//! ```
33
34#[cfg(test)]
35mod tests;
36
37use core::mem::MaybeUninit;
38use core::marker::PhantomData;
39
40/// An Out Reference, you can only write to this reference using the `set` method
41/// and reborrow this reference with the `borrow` method. It isn't safe to read from
42/// an `Out` pointer.
43#[derive(Debug)]
44#[repr(transparent)]
45pub struct Out<'a, T: ?Sized>(*mut T, PhantomData<&'a mut T>);
46
47/// Writes a value to the reference without dropping the old value
48#[inline(always)]
49pub fn write<T>(ptr: &mut T, value: T) {
50    Out::from_mut(ptr).set(value)
51}
52
53impl<'a, T> Out<'a, T> {
54    /// To allow writing to the value inside the MaybeUninit
55    #[inline(always)]
56    pub fn from_maybe_uninit(maybe_uninit: &mut MaybeUninit<T>) -> Out<'_, T> {
57        Out(maybe_uninit.as_mut_ptr(), PhantomData)
58    }
59}
60
61impl<'a, T: ?Sized> Out<'a, T> {
62    /// Create `Out` from exclusive reference
63    #[inline(always)]
64    pub fn from_mut(value: &'a mut T) -> Self {
65        unsafe { Self::from_raw(value) }
66    }
67
68    /// Create `Out` from raw pointer
69    #[inline(always)]
70    pub unsafe fn from_raw(ptr: *mut T) -> Out<'a, T> {
71        Self(ptr, PhantomData)
72    }
73
74    /// Reborrows the `Out` reference
75    #[inline(always)]
76    pub fn borrow(&mut self) -> Out<'_, T> { Out(self.0, PhantomData) }
77
78    /// Convert this `Out` reference into a raw pointer
79    /// 
80    /// see `as_mut_ptr` for safety documentation of the this pointer.
81    #[inline(always)]
82    pub fn into_raw(self) -> *mut T { self.0 }
83
84    /// Get a raw pointer to the `Out`, it is only safe to write to this pointer
85    /// unless specified otherwise by the creator of this `Out` reference
86    /// 
87    /// i.e. it's safe to read to an `Out<'_, T>` that was created from a `&mut T`
88    /// and it's safe to read from a `Out<'_, T>` that was created from a
89    /// `&mut MaybeUninit<T>` after it has been initialized.
90    #[inline(always)]
91    pub fn as_mut_ptr(&mut self) -> *mut T {
92        self.0
93    }
94}
95
96impl<'a, T> Out<'a, T> {
97    /// Set the value behind the `Out` reference *without dropping the old value *
98    pub fn set(&mut self, value: T) { unsafe { std::ptr::write(self.0, value) } }
99}
100
101/// Used to create an Out reference, for all types
102pub trait OutMethod {
103    /// creates an Out ref
104    #[inline(always)]
105    fn out(&mut self) -> Out<'_, Self> { Out::from_mut(self) }
106}
107
108impl<T: ?Sized> OutMethod for T {}
109
110impl<'a, T: ?Sized> From<&'a mut T> for Out<'a, T> {
111    #[inline(always)]
112    fn from(ptr: &'a mut T) -> Self {
113        Self::from_mut(ptr)
114    }
115}
116
117impl<'a, T> From<&'a mut MaybeUninit<T>> for Out<'a, T> {
118    #[inline(always)]
119    fn from(ptr: &'a mut MaybeUninit<T>) -> Self {
120        Self::from_maybe_uninit(ptr)
121    }
122}
123
124#[cfg(feature = "nightly")]
125mod nightly {
126    use std::ops::CoerceUnsized;
127    use std::marker::Unsize;
128    use super::*;
129
130    impl<'a, T: Unsize<U>, U: ?Sized> CoerceUnsized<Out<'a, U>> for Out<'a, T> {}
131}