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
use crate::*;

/// The types of errors a `System` can create.
#[derive(Debug)]
pub enum EcsError {
    /// A resource was not initialized in the `World` but the
    /// `System` tries to access it.
    ///
    /// Usually, this means no dispatcher was used and `World::initialize`
    /// was not called.
    NotInitialized,
    /// The requested resource is already borrowed.
    /// This error is created if the `System` tries to read a resource that
    /// has already been mutably borrowed.
    /// It can also happen when trying to mutably borrow a resource that is
    /// already being read.
    ///
    /// This error should not occur during normal use, as the dispatchers
    /// can recover easily.
    AlreadyBorrowed,
    /// The execution of the dispatcher failed and returned one or more errors.
    DispatcherExecutionFailed(Vec<EcsError>),
    /// This variant is for user-defined errors.
    /// To create an error of this type easily, use the `system_error!` macro.
    SystemError(Box<dyn Error+Send>),
}

/// The result of a `System`'s execution.
/// Returns Ok(()) on success, `EcsError` on failure.
/// To return a custom error from a system, use the
/// `system_error!` macro.
pub type SystemResult = Result<(), EcsError>;

/// Returns a custom error from a `System` during execution.
#[macro_export]
macro_rules! system_error {
    ($err:expr) => {
        return Err(EcsError::SystemError(Box::new($err)));
    };
}

#[cfg(test)]
mod tests {
    use crate::*;
    use wasm_bindgen_test::*;

    #[test]
    #[wasm_bindgen_test]
    fn system_return_custom_error() {
        #[derive(Debug)]
        struct CustomError;
        impl std::fmt::Display for CustomError {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                write!(f, "Custom error crash")
            }
        }
        impl Error for CustomError {}
        fn sys() -> SystemResult {
            system_error!(CustomError)
        }
        let mut s = sys.system();
        let result = s.run(&World::default());
        match result {
            Err(EcsError::SystemError(err)) => assert_eq!(err.to_string(), "Custom error crash"),
            _ => unreachable!(),
        }
    }
}