pub trait AssertSomeExt {
fn assert_some(self) -> Self;
fn debug_assert_some(self) -> Self;
}
pub trait AssertSomeAndExt<T> {
fn assert_some_and(self, cond: impl FnOnce(&T) -> bool) -> Self;
fn debug_assert_some_and(self, cond: impl FnOnce(&T) -> bool) -> Self;
}
pub trait AssertNoneExt {
fn assert_none(self) -> Self;
fn debug_assert_none(self) -> Self;
}
impl<T> AssertSomeExt for Option<T> {
#[track_caller]
#[inline]
fn assert_some(self) -> Self {
if self.is_none() {
panic!("Expected Some(_), got None");
}
self
}
#[track_caller]
#[inline]
fn debug_assert_some(self) -> Self {
#[cfg(all(debug_assertions, not(feature = "passthrough")))]
{
if self.is_none() {
panic!("Expected Some(_), got None");
}
}
self
}
}
impl<T> AssertSomeAndExt<T> for Option<T>
where
T: crate::fmt::Debug,
{
#[track_caller]
#[inline]
fn assert_some_and(self, cond: impl FnOnce(&T) -> bool) -> Self {
match self {
Some(ref v) if cond(v) => { }
Some(ref v) => panic!("Condition not satisfied for Some({:?})", v),
None => panic!("Expected Some(_), got None"),
}
self
}
#[track_caller]
#[inline]
fn debug_assert_some_and(self, _cond: impl FnOnce(&T) -> bool) -> Self {
#[cfg(all(debug_assertions, not(feature = "passthrough")))]
{
match self {
Some(ref v) if _cond(v) => { }
Some(ref v) => panic!("Condition not satisfied for Some({:?})", v),
None => panic!("Expected Some(_), got None"),
}
}
self
}
}
impl<T> AssertNoneExt for Option<T>
where
T: crate::fmt::Debug,
{
#[track_caller]
#[inline]
fn assert_none(self) -> Self {
if let Some(ref v) = self {
panic!("Expected None, got Some({:?})", v);
}
self
}
#[track_caller]
#[inline]
fn debug_assert_none(self) -> Self {
#[cfg(all(debug_assertions, not(feature = "passthrough")))]
{
if let Some(ref v) = self {
panic!("Expected None, got Some({:?})", v);
}
}
self
}
}
#[cfg(test)]
mod tests {
#[derive(PartialEq)]
struct NonDebuggable;
#[derive(Debug, PartialEq)]
struct Debuggable;
mod assert_some {
use super::{super::*, *};
#[test]
fn it_succeeds_on_some() {
let x: Option<NonDebuggable> = Some(NonDebuggable);
let x = x.assert_some();
assert!(
matches!(x, Some(NonDebuggable)),
"Expected Some(NonDebuggable)"
);
}
#[test]
#[should_panic(expected = "Expected Some(_), got None")]
fn it_fails_on_none() {
let opt: Option<NonDebuggable> = None;
let _ = opt.assert_some();
}
}
mod assert_some_and {
use super::super::*;
#[test]
fn it_succeeds_on_ok_and_condition_satisfied() {
let x: Option<i32> = Some(21);
let x = x.assert_some_and(|x| x >= &20).map(|x| x * 2);
assert_eq!(x, Some(42));
}
#[test]
#[should_panic(expected = "Condition not satisfied for Some(19)")]
fn it_fails_on_ok_and_condition_not_satisfied() {
let x: Option<i32> = Some(19);
let _ = x.assert_some_and(|x| x >= &20).map(|x| x * 2);
}
#[test]
#[should_panic(expected = "Expected Some(_), got None")]
fn it_fails_on_none() {
let x: Option<i32> = None;
let _ = x.assert_some_and(|x| x >= &20).map(|x| x * 2);
}
}
mod debug_assert_some {
use super::{super::*, *};
#[test]
fn it_succeeds_on_some() {
let x: Option<NonDebuggable> = Some(NonDebuggable);
let x = x.debug_assert_some();
assert!(
matches!(x, Some(NonDebuggable)),
"Expected Some(NonDebuggable)"
);
}
#[test]
#[cfg_attr(
all(debug_assertions, not(feature = "passthrough")),
should_panic(expected = "Expected Some(_), got None")
)]
fn it_fails_on_none() {
let x: Option<NonDebuggable> = None;
let x = x.debug_assert_some();
assert!(matches!(x, None), "Expected None");
}
}
mod debug_assert_some_and {
use super::super::*;
#[test]
fn it_succeeds_on_some_and_condition_satisfied() {
let x: Option<i32> = Some(21);
let x = x.debug_assert_some_and(|x| x >= &20).map(|x| x * 2);
assert_eq!(x, Some(42));
}
#[test]
#[cfg_attr(
all(debug_assertions, not(feature = "passthrough")),
should_panic(expected = "Condition not satisfied for Some(19)")
)]
fn it_fails_on_some_and_condition_not_satisfied() {
let x: Option<i32> = Some(19);
let x = x.debug_assert_some_and(|x| x >= &20).map(|x| x * 2);
assert_eq!(x, Some(38));
}
#[test]
#[cfg_attr(
all(debug_assertions, not(feature = "passthrough")),
should_panic(expected = "Expected Some(_), got None")
)]
fn it_fails_on_none() {
let x: Option<i32> = None;
let _ = x.debug_assert_some_and(|x| x >= &20).map(|x| x * 2);
assert_eq!(x, None);
}
}
mod assert_none {
use super::{super::*, *};
#[test]
fn it_succeeds_on_none() {
let x: Option<Debuggable> = None;
let x = x.assert_none();
assert!(matches!(x, None), "Expected None");
}
#[test]
#[should_panic(expected = "Expected None, got Some(Debuggable)")]
fn it_fails_on_some() {
let x: Option<Debuggable> = Some(Debuggable);
let _ = x.assert_none();
}
}
mod debug_assert_none {
use super::{super::*, *};
#[test]
fn it_succeeds_on_none() {
let x: Option<Debuggable> = None;
let x = x.debug_assert_none();
assert!(matches!(x, None), "Expected None");
}
#[test]
#[cfg_attr(
all(debug_assertions, not(feature = "passthrough")),
should_panic(expected = "Expected None, got Some(Debuggable)")
)]
fn it_fails_on_some() {
let x: Option<Debuggable> = Some(Debuggable);
let x = x.debug_assert_none();
assert!(matches!(x, Some(Debuggable)), "Expected Some(Debuggable)");
}
}
}