konst/drop_flavor.rs
1//! Contains items for parameterizing types by whether they need dropping.
2//!
3//! Refer to [`DropFlavor`] for more details
4
5use core::mem::ManuallyDrop;
6
7mod sealed {
8 pub trait Sealed {}
9
10 impl Sealed for super::MayDrop {}
11 impl Sealed for super::NonDrop {}
12}
13
14/// For parameterizing types by whether they need dropping.
15///
16/// This trait is sealed, it's implemented by [`NonDrop`] and [`MayDrop`],
17/// it cannot be implemented by any other type.
18///
19/// # Motivation
20///
21/// The reason this whole module exists is to allow containers to
22/// need dropping only when the type they wrap doesn't need dropping.
23///
24/// # Example
25///
26/// As you can see here, to make the container drop conditionally, you need to have
27/// a `Foo` that wraps a `FooInner` in this particular way,
28/// and then define constructors for types that need dropping (what `of_drop` does here)
29/// and types that don't (what `of_copy` does here).
30///
31/// ```rust
32/// use konst::drop_flavor::{self, DropFlavor, MayDrop, NonDrop};
33///
34///
35/// const fn using_nondrop<T: Copy>(val: T) {
36/// let mut container = Container::of_copy(val);
37///
38/// let by_ref: &T = container.get();
39/// let by_mut: &mut T = container.get_mut();
40///
41/// // some code that does something useful with Container
42/// }
43///
44/// struct Container<T, D: DropFlavor>(D::Wrap<ContainerInner<T>>);
45///
46/// struct ContainerInner<T>(T);
47///
48/// impl<T> Container<T, NonDrop> {
49/// const fn of_copy(val: T) -> Self
50/// where
51/// T: Copy
52/// {
53/// Container(drop_flavor::wrap(ContainerInner(val)))
54/// }
55/// }
56/// impl<T> Container<T, MayDrop> {
57/// const fn of_drop(val: T) -> Self {
58/// Container(drop_flavor::wrap(ContainerInner(val)))
59/// }
60/// }
61///
62/// impl<T, D: DropFlavor> Container<T, D> {
63/// const fn get(&self) -> &T {
64/// &drop_flavor::as_inner::<D, _>(&self.0).0
65/// }
66/// const fn get_mut(&mut self) -> &mut T {
67/// &mut drop_flavor::as_inner_mut::<D, _>(&mut self.0).0
68/// }
69/// }
70///
71/// impl<T> Drop for ContainerInner<T> {
72/// // only ran if `Container<T, D>` is `Container<T, MayDrop>`
73/// fn drop(&mut self) {
74/// println!("dropping {}!", std::any::type_name::<T>());
75/// }
76/// }
77///
78/// ```
79///
80/// Attempting to construct `Container` above with `of_drop` instead of `of_copy`
81/// produces this compile-time error:
82/// ```text
83/// error[E0493]: destructor of `Container<T, MayDrop>` cannot be evaluated at compile-time
84/// --> konst/src/drop_flavor.rs:25:13
85/// |
86/// 10 | let mut container = Container::of_drop(val);
87/// | ^^^^^^^^^ the destructor for this type cannot be evaluated in constant functions
88/// ...
89/// 13 | }
90/// | - value is dropped here
91/// ```
92///
93///
94pub trait DropFlavor: sealed::Sealed + 'static + Sized {
95 /// This can be either:
96 /// - if `Self == NonDrop`: `ManuallyDrop<T>`
97 /// - if `Self == MayDrop`: `T`
98 type Wrap<T>: DropFlavorWrapper<T, Flavor = Self>;
99}
100
101/// Type argument for types that may need dropping.
102#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
103pub enum MayDrop {}
104
105impl DropFlavor for MayDrop {
106 type Wrap<T> = T;
107}
108
109/// Type argument for types that don't need dropping-
110#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
111pub enum NonDrop {}
112
113impl DropFlavor for NonDrop {
114 type Wrap<T> = ManuallyDrop<T>;
115}
116
117/// Trait for the types that [`DropFlavor::Wrap`] can produce.
118pub trait DropFlavorWrapper<T> {
119 /// The DropFlavor that [`wrap`]s `T` into `Self`
120 type Flavor: DropFlavor<Wrap<T> = Self>;
121}
122
123impl<T> DropFlavorWrapper<T> for T {
124 type Flavor = MayDrop;
125}
126
127impl<T> DropFlavorWrapper<T> for ManuallyDrop<T> {
128 type Flavor = NonDrop;
129}
130
131/// Unwraps [`D::Wrap<T>`](DropFlavor::Wrap) into `T`
132///
133/// # Example
134///
135/// ```rust
136/// use konst::drop_flavor::{self, DropFlavor, MayDrop, NonDrop};
137///
138/// use std::mem::ManuallyDrop;
139///
140///
141/// assert_eq!(unwrap_foo::<_, MayDrop>(Foo(10)), 10);
142///
143/// assert_eq!(unwrap_foo::<_, NonDrop>(Foo(ManuallyDrop::new(10))), 10);
144///
145///
146/// fn unwrap_foo<T, D: DropFlavor>(foo: Foo<T, D>) -> T {
147/// drop_flavor::unwrap::<D, _>(foo.0)
148/// }
149///
150/// struct Foo<T, D: DropFlavor>(D::Wrap<T>);
151/// ```
152///
153pub const fn unwrap<D, T>(wrapper: D::Wrap<T>) -> T
154where
155 D: DropFlavor,
156{
157 // SAFETY: because DropFlavor is sealed, `D::Wrap<T>` is transmutable to `T`
158 // because it's either `T` or a `ManuallyDrop<T>`
159 unsafe { crate::__priv_transmute!(D::Wrap<T>, T, wrapper) }
160}
161
162/// Coerces [`&D::Wrap<T>`](DropFlavor::Wrap) into its contained `&T`
163///
164/// # Example
165///
166/// ```rust
167/// use konst::drop_flavor::{self, DropFlavor, MayDrop, NonDrop};
168///
169/// use std::mem::ManuallyDrop;
170///
171///
172/// assert_eq!(foo_as_inner::<_, MayDrop>(&Foo(10)), &10);
173///
174/// assert_eq!(foo_as_inner::<_, NonDrop>(&Foo(ManuallyDrop::new(10))), &10);
175///
176///
177/// fn foo_as_inner<T, D: DropFlavor>(foo: &Foo<T, D>) -> &T {
178/// drop_flavor::as_inner::<D, _>(&foo.0)
179/// }
180///
181/// struct Foo<T, D: DropFlavor>(D::Wrap<T>);
182/// ```
183///
184pub const fn as_inner<D, T>(wrapper: &D::Wrap<T>) -> &T
185where
186 D: DropFlavor,
187{
188 // SAFETY: because DropFlavor is sealed, `&D::Wrap<T>` is castable to `&T`
189 // because it's either `&T` or a `&ManuallyDrop<T>`
190 unsafe { &*(wrapper as *const D::Wrap<T> as *const T) }
191}
192
193/// Coerces [`&mut D::Wrap<T>`](DropFlavor::Wrap) into its contained `&mut T`
194///
195/// # Example
196///
197/// ```rust
198/// use konst::drop_flavor::{self, DropFlavor, MayDrop, NonDrop};
199///
200/// use std::mem::ManuallyDrop;
201///
202///
203/// assert_eq!(foo_as_inner_mut::<_, MayDrop>(&mut Foo(10)), &mut 10);
204///
205/// assert_eq!(foo_as_inner_mut::<_, NonDrop>(&mut Foo(ManuallyDrop::new(10))), &mut 10);
206///
207///
208/// fn foo_as_inner_mut<T, D: DropFlavor>(foo: &mut Foo<T, D>) -> &mut T {
209/// drop_flavor::as_inner_mut::<D, _>(&mut foo.0)
210/// }
211///
212/// struct Foo<T, D: DropFlavor>(D::Wrap<T>);
213/// ```
214///
215pub const fn as_inner_mut<D, T>(wrapper: &mut D::Wrap<T>) -> &mut T
216where
217 D: DropFlavor,
218{
219 // SAFETY: because DropFlavor is sealed, `&mut D::Wrap<T>` is castable to `&mut T`
220 // because it's either `&mut T` or a `&mut ManuallyDrop<T>`
221 unsafe { &mut *(wrapper as *mut D::Wrap<T> as *mut T) }
222}
223
224/// Converts `T` into either `T` or `ManuallyDrop<T>` as determined by the return type.
225///
226/// # Example
227///
228/// ```rust
229/// use konst::drop_flavor::{self, DropFlavor, MayDrop, NonDrop};
230///
231/// use std::mem::ManuallyDrop;
232///
233///
234/// assert_eq!(make_foo::<MayDrop, _>(3), Foo(3));
235///
236/// assert_eq!(make_foo::<NonDrop, _>(5), Foo(ManuallyDrop::new(5)));
237///
238///
239/// const fn make_foo<D: DropFlavor, T>(val: T) -> Foo<D, T> {
240/// Foo(drop_flavor::wrap(val))
241/// }
242///
243/// #[derive(Debug, PartialEq, Eq)]
244/// struct Foo<D: DropFlavor, T>(D::Wrap<T>);
245/// ```
246///
247pub const fn wrap<W, T>(wrapper: T) -> W
248where
249 W: DropFlavorWrapper<T>,
250{
251 // SAFETY: `T` is transmutable to `W`
252 // because it's either `T` or a `ManuallyDrop<T>`
253 unsafe { crate::__priv_transmute!(T, W, wrapper) }
254}