unsafe_binders/
unsafe.rs

1#![allow(unsafe_code)]
2use ::core::{
3    marker::PhantomData as PD,
4    pin::Pin,
5    ptr,
6};
7use ::maybe_dangling::{
8    ManuallyDrop as MD,
9};
10use ::higher_kinded_types::{
11    ForLt,
12};
13use crate::{
14    DropMarker::{self, DropMarkerKind},
15    ForLifetime,
16};
17
18pub trait Is {
19    type ItSelf : ?Sized;
20}
21
22impl<T : ?Sized> Is for T {
23    type ItSelf = Self;
24}
25
26trait NoAutoTraits {}
27
28/// Stable rust polyfill of [`unsafe<'lt> …` binders](https://hackmd.io/@compiler-errors/HkXwoBPaR),
29/// with a fixed arity of 1.
30///
31/// **Important note**: only use this _type_ name when wanting to access the associated functions.
32/// Most notably, the [`Unsafe::wrap_binder…()`][`Unsafe::wrap_binder_manually_drop()`]
33/// constructors.
34///
35/// Otherwise, the eponymous [`Unsafe![]`][`Unsafe!`] macro is to be used.
36///
37/// # Memory layout
38///
39/// This is a SemVer-guaranteed `#[repr(transparent)]` around its inner `T::Of<'_>` value.
40///
41/// ## Guarantees `unsafe` code may rely on
42///
43/// Given this, if you know that for some wrapper type `Coll`, `Coll<&'a str>` is sound to transmute
44/// into `Coll<&'b str>`, for instance **because the `Coll` wrapper type makes guarantees about its
45/// own layout and API based on that of the `<T>` generic type**, then it will be sound to transmute
46/// an `&'a str`-stemming `Coll<Unsafe<_, T>>` into a `Coll<T::Of<'b>>`. And so on for other
47/// `T::Of<'_>` lifetime-generic wrappee types.
48///
49///   - You should generally not need this, thanks to the various
50///     [`Self::unwrap_binder…()`][`Self::unwrap_binder()`] APIs already exposed by this type.
51///
52///   - In any "sane wrapper type" case, the property required herein is met.
53///
54///     But a counter-example would be the following:
55///
56///     <details class="custom"><summary><span class="summary-box"><span>Click to show</span></span></summary>
57///
58///     ```rust ,no_run
59///     # use ::unsafe_binders::prelude::*;
60///     #
61///     struct Helix<T: Shenanigans>(
62///         <T as Shenanigans>::Assoc,
63///     );
64///
65///     trait Shenanigans {
66///         type Assoc;
67///     }
68///
69///     impl Shenanigans for &str {
70///         type Assoc = bool;
71///     }
72///
73///     impl<D: DropMarkerKind> Shenanigans for Unsafe![D, &str] {
74///         type Assoc = u8;
75///     }
76///
77///     let helix: Helix<Unsafe![DropMarker::NoDropGlue, &str]> = Helix(2_u8);
78///     let Helix::<&str>(bool) = unsafe {
79///         ::core::mem::transmute::<
80///             Helix<Unsafe![<'any> &'any str]>,
81///             Helix<                 &'_ str >,
82///         >(helix)
83///     }; // UB! `bool: bool`'s bitpattern is `2_u8`!
84///     ```
85///
86///     </details>
87#[repr(transparent)]
88pub
89struct Unsafe<D : DropMarkerKind, T : ForLifetime> {
90    _p: PD<(fn() -> D, dyn NoAutoTraits)>,
91    value: MD<T::Of<'static>>,
92}
93
94impl<D : DropMarkerKind, T : ForLifetime> Drop for Unsafe<D, T> {
95    fn drop(&mut self) {
96        match <D as DropMarker::Sealed>::REIFIED {
97            DropMarker::Reified::MayDrop => {
98                unsafe {
99                    self.do_drop_in_place();
100                }
101            },
102            DropMarker::Reified::NoDropGlue => {},
103        }
104    }
105}
106
107unsafe
108impl<D : DropMarkerKind, T : ForLifetime> Send for Unsafe<D, T>
109where
110    for<'any> T::Of<'any> : Send,
111{}
112
113unsafe
114impl<D : DropMarkerKind, T : ForLifetime> Sync for Unsafe<D, T>
115where
116    for<'any> T::Of<'any> : Sync,
117{}
118
119/// Pinning projection (see [`Self::unwrap_binder_pin_mut()`]).
120impl<T : ForLifetime> Unpin for Unsafe<DropMarker::MayDrop, T>
121where
122    for<'any> T::Of<'any> : Unpin,
123{}
124
125/// **No** pinning projection whatsoever (unconditionally `Unpin`).
126impl<T : ForLifetime> Unpin for Unsafe<DropMarker::NoDropGlue, T> {}
127
128unsafe
129fn transmute_lt<'src, 'dst, T : ForLifetime>(src: T::Of<'src>) -> T::Of<'dst> {
130    unsafe {
131        ::core::mem::transmute(src)
132    }
133}
134
135/* Nobody cares about you, `{Ref,}UnwindSafe`. */
136
137impl<D : DropMarkerKind, T : ForLifetime> Unsafe<D, T> {
138    unsafe
139    fn new(value: T::Of<'_>) -> Self {
140        Self {
141            _p: PD,
142            value: MD::new(unsafe {
143                transmute_lt::<T>(value)
144            }),
145        }
146    }
147
148    /// Constructs an [`Unsafe<_, T>`][`Self`] with [`DropMarker::NoDropGlue`], _i.e._, with no drop
149    /// glue attached.
150    ///
151    /// <div class="warning">
152    ///
153    /// This means that a memory leak may ensue when
154    /// [`::core::mem::needs_drop::<T::Of<'_>>()`][1]
155    ///
156    /// </div>
157    ///
158    /// [1]: `::core::mem::needs_drop()`
159    ///
160    ///   - If so, you will need to call [`Self::manually_drop_in_place()`] eventually to avoid
161    ///     that.
162    ///
163    ///   - When <code>T::Of\<\'_\> : [Copy]</code>, consider using [`Self::wrap_binder_copy()`]
164    ///     instead.
165    #[doc(alias = "new")]
166    pub
167    fn wrap_binder_manually_drop(value: T::Of<'_>) -> Self
168    where
169        DropMarker::NoDropGlue : Is<ItSelf = D>,
170    {
171        unsafe { Self::new(value) }
172    }
173
174    /// Constructs an [`Unsafe<_, T>`][`Self`] with a [`DropMarker`] which does not matter. This is
175    /// fine since this requires <code>T::Of\<\'input\> : [Copy]</code> to hold, so there cannot be
176    /// actual drop glue.
177    #[doc(alias = "new")]
178    pub
179    fn wrap_binder_copy<'input>(value: T::Of<'input>) -> Self
180    where
181        DropMarker::NoDropGlue : Is<ItSelf = D>,
182        T::Of<'input> : Copy,
183    {
184        unsafe { Self::new(value) }
185    }
186
187    /// Constructs an [`Unsafe<_, T>`][`Self`] with [`DropMarker::MayDrop`], _i.e._, with drop
188    /// glue attached to it.
189    ///
190    /// <div class="warning">
191    ///
192    /// The very point of using this wrapper is to erase a lifetime, so this API can result in
193    /// access to dangling data (UAF) when misused!
194    ///
195    /// </div>
196    ///
197    /// # Safety
198    ///
199    /// It must be sound to call [`Self::manually_drop_in_place()`] when this instance is dropped /
200    /// goes out of scope. This soundness property is usually the result of immediately wrapping
201    /// this instance in an aptly-lifetime infected or properly self-referential struct.
202    ///
203    /// Moreover, it must be sound to access the inner value as long as this value lives. This
204    /// is indeed the case due to the existence of the scoped/existential-lifetime
205    /// [`Self::with_unwrapped_binder…()`][`Self::with_unwrapped_binder()`] APIs.
206    ///
207    ///   - A subtle corollary is that you can only relinquish owned access of this instance to
208    ///     an arbitrary API if you are fine with the `value` becoming `T::Of<'static>`.
209    ///
210    ///     Or phrased differently: you can only soundly call this constructor as an **owner** (who
211    ///     wraps the whole thing in a sound API). This is a very non-local `SAFETY` property much
212    ///     alike that of `Pin::new_unchecked()`.
213    #[doc(alias = "new")]
214    pub
215    unsafe
216    fn wrap_binder_with_drop_glue(value: T::Of<'_>) -> Self
217    where
218        DropMarker::MayDrop : Is<ItSelf = D>,
219    {
220        unsafe { Self::new(value) }
221    }
222
223    /// **By value,** imbue back the binder with a concrete `'lt` of your choice.
224    ///
225    /// # Safety
226    ///
227    /// Pick `'lt` wisely: it ought to match the original input lifetime used when doing
228    /// `Self::wrap_binder…()`, or something semantically equivalent.
229    ///
230    /// Using `'input` upon `Self::wrap_binder…()` construction and `'lt` here is tantamount
231    /// to having transmuted the `'input` lifetime to `'lt`.
232    pub
233    unsafe
234    fn unwrap_binder<'lt>(self) -> T::Of<'lt>
235    where
236        'lt : /* early-bound, turbofishable */,
237    {
238        let value = unsafe { MD::take(&mut (*MD::new(self)).value) };
239        unsafe {
240            transmute_lt::<T>(value)
241        }
242    }
243
244    /// **By `&`-reference,** imbue back the binder with a concrete `'lt` of your choice.
245    ///
246    /// # Safety
247    ///
248    /// Pick `'lt` wisely: it ought to match the original input lifetime used when doing
249    /// `Self::wrap_binder…()`, or something semantically equivalent.
250    ///
251    /// Using `'input` upon `Self::wrap_binder…()` construction and `'lt` here is tantamount
252    /// to having transmuted the `'input` lifetime to `'lt`.
253    pub
254    unsafe
255    fn unwrap_binder_ref<'r, 'lt>(&'r self) -> &'r T::Of<'lt>
256    where
257        'lt : /* early-bound, turbofishable */,
258        'r : /* needs to be early-bound for `'lt` to be turbofishable */,
259    {
260        let value = &self.value;
261        unsafe {
262            transmute_lt::<ForLt!(&'r T::Of<'_>)>(value)
263        }
264    }
265
266
267    /// **By `&mut`-reference,** imbue back the binder with a concrete `'lt` of your choice.
268    ///
269    /// # Safety
270    ///
271    /// Pick `'lt` wisely: it ought to match the original input lifetime used when doing
272    /// `Self::wrap_binder…()`, or something semantically equivalent.
273    ///
274    /// Using `'input` upon `Self::wrap_binder…()` construction and `'lt` here is tantamount
275    /// to having transmuted the `'input` lifetime to `'lt`.
276    pub
277    unsafe
278    fn unwrap_binder_mut<'r, 'lt>(&'r mut self) -> &'r mut T::Of<'lt>
279    where
280        'lt : /* early-bound, turbofishable */,
281        'r : /* needs to be early-bound for `'lt` to be turbofishable */,
282    {
283        let value = &mut self.value;
284        unsafe {
285            transmute_lt::<ForLt!(&'r mut T::Of<'_>)>(value)
286        }
287    }
288
289
290    /// **By `&pin mut`-reference,** imbue back the binder with a concrete `'lt` of your choice.
291    ///
292    /// This is effectively a pinning projection (on top of lifetime transmutation).
293    ///
294    /// # Safety
295    ///
296    /// Pick `'lt` wisely: it ought to match the original input lifetime used when doing
297    /// `Self::wrap_binder…()`, or something semantically equivalent.
298    ///
299    /// Using `'input` upon `Self::wrap_binder…()` construction and `'lt` here is tantamount
300    /// to having transmuted the `'input` lifetime to `'lt`.
301    pub
302    unsafe
303    fn unwrap_binder_pin_mut<'r, 'lt>(
304        self: Pin<&'r mut Self>,
305    ) -> Pin<&'r mut T::Of<'lt>>
306    where
307        'lt : /* early-bound, turbofishable */,
308        'r : /* needs to be early-bound for `'lt` to be turbofishable */,
309        DropMarker::MayDrop : Is<ItSelf = D>,
310    {
311        let value = unsafe {
312            self.map_unchecked_mut(|Self { value , ..}| -> &mut T::Of<'_> { value })
313        };
314        unsafe {
315            transmute_lt::<ForLt!(Pin<&'r mut T::Of<'_>>)>(value)
316        }
317    }
318
319    unsafe
320    fn do_drop_in_place(&mut self) {
321        unsafe {
322            ptr::drop_in_place::<T::Of<'_>>(self.unwrap_binder_mut());
323        }
324    }
325
326    /// Manually drop in place the `value` provided to [`Self::wrap_binder_manually_drop()`] (since
327    /// it would otherwise not be dropped).
328    ///
329    /// Note: this API is only available in the [`DropMarker::NoDropGlue`] case. If you nonetheless
330    /// wish to do this in the [`DropMarker::MayDrop`] case despite the resulting humongous risk of
331    /// double dropping, then do so the usual way, _i.e._, using [`::core::ptr::drop_in_place()`]
332    /// or your own [`::core::mem::ManuallyDrop::drop()`].
333    pub
334    unsafe
335    fn manually_drop_in_place(&mut self)
336    where
337        DropMarker::NoDropGlue : Is<ItSelf = D>,
338    {
339        unsafe {
340            self.do_drop_in_place();
341        }
342    }
343}
344
345/// Convenience non-`unsafe` APIs, courtesy of the `unsafe` promise provided by
346/// [`Unsafe::wrap_binder_with_drop_glue()`].
347///
348/// Uses a scoped API to emulate an existential lifetime.
349///
350/// # Example
351///
352/// ```rust
353/// use ::unsafe_binders::prelude::*;
354///
355/// let static_: &'static str = "Hello, World!";
356/// let erased: Unsafe![DropMarker::MayDrop, &str] = unsafe {
357///     // Safety: `&str` is covariant, and we have a `&'static str`, so we may
358///     // as well have a `&'any str`.
359///     Unsafe::wrap_binder_with_drop_glue(static_)
360/// };
361///
362/// // Safely access the value!
363/// erased.with_unwrapped_binder_ref(|&s| {
364///     assert_eq!(s, "Hello, World!");
365/// })
366/// ```
367impl<T : ForLifetime> Unsafe<DropMarker::MayDrop, T> {
368    pub
369    fn with_unwrapped_binder<R>(
370        self,
371        scope: impl FnOnce(T::Of<'_>) -> R,
372    ) -> R
373    {
374        scope(unsafe {
375            self.unwrap_binder::<'_>()
376        })
377    }
378
379    pub
380    fn with_unwrapped_binder_ref<'r, R>(
381        &'r self,
382        scope: impl FnOnce(&'r T::Of<'_>) -> R,
383    ) -> R
384    {
385        scope(unsafe {
386            self.unwrap_binder_ref::<'r, '_>()
387        })
388    }
389
390    pub
391    fn with_unwrapped_binder_mut<'r, R>(
392        &'r mut self,
393        scope: impl FnOnce(&'r mut T::Of<'_>) -> R,
394    ) -> R
395    {
396        scope(unsafe {
397            self.unwrap_binder_mut::<'r, '_>()
398        })
399    }
400}
401
402/// Convenience macro to _name_/express an `unsafe<'lt> …` type:
403///
404/// ```rust
405/// # {} /*
406/// Unsafe![<'lt> = …] // morally, `unsafe<'lt> …`
407/// // e.g.
408/// Unsafe![<'lt> = &'lt str] // morally, `unsafe<'lt> &'lt str`.
409/// # */
410/// ```
411///
412/// # Syntax
413///
414/// ```rust
415/// # {} /*
416/// Unsafe![
417///     $($DropMarker:ty, )? // if elided, it is left to be `_`-inferred.
418///
419///     // then, either:
420///     <$lt:lifetime> = $T:ty $(,)?
421///
422///     // or (lifetime-elision shorthand syntax):
423///     $T:ty // <- every `'_` or unnamed `&`-lifetime is deemed parametric.
424/// ]
425/// # */
426/// ```
427///
428///   - ### Lifetime-elision shorthand syntax
429///
430///     Similar to lifetime-elision in `fn` signatures (to be more precise, the elision of the
431///     return type of an `fn` pointer, item, or `Fn…` trait), the [`Unsafe!`] macro also allows for
432///     "inferring" which lifetime parameters are parametric simply by virtue of eliding them,
433///     be it explicitly (_via_ `'_`), or implicitly (unnamed-`&[mut]`).
434///
435///     <div class="warning">
436///
437///     Do note that this macro is not able to see through `elided_lifetimes_in_paths`.
438///
439///     </div>
440///
441/// # Example
442///
443/// ```rust
444/// use ::unsafe_binders::{DropMarker, Unsafe};
445///
446/// pub struct SelfReferential {
447///     full_name: String,
448///     first_name: Unsafe![DropMarker::NoDropGlue, <'this> &'this str],
449///                                                // using lifetime-elision shorthand syntax:
450///     last_name: Unsafe![DropMarker::NoDropGlue, &str],
451/// }
452///
453/// impl SelfReferential {
454///     pub fn new(full_name: String) -> Option<Self> {
455///         let (first_name, last_name) = full_name.split_once(" ")?;
456///         // erase the `&'full_name` lifetime:
457///         let first_name: Unsafe![_, &str] = Unsafe::wrap_binder_copy(first_name);
458///                                // shorthand syntax
459///         let last_name: Unsafe![&str] = Unsafe::wrap_binder_copy(last_name);
460///         Some(Self {
461///             full_name,
462///             first_name,
463///             last_name,
464///         })
465///     }
466///
467///     pub fn first_name<'r>(&'r self) -> &'r str {
468///         unsafe {
469///             self.first_name.unwrap_binder_ref::<'_, 'r>()
470///         }
471///     }
472///
473///     pub fn last_name<'r>(&'r self) -> &'r str {
474///         unsafe {
475///             self.last_name.unwrap_binder_ref::<'_, 'r>()
476///         }
477///     }
478/// }
479/// ```
480///
481/// <!-- rust-analyzer nudge
482/// ```rust ,ignore
483/// ඞUnsafe![];
484/// ```
485/// -->
486#[doc(hidden)] #[macro_export]
487macro_rules! ඞUnsafe {
488    (
489        <$lt:lifetime> $($T:tt)+
490    ) => (
491        $crate::Unsafe<_, $crate::ඞ::ForLt!(<$lt> = $($T)+)>
492    );
493
494    (
495        $DropMarker:ty,
496        <$lt:lifetime> $($T:tt)+
497    ) => (
498        $crate::Unsafe<$DropMarker, $crate::ඞ::ForLt!(<$lt> = $($T)+)>
499    );
500
501    (
502        $DropMarker:ty,
503        $($T:tt)+
504    ) => (
505        $crate::Unsafe<$DropMarker, $crate::ඞ::ForLt!($($T)+)>
506    );
507
508    (
509        $($T:tt)+
510    ) => (
511        $crate::Unsafe<_, $crate::ඞ::ForLt!($($T)+)>
512    );
513}
514#[doc(inline)]
515pub use ඞUnsafe as Unsafe;