optional_error/
lib.rs

1use syn::Error;
2
3/// Represents an `Option<syn::Error>`.
4#[derive(Default)]
5pub struct OptionalError(Option<Error>);
6
7impl OptionalError {
8    /// Create a new [`OptionalError`] with the given [error](Error).
9    pub fn new(error: Error) -> Self {
10        Self(Some(error))
11    }
12
13    /// Returns a reference to the contained [error](Error), if any.
14    pub fn error(&self) -> Option<&Error> {
15        self.0.as_ref()
16    }
17
18    /// Returns a mutable reference to the contained [error](Error), if any.
19    pub fn error_mut(&mut self) -> Option<&mut Error> {
20        self.0.as_mut()
21    }
22
23    /// Removes the contained [error](Error) and returns it, if any.
24    pub fn take(&mut self) -> Option<Error> {
25        self.0.take()
26    }
27
28    /// Replaces the contained [error](Error) with the given one.
29    ///
30    /// Returns the previous error, if any.
31    pub fn replace(&mut self, error: Error) -> Option<Error> {
32        self.0.replace(error)
33    }
34
35    /// Combine the given [error](Error) with the existing one,
36    /// initializing it if none currently exists.
37    pub fn combine(&mut self, error: Error) {
38        match self.0 {
39            None => self.0 = Some(error),
40            Some(ref mut prev) => prev.combine(error),
41        }
42    }
43
44    /// Returns a [`Result`] with the contained [error](Error), if any.
45    ///
46    /// This can be used for quick and easy early returns.
47    pub fn try_throw(self) -> Result<(), Error> {
48        match self.0 {
49            None => Ok(()),
50            Some(err) => Err(err),
51        }
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use syn::__private::Span;
58    use super::*;
59
60    #[test]
61    fn should_combine() {
62        let mut collector = OptionalError::new(Error::new(Span::call_site(), "First Error"));
63        collector.combine(Error::new(Span::call_site(), "Second Error"));
64
65        let expected = r#"compile_error ! { "First Error" } compile_error ! { "Second Error" }"#;
66        let received = collector.try_throw().expect_err("expected error").to_compile_error().to_string();
67        assert_eq!(expected, received);
68    }
69
70    #[test]
71    fn should_replace() {
72        let mut collector = OptionalError::new(Error::new(Span::call_site(), "First Error"));
73        let existing = collector.replace(Error::new(Span::call_site(), "Second Error"));
74
75        let expected = r#"compile_error ! { "First Error" }"#;
76        let received = existing.expect("expected error").to_compile_error().to_string();
77        assert_eq!(expected, received);
78
79        let expected = r#"compile_error ! { "Second Error" }"#;
80        let received = collector.try_throw().expect_err("expected error").to_compile_error().to_string();
81        assert_eq!(expected, received);
82    }
83
84    #[test]
85    fn should_take() {
86        let mut collector = OptionalError::new(Error::new(Span::call_site(), "First Error"));
87        let existing = collector.take();
88
89        let expected = r#"compile_error ! { "First Error" }"#;
90        let received = existing.expect("expected error").to_compile_error().to_string();
91        assert_eq!(expected, received);
92        assert!(collector.try_throw().is_ok());
93    }
94}