ref_extended/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use core::mem;
4use std::{hint::unreachable_unchecked, process};
5
6/// Returns reference with lifetime of value
7///
8/// # Safety
9/// * You must not move original variable
10/// * You must not create immutable reference while having mutable reference
11/// * The reference must not outlive
12#[inline(always)]
13pub unsafe fn extend_ref<'a, T: 'a>(target: &T) -> &'a T {
14    mem::transmute::<&T, &'a T>(target)
15}
16
17/// Returns mutable reference with lifetime of value
18///
19/// # Safety
20/// * You must not move original variable
21/// * You must not create mutable reference while having immutable references
22/// * You must not create multiple mutable reference
23/// * The reference must not outlive
24#[inline(always)]
25pub unsafe fn extend_mut<'a, T: 'a>(target: &mut T) -> &'a mut T {
26    mem::transmute::<&mut T, &'a mut T>(target)
27}
28
29#[doc(hidden)]
30#[inline(always)]
31pub fn run_abort_guarded<F: FnOnce()>(func: F) -> ! {
32    struct AbortGuard;
33
34    impl Drop for AbortGuard {
35        fn drop(&mut self) {
36            process::abort();
37        }
38    }
39
40    {
41        let _guard = AbortGuard;
42
43        func();
44    }
45
46    // Safety: AbortGuard always abort process on drop and cannot be touched from outside
47    unsafe { unreachable_unchecked() }
48}
49
50/// Safely extends lifetime of reference as long as lifetime of it's value.
51///
52/// ## Usage
53/// ```Rust
54/// ref_extended(|&a| {}); // a is &'static u32 because lifetime of a's value is 'static
55///
56/// ref_extended(|&a, &mut b| {}); // a is &'static u32 and b is &'static mut u32 because lifetime of a and b' value is 'static
57/// ```
58#[macro_export]
59macro_rules! ref_extended {
60    (|$(& $($var: ident)+ ),*| $body: expr) => {
61        ::ref_extended::run_abort_guarded(move || {
62            $(let ::ref_extended::extract_ref_name!($($var)*) = unsafe { ::ref_extended::extend_lifetime!($($var)*) };)*
63
64            {
65                $body
66            }
67        })
68    };
69}
70
71#[doc(hidden)]
72#[macro_export]
73macro_rules! extract_ref_name {
74    ($name: ident) => {
75        $name
76    };
77
78    (mut $name: ident) => {
79        $name
80    };
81}
82
83#[doc(hidden)]
84#[macro_export]
85macro_rules! extend_lifetime {
86    ($name: ident) => {
87        ::ref_extended::extend_ref(&$name)
88    };
89
90    (mut $name: ident) => {
91        ::ref_extended::extend_mut(&mut $name)
92    };
93}