• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // This file is part of ICU4X. For terms of use, please see the file
2 // called LICENSE at the top level of the ICU4X source tree
3 // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4 
5 use core::mem::{ManuallyDrop, MaybeUninit};
6 use core::ops::{Deref, DerefMut};
7 
8 /// This type is intended to be similar to the type `MaybeDangling<T>`
9 /// proposed in [RFC 3336].
10 ///
11 /// The effect of this is that in Rust's safety model, types inside here are not
12 /// expected to have any memory dependent validity properties (`dereferenceable`, `noalias`).
13 ///
14 /// See [#3696] for a testcase where `Yoke` fails under miri's field-retagging mode if not using
15 /// KindaSortaDangling.
16 ///
17 /// This has `T: 'static` since we don't need anything
18 /// else and we don't want to have to think (more) about variance over lifetimes or dropck.
19 ///
20 /// After [RFC 3336] lands we can use `MaybeDangling` instead.
21 ///
22 /// Note that a version of this type also exists publicly as the [`maybe_dangling`]
23 /// crate; which also exports a patched `ManuallyDrop` with similar semantics and
24 /// does not require `T: 'static`. Consider using this if you need something more general
25 /// and are okay with adding dependencies.
26 ///
27 /// [RFC 3336]: https://github.com/rust-lang/rfcs/pull/3336
28 /// [#3696]: https://github.com/unicode-org/icu4x/issues/3696
29 /// [`maybe_dangling`](https://docs.rs/maybe-dangling/0.1.0/maybe_dangling/struct.MaybeDangling.html)
30 #[repr(transparent)]
31 pub(crate) struct KindaSortaDangling<T: 'static> {
32     /// Safety invariant: This is always an initialized T, never uninit or other
33     /// invalid bit patterns. Its drop glue will execute during Drop::drop rather than
34     /// during the drop glue for KindaSortaDangling, which means that we have to be careful about
35     /// not touching the values as initialized during `drop` after that, but that's a short period of time.
36     dangle: MaybeUninit<T>,
37 }
38 
39 impl<T: 'static> KindaSortaDangling<T> {
40     #[inline]
new(dangle: T) -> Self41     pub(crate) const fn new(dangle: T) -> Self {
42         KindaSortaDangling {
43             dangle: MaybeUninit::new(dangle),
44         }
45     }
46     #[inline]
into_inner(self) -> T47     pub(crate) fn into_inner(self) -> T {
48         // Self has a destructor, we want to avoid having it be called
49         let manual = ManuallyDrop::new(self);
50         // Safety:
51         // We can call assume_init_read() due to the library invariant on this type,
52         // however since it is a read() we must be careful about data duplication.
53         // The only code using `self` after this is the drop glue, which we have disabled via
54         // the ManuallyDrop.
55         unsafe { manual.dangle.assume_init_read() }
56     }
57 }
58 
59 impl<T: 'static> Deref for KindaSortaDangling<T> {
60     type Target = T;
61     #[inline]
deref(&self) -> &T62     fn deref(&self) -> &T {
63         // Safety: Due to the safety invariant on `dangle`, it is guaranteed to be always
64         // initialized as deref is never called during drop.
65         unsafe { self.dangle.assume_init_ref() }
66     }
67 }
68 
69 impl<T: 'static> DerefMut for KindaSortaDangling<T> {
70     #[inline]
deref_mut(&mut self) -> &mut T71     fn deref_mut(&mut self) -> &mut T {
72         // Safety: Due to the safety invariant on `dangle`, it is guaranteed to be always
73         // initialized as deref_mut is never called during drop.
74         unsafe { self.dangle.assume_init_mut() }
75     }
76 }
77 
78 impl<T: 'static> Drop for KindaSortaDangling<T> {
79     #[inline]
drop(&mut self)80     fn drop(&mut self) {
81         // Safety: We are reading and dropping a valid initialized T.
82         //
83         // As `drop_in_place()` is a `read()`-like duplication operation we must be careful that the original value isn't
84         // used afterwards. It won't be because this is drop and the only
85         // code that will run after this is `self`'s drop glue, and that drop glue is empty
86         // because MaybeUninit has no drop.
87         //
88         // We use `drop_in_place()` instead of `let _ = ... .assume_init_read()` to avoid creating a move
89         // of the inner `T` (without `KindaSortaDangling` protection!) type into a local -- we don't want to
90         // assert any of `T`'s memory-related validity properties here.
91         unsafe {
92             self.dangle.as_mut_ptr().drop_in_place();
93         }
94     }
95 }
96