pin_macros/
lib.rs

1use std::mem::{self, MaybeUninit};
2
3/// Since `&mut MaybeUninit<T>` is writable, we are allowed to perform the
4/// following call, which is unsafe:
5/// ```
6/// mem::take(transmute_maybe_uninit(ptr), MaybeUninit::uninit());
7/// ```
8pub unsafe fn transmute_maybe_uninit<T>(ptr: &mut T) -> &mut MaybeUninit<T> {
9    mem::transmute(ptr)
10}
11
12/// Initializes owned immovable value on stack.
13#[macro_export]
14macro_rules! pin_new {
15    ($varn:ident: $vart:ty = $methodn:ident($($arg:expr),* $(,)?)) => {
16        let mut __uninit = std::mem::MaybeUninit::<$vart>::uninit();
17        let __uninit_ptr = std::pin::pin!(__uninit);
18        let $varn = <$vart>::init(__uninit_ptr, $($($arg),*)?);
19    };
20    (mut $varn:ident: $vart:ty = $methodn:ident($($arg:expr),* $(,)?)) => {
21        let mut __uninit = std::mem::MaybeUninit::<$vart>::uninit();
22        let __uninit_ptr = std::pin::pin!(__uninit);
23        let mut $varn = <$vart>::init(__uninit_ptr, $($($arg),*)?);
24    };
25}
26/// Defines `Self::init` method, a replacement of the `Self::new` method.
27#[macro_export]
28macro_rules! pin_init {
29    ($v:vis fn $name:ident<$a:lifetime>($this:ident $(, $($argn:ident: $argt:ty),+)? $(,)?) $blk:block) => {
30        $v fn $name(
31            mut __uninit_ptr: std::pin::Pin<&$a mut std::mem::MaybeUninit<Self>>,
32            $($($argn: $argt)+)?
33        ) -> std::pin::Pin<&$a mut Self> {
34            let __init_ptr = unsafe { __uninit_ptr.as_mut().get_unchecked_mut().as_mut_ptr() };
35
36            /// Clones the potential result of this method. Should be used
37            /// Only to speculatively obtain pointers lying inside `Self`.
38            macro_rules! pin_init_clone {
39                () => {
40                    unsafe { std::pin::Pin::new_unchecked(&mut *__init_ptr) }
41                };
42            }
43            /// Gets `Pin<&mut MaybeUninit<F>>`, where `F` — owned immovable type.
44            macro_rules! pin_init_field {
45                ($fieldn:ident: $fieldt:ty) => {
46                    unsafe { std::pin::Pin::new_unchecked($crate::transmute_maybe_uninit(&mut (*__init_ptr).$fieldn)) }
47                };
48            }
49
50            let $this = unsafe { &mut *__init_ptr };
51            $blk;
52            unsafe { std::pin::Pin::new_unchecked($this) }
53        }
54    };
55}
56/// Generic utility for initializing optional fields of an immovable value
57/// after value's primary initialization. Rules summaries:
58/// 1. Initializes field of owned immovable type;
59/// 2. Initializes self-referencing field from an array of already initialized
60/// field value references;
61/// 3. A special simpliest case for the 2nd rule.
62#[macro_export]
63macro_rules! pin_field_init {
64    ($fieldt:ty: $methodn:ident($this:ident.$fieldn:ident $(, $($arg:expr)+)? $(,)?)) => {
65        unsafe {
66            let __field_ptr = &mut $this.as_mut().get_unchecked_mut().$fieldn as *mut Option<$fieldt>;
67            *__field_ptr = Some(std::mem::MaybeUninit::uninit().assume_init());
68
69            match &mut *__field_ptr {
70                Some(__field) => {
71                    let __pinned_field = std::pin::Pin::new_unchecked($crate::transmute_maybe_uninit(__field));
72                    <$fieldt>::$methodn(__pinned_field, $($($arg)+)?);
73                },
74                None => unreachable!(),
75            }
76        }
77    };
78    ($this:ident: |$($srcfield:ident),+ => $dstfield:ident| $fieldv:expr) => {{
79        let __this_ptr = unsafe { $this.as_mut().get_unchecked_mut() as *mut Self };
80        $(let $srcfield = unsafe { &mut (*__this_ptr).$srcfield };)+
81        let __dst_ptr = unsafe { &mut (*__this_ptr).$dstfield };
82        __dst_ptr.replace($fieldv)
83    }};
84}
85/// Defines a `Pin<&mut F>` getter, where `F` — field type. Use on owned
86/// immovable values only.
87#[macro_export]
88macro_rules! field_pin {
89    ($name:ident: $type:ty) => {
90        fn $name(self: std::pin::Pin<&mut Self>) -> std::pin::Pin<&mut $type> {
91            unsafe { self.map_unchecked_mut(|this| &mut this.$name) }
92        }
93    }
94}
95/// Defines a `&mut F` getter, where `F` — field type.
96#[macro_export]
97macro_rules! field_unpin {
98    ($name:ident: $type:ty) => {
99        fn $name(self: std::pin::Pin<&mut Self>) -> &mut $type {
100            unsafe { self.map_unchecked_mut(|this| &mut this.$name).get_mut() }
101        }
102    };
103}