use core::fmt;
use core::mem;
#[cfg(feature = "enable-serde")]
use serde_derive::{Deserialize, Serialize};
pub trait ReservedValue {
fn reserved_value() -> Self;
fn is_reserved_value(&self) -> bool;
}
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
#[repr(transparent)]
pub struct PackedOption<T: ReservedValue>(T);
impl<T: ReservedValue> PackedOption<T> {
pub fn is_none(&self) -> bool {
self.0.is_reserved_value()
}
pub fn is_some(&self) -> bool {
!self.0.is_reserved_value()
}
pub fn expand(self) -> Option<T> {
if self.is_none() { None } else { Some(self.0) }
}
pub fn map<U, F>(self, f: F) -> Option<U>
where
F: FnOnce(T) -> U,
{
self.expand().map(f)
}
#[track_caller]
pub fn unwrap(self) -> T {
self.expand().unwrap()
}
#[track_caller]
pub fn expect(self, msg: &str) -> T {
self.expand().expect(msg)
}
pub fn take(&mut self) -> Option<T> {
mem::replace(self, None.into()).expand()
}
}
impl<T: ReservedValue> Default for PackedOption<T> {
fn default() -> Self {
Self(T::reserved_value())
}
}
impl<T: ReservedValue> From<T> for PackedOption<T> {
fn from(t: T) -> Self {
debug_assert!(
!t.is_reserved_value(),
"Can't make a PackedOption from the reserved value."
);
Self(t)
}
}
impl<T: ReservedValue> From<Option<T>> for PackedOption<T> {
fn from(opt: Option<T>) -> Self {
match opt {
None => Self::default(),
Some(t) => t.into(),
}
}
}
impl<T: ReservedValue> From<PackedOption<T>> for Option<T> {
fn from(packed: PackedOption<T>) -> Option<T> {
packed.expand()
}
}
impl<T> fmt::Debug for PackedOption<T>
where
T: ReservedValue + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.is_none() {
write!(f, "None")
} else {
write!(f, "Some({:?})", self.0)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, PartialEq, Eq)]
struct NoC(u32);
impl ReservedValue for NoC {
fn reserved_value() -> Self {
NoC(13)
}
fn is_reserved_value(&self) -> bool {
self.0 == 13
}
}
#[test]
fn moves() {
let x = NoC(3);
let somex: PackedOption<NoC> = x.into();
assert!(!somex.is_none());
assert_eq!(somex.expand(), Some(NoC(3)));
let none: PackedOption<NoC> = None.into();
assert!(none.is_none());
assert_eq!(none.expand(), None);
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct Ent(u32);
impl ReservedValue for Ent {
fn reserved_value() -> Self {
Ent(13)
}
fn is_reserved_value(&self) -> bool {
self.0 == 13
}
}
#[test]
fn copies() {
let x = Ent(2);
let some: PackedOption<Ent> = x.into();
assert_eq!(some.expand(), x.into());
assert_eq!(some, x.into());
}
}