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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! Specs errors
//!
//! There are specific types for errors (e.g. `WrongGeneration`)
//! and additionally one `Error` type that can represent them all.
//! Each error in this module has an `Into<Error>` implementation.

use std::{
    error::Error as StdError,
    fmt::{Debug, Display, Formatter, Result as FmtResult},
};

use crate::world::{Entity, Generation};

/// A boxed error implementing `Debug`, `Display` and `Error`.
pub struct BoxedErr(pub Box<dyn StdError + Send + Sync + 'static>);

impl BoxedErr {
    /// Creates a new boxed error.
    pub fn new<T>(err: T) -> Self
    where
        T: StdError + Send + Sync + 'static,
    {
        BoxedErr(Box::new(err))
    }
}

impl AsRef<dyn StdError> for BoxedErr {
    fn as_ref(&self) -> &(dyn StdError + 'static) {
        self.0.as_ref()
    }
}

impl Debug for BoxedErr {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{:}", self.0)
    }
}

impl Display for BoxedErr {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}", self.as_ref())
    }
}

impl StdError for BoxedErr {
    fn description(&self) -> &str {
        self.as_ref().description()
    }
}

/// The Specs error type.
/// This is an enum which is able to represent
/// all error types of this library.
///
/// Please note that you should not use `__NonExhaustive`,
/// which is a variant specifically added for extensibility
/// without breakage.
#[derive(Debug)]
pub enum Error {
    /// A custom, boxed error.
    Custom(BoxedErr),
    /// Wrong generation error.
    WrongGeneration(WrongGeneration),

    #[doc(hidden)]
    __NonExhaustive,
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            Error::Custom(ref e) => write!(f, "Custom: {}", e),
            Error::WrongGeneration(ref e) => write!(f, "Wrong generation: {}", e),

            Error::__NonExhaustive => unimplemented!(),
        }
    }
}

impl From<NoError> for Error {
    fn from(e: NoError) -> Self {
        match e {}
    }
}

impl From<WrongGeneration> for Error {
    fn from(e: WrongGeneration) -> Self {
        Error::WrongGeneration(e)
    }
}

impl StdError for Error {
    fn description(&self) -> &str {
        "A Specs error"
    }

    fn cause(&self) -> Option<&dyn StdError> {
        let e = match *self {
            Error::Custom(ref e) => e.as_ref(),
            Error::WrongGeneration(ref e) => e,

            Error::__NonExhaustive => unimplemented!(),
        };

        Some(e)
    }
}

/// Wrong generation error.
#[derive(Debug, PartialEq, Eq)]
pub struct WrongGeneration {
    /// The action that failed because of the wrong generation.
    pub action: &'static str,
    /// The actual generation of this id.
    pub actual_gen: Generation,
    /// The entity that has been passed, containing
    /// the id and the invalid generation.
    pub entity: Entity,
}

impl Display for WrongGeneration {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(
            f,
            "Tried to {} entity {:?}, but the generation is wrong; it should be {:?}",
            self.action, self.entity, self.actual_gen
        )
    }
}

impl StdError for WrongGeneration {
    fn description(&self) -> &str {
        "Used an entity with a generation that is not valid anymore \
         (e.g. because the entity has been deleted)"
    }
}

/// An error type which cannot be instantiated.
/// Used as a placeholder for associated error types if
/// something cannot fail.
#[derive(Debug, PartialEq, Eq)]
pub enum NoError {}

impl Display for NoError {
    fn fmt(&self, _: &mut Formatter) -> FmtResult {
        match *self {}
    }
}

impl StdError for NoError {
    fn description(&self) -> &str {
        match *self {}
    }
}