#![forbid(unsafe_code)]
use core::fmt::{Debug, Display, Formatter};
pub enum OptionABCD<A, B, C, D> {
A(A),
B(B),
C(C),
D(D),
}
impl<T> OptionABCD<T, T, T, T> {
pub fn take(self) -> T {
match self {
OptionABCD::A(value) => value,
OptionABCD::B(value) => value,
OptionABCD::C(value) => value,
OptionABCD::D(value) => value,
}
}
}
impl<A, B, C, D> OptionABCD<A, B, C, D> {
pub fn as_ref(&self) -> OptionABCD<&A, &B, &C, &D> {
match self {
OptionABCD::A(value) => OptionABCD::A(&value),
OptionABCD::B(value) => OptionABCD::B(&value),
OptionABCD::C(value) => OptionABCD::C(&value),
OptionABCD::D(value) => OptionABCD::D(&value),
}
}
pub fn a(&self) -> Option<&A> {
match self {
OptionABCD::A(value) => Some(value),
_ => None,
}
}
pub fn b(&self) -> Option<&B> {
match self {
OptionABCD::B(value) => Some(value),
_ => None,
}
}
pub fn c(&self) -> Option<&C> {
match self {
OptionABCD::C(value) => Some(value),
_ => None,
}
}
pub fn d(&self) -> Option<&D> {
match self {
OptionABCD::D(value) => Some(value),
_ => None,
}
}
}
impl<A: Debug, B: Debug, C: Debug, D: Debug> OptionABCD<A, B, C, D> {
pub fn unwrap_a(self) -> A {
match self {
OptionABCD::A(value) => value,
_ => panic!("expected OptionABCD::A(_) but found {:?}", self),
}
}
pub fn unwrap_b(self) -> B {
match self {
OptionABCD::B(value) => value,
_ => panic!("expected OptionABCD::B(_) but found {:?}", self),
}
}
pub fn unwrap_c(self) -> C {
match self {
OptionABCD::C(value) => value,
_ => panic!("expected OptionABCD::C(_) but found {:?}", self),
}
}
pub fn unwrap_d(self) -> D {
match self {
OptionABCD::D(value) => value,
_ => panic!("expected OptionABCD::D(_) but found {:?}", self),
}
}
}
impl<A: Clone, B: Clone, C: Clone, D: Clone> Clone for OptionABCD<A, B, C, D> {
fn clone(&self) -> Self {
match self {
OptionABCD::A(value) => OptionABCD::A(value.clone()),
OptionABCD::B(value) => OptionABCD::B(value.clone()),
OptionABCD::C(value) => OptionABCD::C(value.clone()),
OptionABCD::D(value) => OptionABCD::D(value.clone()),
}
}
}
impl<A: Debug, B: Debug, C: Debug, D: Debug> Debug for OptionABCD<A, B, C, D> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
OptionABCD::A(value) => write!(f, "OptionABCD::A({:?})", value),
OptionABCD::B(value) => write!(f, "OptionABCD::B({:?})", value),
OptionABCD::C(value) => write!(f, "OptionABCD::C({:?})", value),
OptionABCD::D(value) => write!(f, "OptionABCD::D({:?})", value),
}
}
}
impl<A: Display, B: Display, C: Display, D: Display> Display for OptionABCD<A, B, C, D> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
OptionABCD::A(value) => write!(f, "{}", value),
OptionABCD::B(value) => write!(f, "{}", value),
OptionABCD::C(value) => write!(f, "{}", value),
OptionABCD::D(value) => write!(f, "{}", value),
}
}
}
impl<A: PartialEq, B: PartialEq, C: PartialEq, D: PartialEq> PartialEq for OptionABCD<A, B, C, D> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(OptionABCD::A(value), OptionABCD::A(other)) if value == other => true,
(OptionABCD::B(value), OptionABCD::B(other)) if value == other => true,
(OptionABCD::C(value), OptionABCD::C(other)) if value == other => true,
(OptionABCD::D(value), OptionABCD::D(other)) if value == other => true,
_ => false,
}
}
}
impl<A: PartialEq, B: PartialEq, C: PartialEq, D: PartialEq> Eq for OptionABCD<A, B, C, D> {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test() {
let a: OptionABCD<bool, u8, &'static str, usize> = OptionABCD::A(true);
let b: OptionABCD<bool, u8, &'static str, usize> = OptionABCD::B(42);
let c: OptionABCD<bool, u8, &'static str, usize> = OptionABCD::C("s1");
let d: OptionABCD<bool, u8, &'static str, usize> = OptionABCD::D(7usize);
let _: OptionABCD<&bool, &u8, &&'static str, &usize> = a.as_ref();
let _: &u8 = b.as_ref().unwrap_b();
let _: &&'static str = c.as_ref().unwrap_c();
let _: &usize = d.as_ref().unwrap_d();
assert_eq!(true, *(a.as_ref().unwrap_a()));
assert_eq!(42u8, *(b.as_ref().unwrap_b()));
assert_eq!("s1", *(c.as_ref().unwrap_c()));
assert_eq!(7usize, *(d.as_ref().unwrap_d()));
assert_eq!(true, *(a.a().unwrap()));
assert_eq!(None, a.b());
assert_eq!(None, a.c());
assert_eq!(None, a.d());
assert_eq!(None, b.a());
assert_eq!(42u8, *(b.b().unwrap()));
assert_eq!(None, b.c());
assert_eq!(None, b.d());
assert_eq!(None, c.a());
assert_eq!(None, c.b());
assert_eq!("s1", *(c.c().unwrap()));
assert_eq!(None, c.d());
assert_eq!(None, d.a());
assert_eq!(None, d.b());
assert_eq!(None, d.c());
assert_eq!(7usize, *(d.d().unwrap()));
assert_eq!("OptionABCD::A(true)", format!("{:?}", a));
assert_eq!("OptionABCD::B(42)", format!("{:?}", b));
assert_eq!("OptionABCD::C(\"s1\")", format!("{:?}", c));
assert_eq!("OptionABCD::D(7)", format!("{:?}", d));
assert_eq!("true", format!("{}", a));
assert_eq!("42", format!("{}", b));
assert_eq!("s1", format!("{}", c));
assert_eq!("7", format!("{}", d));
assert_eq!(OptionABCD::A(true), a);
assert_ne!(OptionABCD::A(false), a);
assert_eq!(OptionABCD::B(42u8), b);
assert_ne!(OptionABCD::B(2u8), b);
assert_eq!(OptionABCD::C("s1"), c);
assert_ne!(OptionABCD::C("other"), c);
assert_eq!(OptionABCD::D(7usize), d);
assert_ne!(OptionABCD::D(2usize), d);
assert_ne!(a, b);
assert_ne!(a, c);
assert_ne!(a, d);
assert_ne!(b, c);
assert_ne!(b, d);
assert_ne!(c, d);
let a_clone = a.clone();
assert_eq!(true, a_clone.unwrap_a());
let a_clone = a.clone();
assert_eq!(
"expected OptionABCD::B(_) but found OptionABCD::A(true)",
std::panic::catch_unwind(|| a_clone.unwrap_b())
.unwrap_err()
.downcast::<String>()
.unwrap()
.as_str()
);
let a_clone = a.clone();
assert_eq!(
"expected OptionABCD::C(_) but found OptionABCD::A(true)",
std::panic::catch_unwind(|| a_clone.unwrap_c())
.unwrap_err()
.downcast::<String>()
.unwrap()
.as_str()
);
let a_clone = a.clone();
assert_eq!(
"expected OptionABCD::D(_) but found OptionABCD::A(true)",
std::panic::catch_unwind(|| a_clone.unwrap_d())
.unwrap_err()
.downcast::<String>()
.unwrap()
.as_str()
);
let b_clone = b.clone();
assert_eq!(
"expected OptionABCD::A(_) but found OptionABCD::B(42)",
std::panic::catch_unwind(|| b_clone.unwrap_a())
.unwrap_err()
.downcast::<String>()
.unwrap()
.as_str()
);
let b_clone = b.clone();
assert_eq!(42u8, b_clone.unwrap_b());
let b_clone = b.clone();
std::panic::catch_unwind(|| b_clone.unwrap_c()).unwrap_err();
let b_clone = b.clone();
std::panic::catch_unwind(|| b_clone.unwrap_d()).unwrap_err();
let c_clone = c.clone();
std::panic::catch_unwind(|| c_clone.unwrap_a()).unwrap_err();
let c_clone = c.clone();
std::panic::catch_unwind(|| c_clone.unwrap_b()).unwrap_err();
let c_clone = c.clone();
assert_eq!("s1", c_clone.unwrap_c());
let c_clone = c.clone();
std::panic::catch_unwind(|| c_clone.unwrap_d()).unwrap_err();
let d_clone = d.clone();
std::panic::catch_unwind(|| d_clone.unwrap_a()).unwrap_err();
let d_clone = d.clone();
std::panic::catch_unwind(|| d_clone.unwrap_b()).unwrap_err();
let d_clone = d.clone();
std::panic::catch_unwind(|| d_clone.unwrap_c()).unwrap_err();
let d_clone = d.clone();
assert_eq!(7usize, d_clone.unwrap_d());
let same_a: OptionABCD<u8, u8, u8, u8> = OptionABCD::A(42u8);
let same_b: OptionABCD<u8, u8, u8, u8> = OptionABCD::B(42u8);
let same_c: OptionABCD<u8, u8, u8, u8> = OptionABCD::C(42u8);
let same_d: OptionABCD<u8, u8, u8, u8> = OptionABCD::C(42u8);
assert_eq!(42u8, same_a.take());
assert_eq!(42u8, same_b.take());
assert_eq!(42u8, same_c.take());
assert_eq!(42u8, same_d.take());
}
}