1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
//! A value that may or may not exist.
use ::core::{hint::unreachable_unchecked, ptr::addr_of_mut};
use ::mischief::{In, Region, Slot};
use ::ptr_meta::Pointee;
use ::raw_enum_macro::raw_enum;
use ::situ::DropRaw;
use crate::{Emplace, EmplaceExt, Move, Portable};
/// A relative counterpart to `Option`.
#[derive(DropRaw, Move, Portable)]
#[rel_core = "crate"]
#[repr(u8)]
#[raw_enum]
pub enum RelOption<T> {
/// No value.
None,
/// Some value of type `T`.
Some(T),
}
// SAFETY:
// - `emplaced_meta` returns `()`, the only valid metadata for `Sized` types.
// - `emplace_unsized_unchecked` initializes its `out` parameter by always
// setting the discriminant and additionally emplacing a value for the `Some`
// variant.
unsafe impl<T: DropRaw, E, R: Region> Emplace<RelOption<T>, R> for Option<E>
where
E: Emplace<T, R>,
{
fn emplaced_meta(&self) -> <RelOption<T> as Pointee>::Metadata {}
unsafe fn emplace_unsized_unchecked(
self,
out: In<Slot<'_, RelOption<T>>, R>,
) {
let raw_out = raw_rel_option(out.ptr().as_ptr());
let out_discriminant = raw_rel_option_discriminant(raw_out);
match self {
// SAFETY: `raw_rel_option_discriminant` guarantees that the pointer
// it returns is properly aligned and valid for writes.
None => unsafe {
out_discriminant.write(RawRelOptionDiscriminant::None);
},
Some(emplacer) => {
// SAFETY: `raw_rel_option_discriminant` guarantees that the
// pointer it returns is properly aligned and valid for writes.
unsafe {
out_discriminant.write(RawRelOptionDiscriminant::Some);
}
match raw_rel_option_variant(raw_out) {
RawRelOptionVariants::Some(out_ptr) => {
let value_ptr = addr_of_mut!((*out_ptr).1);
// SAFETY:
// - `value_ptr` is a pointer into `out`, so it is
// non-null, properly aligned, and valid for reads and
// writes.
// - `value_ptr` is a disjoint borrow of `out`, which is
// guaranteed not to alias any other accessible
// references, so the returned `Slot` will not either.
let slot = unsafe { Slot::new_unchecked(value_ptr) };
// SAFETY: `value_ptr` is a pointer into `out`, which is
// contained in `R`, so `value_ptr` must be contained in
// `R` as well.
let slot = unsafe { In::new_unchecked(slot) };
emplacer.emplace(slot);
}
// SAFETY: We wrote the `Some` discriminant to
// `out_discriminant` so it must be the `Some` variant.
_ => unsafe { unreachable_unchecked() },
}
}
}
}
}