use crate::config::KeyConfig;
use crate::key_piece::KeyPiece;
use crate::parity::{Even, Odd};
use core::fmt;
use core::mem::ManuallyDrop;
use core::ptr;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Parity<G: KeyPiece, T, U> {
Odd(Odd<G>, T),
Even(Even<G>, U),
}
union Value<T, U> {
odd: ManuallyDrop<T>,
even: ManuallyDrop<U>,
}
pub struct Slot<G: KeyPiece, T, U> {
generation: G,
value: Value<T, U>,
}
impl<G: KeyPiece, T, U> Slot<G, T, U> {
#[inline]
pub fn new(parity: Parity<G, T, U>) -> Self {
match parity {
Parity::Odd(generation, value) => Self::new_odd(generation, value),
Parity::Even(generation, value) => Self::new_even(generation, value),
}
}
#[inline]
pub fn new_odd(generation: Odd<G>, value: T) -> Self {
Self {
generation: G::from_non_zero(generation.get()),
value: Value {
odd: ManuallyDrop::new(value),
},
}
}
#[inline]
pub fn new_even(generation: Even<G>, value: U) -> Self {
Self {
generation: generation.get(),
value: Value {
even: ManuallyDrop::new(value),
},
}
}
#[inline]
pub fn generation(&self) -> G {
self.generation
}
#[inline]
pub fn is_odd(&self) -> bool {
self.generation.is_odd()
}
#[inline]
pub fn is_even(&self) -> bool {
!self.generation.is_odd()
}
#[inline]
pub fn as_parity(&self) -> Parity<G, &T, &U> {
unsafe {
if self.is_odd() {
Parity::Odd(Odd::new_unchecked(self.generation), &self.value.odd)
} else {
Parity::Even(Even::new_unchecked(self.generation), &self.value.even)
}
}
}
#[inline]
pub fn as_parity_mut(&mut self) -> Parity<G, &mut T, &mut U> {
unsafe {
if self.is_odd() {
Parity::Odd(Odd::new_unchecked(self.generation), &mut self.value.odd)
} else {
Parity::Even(Even::new_unchecked(self.generation), &mut self.value.even)
}
}
}
#[inline]
pub fn into_parity(self) -> Parity<G, T, U> {
let mut slot = ManuallyDrop::new(self);
unsafe {
if slot.is_odd() {
Parity::Odd(
Odd::new_unchecked(slot.generation),
ManuallyDrop::take(&mut slot.value.odd),
)
} else {
Parity::Even(
Even::new_unchecked(slot.generation),
ManuallyDrop::take(&mut slot.value.even),
)
}
}
}
#[inline]
pub fn get_odd(&self, generation: Odd<G>) -> Option<&T> {
if self.generation == G::from_non_zero(generation.get()) {
Some(unsafe { &self.value.odd })
} else {
None
}
}
#[inline]
pub fn get_odd_mut(&mut self, generation: Odd<G>) -> Option<&mut T> {
if self.generation == G::from_non_zero(generation.get()) {
Some(unsafe { &mut self.value.odd })
} else {
None
}
}
#[inline]
pub fn into_odd(self, generation: Odd<G>) -> Result<T, Self> {
if self.generation == G::from_non_zero(generation.get()) {
let mut slot = ManuallyDrop::new(self);
Ok(unsafe { ManuallyDrop::take(&mut slot.value.odd) })
} else {
Err(self)
}
}
#[inline]
pub fn get_even(&self, generation: Even<G>) -> Option<&U> {
if self.generation == generation.get() {
Some(unsafe { &self.value.even })
} else {
None
}
}
#[inline]
pub fn get_even_mut(&mut self, generation: Even<G>) -> Option<&mut U> {
if self.generation == generation.get() {
Some(unsafe { &mut self.value.even })
} else {
None
}
}
#[inline]
pub fn into_even(self, generation: Even<G>) -> Result<U, Self> {
if self.generation == generation.get() {
let mut slot = ManuallyDrop::new(self);
Ok(unsafe { ManuallyDrop::take(&mut slot.value.even) })
} else {
Err(self)
}
}
#[inline]
pub fn replace(&mut self, parity: Parity<G, T, U>) -> Parity<G, T, U> {
match parity {
Parity::Odd(generation, value) => self.set_odd(generation, value),
Parity::Even(generation, value) => self.set_even(generation, value),
}
}
#[inline]
pub fn set_odd(&mut self, generation: Odd<G>, value: T) -> Parity<G, T, U> {
let old = unsafe { ptr::read(self).into_parity() };
self.generation = G::from_non_zero(generation.get());
self.value.odd = ManuallyDrop::new(value);
old
}
#[inline]
pub fn set_even(&mut self, generation: Even<G>, value: U) -> Parity<G, T, U> {
let old = unsafe { ptr::read(self).into_parity() };
self.generation = generation.get();
self.value.even = ManuallyDrop::new(value);
old
}
#[inline]
pub unsafe fn replace_odd_unchecked(&mut self, generation: Even<G>, value: U) -> T {
debug_assert!(self.is_odd());
let old = unsafe { ManuallyDrop::take(&mut self.value.odd) };
self.generation = generation.get();
self.value.even = ManuallyDrop::new(value);
old
}
#[inline]
pub unsafe fn replace_even_unchecked(&mut self, generation: Odd<G>, value: T) -> U {
debug_assert!(self.is_even());
let old = unsafe { ManuallyDrop::take(&mut self.value.even) };
self.generation = G::from_non_zero(generation.get());
self.value.odd = ManuallyDrop::new(value);
old
}
#[inline]
pub unsafe fn get_odd_unchecked(&self) -> &T {
debug_assert!(self.is_odd());
unsafe { &self.value.odd }
}
#[inline]
pub unsafe fn get_odd_unchecked_mut(&mut self) -> &mut T {
debug_assert!(self.is_odd());
unsafe { &mut self.value.odd }
}
#[inline]
pub unsafe fn get_even_unchecked(&self) -> &U {
debug_assert!(self.is_even());
unsafe { &self.value.even }
}
#[inline]
pub unsafe fn get_even_unchecked_mut(&mut self) -> &mut U {
debug_assert!(self.is_even());
unsafe { &mut self.value.even }
}
}
impl<G: KeyPiece, T, U> Drop for Slot<G, T, U> {
#[inline]
fn drop(&mut self) {
unsafe {
if self.is_odd() {
ManuallyDrop::drop(&mut self.value.odd);
} else {
ManuallyDrop::drop(&mut self.value.even);
}
}
}
}
impl<G: KeyPiece, T: Clone, U: Clone> Clone for Slot<G, T, U> {
#[inline]
fn clone(&self) -> Self {
match self.as_parity() {
Parity::Odd(generation, value) => Self::new_odd(generation, value.clone()),
Parity::Even(generation, value) => Self::new_even(generation, value.clone()),
}
}
}
impl<G: KeyPiece, T: fmt::Debug, U: fmt::Debug> fmt::Debug for Slot<G, T, U> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let value: &dyn fmt::Debug = match self.as_parity() {
Parity::Odd(_, value) => value,
Parity::Even(_, value) => value,
};
f.debug_struct("Slot")
.field("generation", &self.generation)
.field("value", value)
.finish()
}
}
mod sealed {
pub trait Sealed {}
}
pub trait GenSlotItem: sealed::Sealed {
type Value;
}
impl<G: KeyPiece, T, U> sealed::Sealed for Slot<G, T, U> {}
impl<G: KeyPiece, T, U> GenSlotItem for Slot<G, T, U> {
type Value = T;
}
pub trait SecondarySlotItem: sealed::Sealed {
type Value;
}
pub struct SecondarySlot<K: KeyConfig, T>(Slot<K::Gen, T, ()>);
impl<K: KeyConfig, T> SecondarySlot<K, T> {
#[inline]
pub fn empty() -> Self {
Self(Slot::new_even(Even::ZERO, ()))
}
#[inline]
pub fn new(generation: Odd<K::Gen>, value: T) -> Self {
Self(Slot::new_odd(generation, value))
}
#[inline]
pub fn get(&self) -> Option<(Odd<K::Gen>, &T)> {
match self.0.as_parity() {
Parity::Odd(generation, value) => Some((generation, value)),
Parity::Even(..) => None,
}
}
#[inline]
pub fn get_mut(&mut self) -> Option<(Odd<K::Gen>, &mut T)> {
match self.0.as_parity_mut() {
Parity::Odd(generation, value) => Some((generation, value)),
Parity::Even(..) => None,
}
}
#[inline]
pub fn get_odd(&self, generation: Odd<K::Gen>) -> Option<&T> {
self.0.get_odd(generation)
}
#[inline]
pub fn get_odd_mut(&mut self, generation: Odd<K::Gen>) -> Option<&mut T> {
self.0.get_odd_mut(generation)
}
#[inline]
pub(crate) fn generation(&self) -> K::Gen {
self.0.generation()
}
#[inline]
pub(crate) unsafe fn get_odd_unchecked(&self) -> &T {
unsafe { self.0.get_odd_unchecked() }
}
#[inline]
pub(crate) unsafe fn get_odd_unchecked_mut(&mut self) -> &mut T {
unsafe { self.0.get_odd_unchecked_mut() }
}
#[inline]
pub fn into_inner(self) -> Option<(Odd<K::Gen>, T)> {
match self.0.into_parity() {
Parity::Odd(generation, value) => Some((generation, value)),
Parity::Even(..) => None,
}
}
#[inline]
pub fn replace(&mut self, generation: Odd<K::Gen>, value: T) -> Option<T> {
match self.0.set_odd(generation, value) {
Parity::Odd(_, old) => Some(old),
Parity::Even(..) => None,
}
}
#[inline]
pub fn take(&mut self) -> Option<T> {
match self.0.set_even(Even::ZERO, ()) {
Parity::Odd(_, value) => Some(value),
Parity::Even(..) => None,
}
}
}
impl<K: KeyConfig, T: Clone> Clone for SecondarySlot<K, T> {
#[inline]
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<K: KeyConfig, T: fmt::Debug> fmt::Debug for SecondarySlot<K, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SecondarySlot")
.field("generation", &self.0.generation())
.field("value", &self.get().map(|(_, value)| value))
.finish()
}
}
impl<K: KeyConfig, T> sealed::Sealed for SecondarySlot<K, T> {}
impl<K: KeyConfig, T> SecondarySlotItem for SecondarySlot<K, T> {
type Value = T;
}