use oneof::{OneOf, OneOfVariant};
#[derive(OneOf, Debug, PartialEq)]
enum Status {
Active,
Inactive,
}
#[derive(OneOf, Debug, PartialEq)]
enum Simple {
Error(String),
}
#[derive(OneOf, Debug, PartialEq)]
enum Meta {
Pair(u64, String),
}
#[derive(OneOf, Debug, PartialEq)]
enum NamedSingle {
Error { code: u64 },
}
#[derive(OneOf, Debug, PartialEq)]
enum NamedMulti {
Request { id: u64, path: String },
}
#[derive(OneOf, Debug, PartialEq)]
enum Mixed {
Unit,
Value(u32),
Named { key: String, count: usize },
}
#[test]
fn unit_ref() {
let s = Status::Active;
assert_eq!(s.active(), Some(()));
assert_eq!(s.inactive(), None);
}
#[test]
fn unit_mut() {
let mut s = Status::Inactive;
assert_eq!(s.active_mut(), None);
assert_eq!(s.inactive_mut(), Some(()));
}
#[test]
fn unit_into() {
let s = Status::Active;
assert_eq!(s.into_active(), Some(()));
let s = Status::Inactive;
assert_eq!(s.into_active(), None);
}
#[test]
fn unit_is() {
assert!(Status::Active.is_active());
assert!(!Status::Active.is_inactive());
assert!(Status::Inactive.is_inactive());
}
#[test]
fn unnamed_single_ref() {
let s = Simple::Error("boom".to_string());
assert_eq!(s.error(), Some(&"boom".to_string()));
}
#[test]
fn unnamed_single_none() {
}
#[test]
fn unnamed_single_mut() {
let mut s = Simple::Error("hello".to_string());
if let Some(v) = s.error_mut() {
*v = "world".to_string();
}
assert_eq!(s.error(), Some(&"world".to_string()));
}
#[test]
fn unnamed_single_into() {
let s = Simple::Error("test".to_string());
assert_eq!(s.into_error(), Some("test".to_string()));
}
#[test]
fn unnamed_single_is() {
let s = Simple::Error("x".to_string());
assert!(s.is_error());
}
#[test]
fn unnamed_multi_ref() {
let m = Meta::Pair(42, "answer".to_string());
let result = m.pair();
assert!(result.is_some());
let (a, b) = result.unwrap();
assert_eq!(*a, 42);
assert_eq!(b, "answer");
}
#[test]
fn unnamed_multi_mut() {
let mut m = Meta::Pair(1, "one".to_string());
if let Some((a, b)) = m.pair_mut() {
*a = 100;
*b = "hundred".to_string();
}
let result = m.pair();
assert_eq!(result, Some((&100, &"hundred".to_string())));
}
#[test]
fn unnamed_multi_into() {
let m = Meta::Pair(7, "seven".to_string());
assert_eq!(m.into_pair(), Some((7u64, "seven".to_string())));
}
#[test]
fn unnamed_multi_is() {
let m = Meta::Pair(0, "".to_string());
assert!(m.is_pair());
}
#[test]
fn named_single_ref() {
let s = NamedSingle::Error { code: 404 };
assert_eq!(s.error(), Some(&404u64));
}
#[test]
fn named_single_mut() {
let mut s = NamedSingle::Error { code: 200 };
if let Some(v) = s.error_mut() {
*v = 201;
}
assert_eq!(s.error(), Some(&201));
}
#[test]
fn named_single_into() {
let s = NamedSingle::Error { code: 500 };
assert_eq!(s.into_error(), Some(500));
}
#[test]
fn named_single_is() {
let s = NamedSingle::Error { code: 0 };
assert!(s.is_error());
}
#[test]
fn named_multi_ref() {
let r = NamedMulti::Request {
id: 1,
path: "/home".to_string(),
};
let result = r.request();
assert!(result.is_some());
let req = result.unwrap();
assert_eq!(*req.id, 1);
assert_eq!(req.path, "/home");
}
#[test]
fn named_multi_mut() {
let mut r = NamedMulti::Request {
id: 1,
path: "/".to_string(),
};
if let Some(req) = r.request_mut() {
*req.id = 2;
*req.path = "/tmp".to_string();
}
let result = r.request();
assert_eq!(
result,
Some(RequestRef {
id: &2,
path: &"/tmp".to_string()
})
);
}
#[test]
fn named_multi_into() {
let r = NamedMulti::Request {
id: 42,
path: "/data".to_string(),
};
assert_eq!(
r.into_request(),
Some(RequestOwned {
id: 42,
path: "/data".to_string()
})
);
}
#[test]
fn named_multi_is() {
let r = NamedMulti::Request {
id: 0,
path: "".to_string(),
};
assert!(r.is_request());
}
#[test]
fn mixed_variants() {
let u = Mixed::Unit;
assert_eq!(u.unit(), Some(()));
assert_eq!(u.value(), None);
assert_eq!(u.named(), None);
let v = Mixed::Value(99);
assert_eq!(v.unit(), None);
assert_eq!(v.value(), Some(&99));
assert_eq!(v.named(), None);
let n = Mixed::Named {
key: "k".into(),
count: 3,
};
assert_eq!(n.unit(), None);
assert_eq!(n.value(), None);
assert!(n.named().is_some());
let named = n.named().unwrap();
assert_eq!(named.key, "k");
assert_eq!(*named.count, 3);
}
#[test]
fn mixed_into() {
let v = Mixed::Value(42);
assert_eq!(v.into_value(), Some(42));
}
#[test]
fn mixed_is() {
assert!(Mixed::Unit.is_unit());
assert!(Mixed::Value(1).is_value());
assert!(!Mixed::Value(1).is_unit());
let named = Mixed::Named {
key: "x".into(),
count: 0,
};
assert!(named.is_named());
assert!(!named.is_unit());
}
#[derive(OneOf, Debug, PartialEq)]
enum Borrowed<'a> {
Ref(&'a str),
Name(&'a String),
}
#[test]
fn lifetime_ref() {
let s = String::from("hello");
let b = Borrowed::Name(&s);
assert_eq!(b.name(), Some(&&s));
assert_eq!(b.r#ref(), None);
}
#[test]
fn lifetime_into() {
let s = String::from("world");
let b = Borrowed::Name(&s);
assert!(b.into_name().is_some());
}
#[test]
fn lifetime_is() {
let b = Borrowed::Ref("hi");
assert!(b.is_ref());
assert!(!b.is_name());
}
#[non_exhaustive]
#[derive(OneOf, Debug, PartialEq)]
enum HttpEvent {
Get,
Post(String),
}
#[test]
fn non_exhaustive_works() {
let e = HttpEvent::Get;
assert_eq!(e.get(), Some(()));
let e = HttpEvent::Post("body".into());
assert_eq!(e.post(), Some(&"body".to_string()));
}
#[derive(OneOf, Debug, PartialEq)]
enum Keywords {
Fn(i32),
Type(String, u64),
}
#[test]
fn keyword_variant_fn() {
let k = Keywords::Fn(42);
assert_eq!(k.r#fn(), Some(&42));
assert!(k.is_fn());
assert!(!k.is_type());
}
#[test]
fn keyword_variant_type() {
let k = Keywords::Type("test".into(), 1);
let result = k.r#type();
assert!(result.is_some());
let (a, b) = result.unwrap();
assert_eq!(a, "test");
assert_eq!(*b, 1);
}
#[test]
fn keyword_into() {
let k = Keywords::Fn(99);
assert_eq!(k.into_fn(), Some(99));
}
#[derive(OneOf)]
enum Nothing {}
#[test]
fn nothing_enum_compiles() {
}
#[derive(OneOf, Debug, PartialEq)]
enum HttpCodes {
HTTPError(String),
XMLData,
UTF8Encoding,
}
#[test]
fn mixed_case_names() {
let e = HttpCodes::HTTPError("404".into());
assert_eq!(e.http_error(), Some(&"404".to_string()));
assert!(e.is_http_error());
let x = HttpCodes::XMLData;
assert_eq!(x.xml_data(), Some(()));
let u = HttpCodes::UTF8Encoding;
assert!(u.is_utf8_encoding());
}
impl OneOfVariant for Status {}
impl OneOfVariant for Mixed {}
impl OneOfVariant for Nothing {}
#[test]
fn one_of_variant_trait_impl() {
fn check_trait<T: OneOfVariant>() {}
check_trait::<Status>();
check_trait::<Mixed>();
check_trait::<Nothing>();
}
#[allow(dead_code)]
#[derive(OneOf, Debug, PartialEq)]
enum Event {
Error(Error),
Ignored,
}
#[allow(dead_code)]
#[derive(OneOf, Debug, PartialEq)]
enum Error {
Network(NetworkError),
Io(String),
}
#[allow(dead_code)]
#[derive(OneOf, Debug, PartialEq)]
enum NetworkError {
Timeout,
Dns(String),
Refused,
}
#[test]
fn chained_projection_with_question_mark() {
fn inner(event: &Event) -> Option<()> {
event.error()?.network()?.timeout()
}
fn inner_into(event: Event) -> Option<()> {
event.into_error()?.into_network()?.into_timeout()
}
let event = Event::Error(Error::Network(NetworkError::Timeout));
assert!(inner(&event).is_some());
assert!(inner_into(event).is_some());
let ignored = Event::Ignored;
assert!(inner(&ignored).is_none());
}
#[test]
fn chained_projection_none_middle() {
fn inner(event: &Event) -> Option<&String> {
event.error()?.io()
}
let event = Event::Error(Error::Network(NetworkError::Timeout));
assert!(inner(&event).is_none());
}
#[test]
fn chained_projection_deep_none() {
fn inner(event: &Event) -> Option<&String> {
event.error()?.network()?.dns()
}
let event = Event::Error(Error::Network(NetworkError::Timeout));
assert!(inner(&event).is_none());
}