chain_assertions/
option.rs

1/// An extension trait to add the assertion_some methods.
2pub trait AssertSomeExt {
3    /// Asserts the Option is [`Some`].
4    ///
5    /// # Panics
6    ///
7    /// If it is [`None`], the method panics.
8    ///
9    /// # Examples
10    ///
11    /// ```rust
12    /// use chain_assertions::prelude::*;
13    ///
14    /// let x: Option<i32> = Some(21);
15    /// let x = x.assert_some().map(|v| v * 2);
16    /// assert_eq!(x, Some(42));
17    /// ```
18    ///
19    /// ```rust,should_panic
20    /// use chain_assertions::prelude::*;
21    ///
22    /// let x: Option<i32> = None;
23    /// let _ = x.assert_some().map(|v| v * 2);
24    /// //        ^-- panics here
25    fn assert_some(self) -> Self;
26
27    /// Asserts the Option is [`Some`] only in debug builds.
28    ///
29    /// # Panics
30    ///
31    /// If it is [`None`] and `debug_assertions` are enabled, the method panics.
32    /// If `debug_assertions` are disabled, the method is a no-op even if it is [`None`].
33    ///
34    /// # Examples
35    ///
36    /// ```rust
37    /// use chain_assertions::prelude::*;
38    ///
39    /// let x: Option<i32> = Some(21);
40    /// let x = x.debug_assert_some().map(|v| v * 2);
41    /// assert_eq!(x, Some(42));
42    /// ```
43    fn debug_assert_some(self) -> Self;
44}
45
46/// An extension trait to add the assertion_none methods.
47pub trait AssertNoneExt {
48    /// Asserts the Option is [`None`].
49    ///
50    /// # Panics
51    ///
52    /// If it is [`Some`], the method panics.
53    ///
54    /// # Examples
55    ///
56    /// ```rust
57    /// use chain_assertions::prelude::*;
58    ///
59    /// let x: Option<i32> = None;
60    /// let x = x.assert_none().map(|v| v * 2);
61    /// assert_eq!(x, None);
62    /// ```
63    ///
64    /// ```rust,should_panic
65    /// use chain_assertions::prelude::*;
66    ///
67    /// let x: Option<i32> = Some(21);
68    /// let _ = x.assert_none().map(|v| v * 2);
69    /// //        ^-- panics here
70    /// ```
71    fn assert_none(self) -> Self;
72
73    /// Asserts the Option is [`None`] only in debug builds.
74    ///
75    /// # Panics
76    ///
77    /// If it is [`Some`] and `debug_assertions` are enabled, the method panics.
78    /// If `debug_assertions` are disabled, the method is a no-op even if it is [`Some`].
79    ///
80    /// # Examples
81    ///
82    /// ```rust
83    /// use chain_assertions::prelude::*;
84    ///
85    /// let x: Option<i32> = None;
86    /// let x = x.debug_assert_none().map(|v| v * 2);
87    /// assert_eq!(x, None);
88    /// ```
89    fn debug_assert_none(self) -> Self;
90}
91
92impl<T> AssertSomeExt for Option<T> {
93    #[track_caller]
94    #[inline]
95    fn assert_some(self) -> Self {
96        if self.is_none() {
97            panic!("Expected Some(_), got None");
98        }
99        self
100    }
101
102    #[track_caller]
103    #[inline]
104    fn debug_assert_some(self) -> Self {
105        #[cfg(all(debug_assertions, not(feature = "passthrough")))]
106        {
107            if self.is_none() {
108                panic!("Expected Some(_), got None");
109            }
110        }
111        self
112    }
113}
114
115impl<T> AssertNoneExt for Option<T>
116where
117    T: crate::fmt::Debug,
118{
119    #[track_caller]
120    #[inline]
121    fn assert_none(self) -> Self {
122        if let Some(ref v) = self {
123            panic!("Expected None, got Some({:?})", v);
124        }
125        self
126    }
127
128    #[track_caller]
129    #[inline]
130    fn debug_assert_none(self) -> Self {
131        #[cfg(all(debug_assertions, not(feature = "passthrough")))]
132        {
133            if let Some(ref v) = self {
134                panic!("Expected None, got Some({:?})", v);
135            }
136        }
137        self
138    }
139}
140
141#[cfg(test)]
142mod tests {
143    struct NonDebuggable;
144
145    #[derive(Debug)]
146    struct Debuggable;
147
148    mod assert_some {
149        use super::{super::*, *};
150
151        #[test]
152        fn it_succeeds_on_some() {
153            let opt: Option<NonDebuggable> = Some(NonDebuggable);
154            let target = opt.assert_some();
155
156            assert!(
157                matches!(target, Some(NonDebuggable)),
158                "Expected Some(NonDebuggable)"
159            );
160        }
161
162        #[test]
163        #[should_panic(expected = "Expected Some(_), got None")]
164        fn it_fails_on_none() {
165            let opt: Option<NonDebuggable> = None;
166            let _ = opt.assert_some();
167            //          ^-- should panic here
168        }
169    }
170
171    mod debug_assert_some {
172        use super::{super::*, *};
173
174        #[test]
175        fn it_succeeds_on_some() {
176            let opt: Option<NonDebuggable> = Some(NonDebuggable);
177            let target = opt.debug_assert_some();
178
179            assert!(
180                matches!(target, Some(NonDebuggable)),
181                "Expected Some(NonDebuggable)"
182            );
183        }
184
185        #[test]
186        #[cfg_attr(
187            all(debug_assertions, not(feature = "passthrough")),
188            should_panic(expected = "Expected Some(_), got None")
189        )]
190        fn it_fails_on_none() {
191            let opt: Option<NonDebuggable> = None;
192            let target = opt.debug_assert_some();
193            //               ^-- should panic here only in debug mode
194            assert!(matches!(target, None), "Expected None");
195        }
196    }
197
198    mod assert_none {
199        use super::{super::*, *};
200
201        #[test]
202        fn it_succeeds_on_none() {
203            let opt: Option<Debuggable> = None;
204            let target = opt.assert_none();
205
206            assert!(matches!(target, None), "Expected None");
207        }
208
209        #[test]
210        #[should_panic(expected = "Expected None, got Some(Debuggable)")]
211        fn it_fails_on_some() {
212            let opt: Option<Debuggable> = Some(Debuggable);
213            let target = opt.assert_none();
214            //          ^-- should panic here only in debug mode
215            assert!(
216                matches!(target, Some(Debuggable)),
217                "Expected Some(Debuggable)"
218            );
219        }
220    }
221
222    mod debug_assert_none {
223        use super::{super::*, *};
224
225        #[test]
226        fn it_succeeds_on_none() {
227            let opt: Option<Debuggable> = None;
228            let target = opt.debug_assert_none();
229
230            assert!(matches!(target, None), "Expected None");
231        }
232
233        #[test]
234        #[cfg_attr(
235            all(debug_assertions, not(feature = "passthrough")),
236            should_panic(expected = "Expected None, got Some(Debuggable)")
237        )]
238        fn it_fails_on_some() {
239            let opt: Option<Debuggable> = Some(Debuggable);
240            let target = opt.debug_assert_none();
241            //               ^-- should panic here only in debug mode
242            assert!(
243                matches!(target, Some(Debuggable)),
244                "Expected Some(Debuggable)"
245            );
246        }
247    }
248}