use core::hash::{Hash, Hasher};
use core::ops::{Deref, DerefMut};
use std::cmp::Ordering;
#[derive(Clone, Copy, Debug)]
#[repr(u8)]
pub enum ArchivedOption<T> {
None,
Some(T),
}
impl<T> ArchivedOption<T> {
pub fn ok_or<E>(self, err: E) -> Result<T, E> {
if let ArchivedOption::Some(x) = self {
Ok(x)
} else {
Err(err)
}
}
pub fn unwrap(self) -> T {
if let ArchivedOption::Some(value) = self {
value
} else {
panic!("called `ArchivedOption::unwrap()` on a `None` value")
}
}
pub fn unwrap_or(self, default: T) -> T {
if let ArchivedOption::Some(value) = self {
value
} else {
default
}
}
pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
if let ArchivedOption::Some(value) = self {
value
} else {
f()
}
}
pub fn is_none(&self) -> bool {
matches!(self, ArchivedOption::None)
}
pub fn is_some(&self) -> bool {
matches!(self, ArchivedOption::Some(_))
}
pub const fn as_ref(&self) -> Option<&T> {
if let ArchivedOption::Some(value) = self {
Some(value)
} else {
None
}
}
pub fn as_mut(&mut self) -> Option<&mut T> {
if let ArchivedOption::Some(value) = self {
Some(value)
} else {
None
}
}
pub fn get_or_insert(&mut self, v: T) -> &mut T {
self.get_or_insert_with(move || v)
}
pub fn get_or_insert_with<F: FnOnce() -> T>(&mut self, f: F) -> &mut T {
if let ArchivedOption::Some(value) = self {
value
} else {
*self = ArchivedOption::Some(f());
unsafe { self.as_mut().unwrap_unchecked() }
}
}
}
impl<T: Deref> ArchivedOption<T> {
pub fn as_deref(&self) -> Option<&<T as Deref>::Target> {
self.as_ref().map(Deref::deref)
}
}
impl<T: DerefMut> ArchivedOption<T> {
pub fn as_deref_mut(&mut self) -> Option<&mut <T as Deref>::Target> {
self.as_mut().map(DerefMut::deref_mut)
}
}
impl<T: Eq> Eq for ArchivedOption<T> {}
impl<T: Hash> Hash for ArchivedOption<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_ref().hash(state);
}
}
impl<T: Ord> Ord for ArchivedOption<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.as_ref().cmp(&other.as_ref())
}
}
impl<T: PartialEq> PartialEq for ArchivedOption<T> {
fn eq(&self, other: &Self) -> bool {
self.as_ref().eq(&other.as_ref())
}
}
impl<T: PartialOrd> PartialOrd for ArchivedOption<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.as_ref().partial_cmp(&other.as_ref())
}
}
impl<T, U: PartialOrd<T>> PartialOrd<Option<T>> for ArchivedOption<U> {
fn partial_cmp(&self, other: &Option<T>) -> Option<Ordering> {
match (self, other) {
(ArchivedOption::None, None) => Some(Ordering::Equal),
(ArchivedOption::None, Some(_)) => Some(Ordering::Less),
(ArchivedOption::Some(_), None) => Some(Ordering::Greater),
(ArchivedOption::Some(self_value), Some(other_value)) => {
self_value.partial_cmp(other_value)
}
}
}
}
impl<T, U: PartialEq<T>> PartialEq<Option<T>> for ArchivedOption<U> {
fn eq(&self, other: &Option<T>) -> bool {
if let ArchivedOption::Some(self_value) = self
&& let Some(other_value) = other
{
self_value.eq(other_value)
} else {
self.is_none() && other.is_none()
}
}
}
impl<T> From<T> for ArchivedOption<T> {
fn from(val: T) -> ArchivedOption<T> {
ArchivedOption::Some(val)
}
}
#[cfg(test)]
mod tests {
#[test]
fn partial_ord_option() {
use core::cmp::Ordering;
use super::ArchivedOption;
let a: ArchivedOption<u8> = ArchivedOption::Some(42);
let b = Some(42);
assert_eq!(Some(Ordering::Equal), a.partial_cmp(&b));
let a: ArchivedOption<u8> = ArchivedOption::Some(1);
let b = Some(2);
assert_eq!(Some(Ordering::Less), a.partial_cmp(&b));
let a: ArchivedOption<u8> = ArchivedOption::Some(2);
let b = Some(1);
assert_eq!(Some(Ordering::Greater), a.partial_cmp(&b));
}
}