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;