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
#![doc = include_str!("../README.md")]
use core::mem;
use std::process;
/// This struct extends reference of value as long as lifetime of value
///
/// Dropping this value will abort process to ensure the lifetime of reference
#[derive(Debug)]
#[repr(transparent)]
pub struct RefExtended<T: ?Sized>(T);
impl<T> RefExtended<T> {
pub const fn new(value: T) -> Self {
Self(value)
}
}
impl<'b, T: ?Sized + 'b> RefExtended<&'_ T> {
/// Returns reference with lifetime of value
///
/// This method is unsafe because
/// * It can create immutable reference while having mutable reference
#[inline(always)]
pub unsafe fn static_ref(&self) -> &'b T {
mem::transmute::<&T, &'b T>(self.0)
}
}
impl<'b, T: ?Sized + 'b> RefExtended<&'_ mut T> {
/// Returns mutable reference with lifetime of value
///
/// This method is unsafe because
/// * It can create mutable reference while having immutable references
/// * It can create multiple mutable reference
#[inline(always)]
pub unsafe fn static_mut(&mut self) -> &'b mut T {
mem::transmute::<&mut T, &'b mut T>(self.0)
}
}
impl<T: ?Sized> Drop for RefExtended<T> {
fn drop(&mut self) {
process::abort();
}
}
/// Safely extends lifetime of reference as long as lifetime of it's value
///
/// ## Usage
/// ```Rust
/// let a = 0_u32;
///
/// ref_extended(&a); // Now a is &'static u32 because lifetime of a's value is 'static
///
/// let mut b = 0_u32;
///
/// ref_extended(&mut b); // Now b is &'static mut u32 because lifetime of b's value is 'static
/// ```
#[macro_export]
macro_rules! ref_extended {
(&$name: ident) => {
let $name = ::ref_extended::RefExtended::new(&$name);
let $name = unsafe { $name.static_ref() };
};
(&mut $name: ident) => {
let mut $name = ::ref_extended::RefExtended::new(&mut $name);
let $name = unsafe { $name.static_mut() };
};
}
/// Pin value to stack and safely extends lifetime of reference as long as lifetime of it's value
///
/// ## Usage
/// ```Rust
/// pin_ref_extended(a, 0_u32); // Now a is &'static u32 with value 0 because lifetime of a's value is 'static
///
/// pin_ref_extended(mut b, 0_u32); // Now b is &'static mut u32 with value 0 because lifetime of b's value is 'static
/// ```
#[macro_export]
macro_rules! pin_ref_extended {
($name: ident, $expr: expr) => {
let $name = $expr;
::ref_extended::ref_extended!(&$name);
};
(mut $name: ident, $expr: expr) => {
let mut $name = $expr;
::ref_extended::ref_extended!(&mut $name);
};
}