1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
// Original source is from https://github.com/rust-lang/rust/pull/83349/files

use core::fmt;

pub trait UnwrapNone {
    /// Consumes `self` while expecting [`None`] and returning nothing.
    ///
    /// # Panics
    ///
    /// Panics if the value is a [`Some`], with a panic message including the
    /// passed message, and the content of the [`Some`].
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(option_expect_none)]
    ///
    /// use std::collections::HashMap;
    /// let mut squares = HashMap::new();
    /// for i in -10..=10 {
    ///     // This will not panic, since all keys are unique.
    ///     squares.insert(i, i * i).expect_none("duplicate key");
    /// }
    /// ```
    ///
    /// ```should_panic
    /// #![feature(option_expect_none)]
    ///
    /// use std::collections::HashMap;
    /// let mut sqrts = HashMap::new();
    /// for i in -10..=10 {
    ///     // This will panic, since both negative and positive `i` will
    ///     // insert the same `i * i` key, returning the old `Some(i)`.
    ///     sqrts.insert(i * i, i).expect_none("duplicate key");
    /// }
    /// ```
	fn expect_none(self, msg: &str);

    /// Consumes `self` while expecting [`None`] and returning nothing.
    ///
    /// # Panics
    ///
    /// Panics if the value is a [`Some`], with a custom panic message provided
    /// by the [`Some`]'s value.
    ///
    /// [`Some(v)`]: Some
    ///
    /// # Examples
    ///
    /// ```
    /// #![feature(option_unwrap_none)]
    ///
    /// use std::collections::HashMap;
    /// let mut squares = HashMap::new();
    /// for i in -10..=10 {
    ///     // This will not panic, since all keys are unique.
    ///     squares.insert(i, i * i).unwrap_none();
    /// }
    /// ```
    ///
    /// ```should_panic
    /// #![feature(option_unwrap_none)]
    ///
    /// use std::collections::HashMap;
    /// let mut sqrts = HashMap::new();
    /// for i in -10..=10 {
    ///     // This will panic, since both negative and positive `i` will
    ///     // insert the same `i * i` key, returning the old `Some(i)`.
    ///     sqrts.insert(i * i, i).unwrap_none();
    /// }
    /// ```
	fn unwrap_none(self);
}

impl<T> UnwrapNone for Option<T>
where
	T: fmt::Debug
{
    #[inline]
    #[track_caller]
    fn expect_none(self, msg: &str) {
        if let Some(val) = self {
            expect_none_failed(msg, &val);
        }
    }

    #[inline]
    #[track_caller]
    fn unwrap_none(self) {
        if let Some(val) = self {
            expect_none_failed("called `Option::unwrap_none()` on a `Some` value", &val);
        }
    }
}

// This is a separate function to reduce the code size of .expect_none() itself.
#[inline(never)]
#[cold]
#[track_caller]
fn expect_none_failed(msg: &str, value: &dyn fmt::Debug) -> ! {
    panic!("{}: {:?}", msg, value)
}