my_ecs/ecs/
mod.rs

1//! ECS core module.
2
3pub(crate) mod cache;
4pub(crate) mod cmd;
5pub(crate) mod ent;
6pub(crate) mod entry;
7pub(crate) mod lock;
8pub(crate) mod post;
9pub(crate) mod resource;
10pub(crate) mod sched;
11pub(crate) mod sys;
12pub(crate) mod wait;
13pub(crate) mod web;
14pub(crate) mod worker;
15
16pub mod prelude {
17    pub use super::{
18        cmd::prelude::*,
19        ent::prelude::*,
20        entry::prelude::*,
21        post::prelude::*,
22        resource::prelude::*,
23        sched::prelude::*,
24        sys::prelude::*,
25        worker::prelude::*,
26        {DynResult, EcsError},
27    };
28}
29
30use std::{error::Error, fmt};
31use thiserror::Error;
32
33/// A [`Result`] with super flexible error type `Box<dyn Error + Send + Sync +
34/// 'static>`.
35pub type DynResult<T> = Result<T, Box<dyn Error + Send + Sync + 'static>>;
36
37/// An error generated by ECS instance.
38#[derive(Error)]
39#[repr(C)]
40pub enum EcsError<Data = ()> {
41    #[error("unknown system `{0}`")]
42    UnknownSystem(String, Data),
43
44    #[error("unknown entity `{0}`")]
45    UnknownEntity(String, Data),
46    #[error("invalid entity `{0}`")]
47    InvalidEntity(String, Data),
48
49    #[error("unknown resource `{0}`")]
50    UnknownResource(String, Data),
51    #[error("duplicated resource `{0}`")]
52    DupResource(String, Data),
53
54    #[error("invalid request `{0}`")]
55    InvalidRequest(String, Data),
56
57    #[error("unknown error `{0}`")]
58    Unknown(String, Data),
59}
60
61impl<Data> fmt::Debug for EcsError<Data> {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        match self {
64            Self::UnknownSystem(reason, ..) => {
65                write!(f, "EcsError::UnknownSystem({reason}, ..)")
66            }
67            Self::UnknownEntity(reason, ..) => {
68                write!(f, "EcsError::UnknownEntity({reason}, ..)")
69            }
70            Self::InvalidEntity(reason, ..) => {
71                write!(f, "EcsError::InvalidEntity({reason}, ..)")
72            }
73            Self::UnknownResource(reason, ..) => {
74                write!(f, "EcsError::UnknownResource({reason}, ..)")
75            }
76            Self::DupResource(reason, ..) => {
77                write!(f, "EcsError::DupResource({reason}, ..)")
78            }
79            Self::InvalidRequest(reason, ..) => {
80                write!(f, "EcsError::InvalidRequest({reason}, ..)")
81            }
82            Self::Unknown(reason, ..) => {
83                write!(f, "EcsError::Unknown({reason}, ..)")
84            }
85        }
86    }
87}
88
89impl<Data> EcsError<Data> {
90    pub fn reason(&self) -> &str {
91        match self {
92            Self::UnknownSystem(reason, ..) => reason,
93            Self::UnknownEntity(reason, ..) => reason,
94            Self::InvalidEntity(reason, ..) => reason,
95            Self::UnknownResource(reason, ..) => reason,
96            Self::DupResource(reason, ..) => reason,
97            Self::InvalidRequest(reason, ..) => reason,
98            Self::Unknown(reason, ..) => reason,
99        }
100    }
101
102    pub fn take_data(self) -> Data {
103        match self {
104            Self::UnknownSystem(_, data) => data,
105            Self::UnknownEntity(_, data) => data,
106            Self::InvalidEntity(_, data) => data,
107            Self::UnknownResource(_, data) => data,
108            Self::DupResource(_, data) => data,
109            Self::InvalidRequest(_, data) => data,
110            Self::Unknown(_, data) => data,
111        }
112    }
113
114    pub fn without_data(self) -> EcsError<()> {
115        self.with_data(())
116    }
117
118    pub fn with_data<OutData>(self, data: OutData) -> EcsError<OutData> {
119        self.map_data(|_| data)
120    }
121
122    pub fn map_data<F, OutData>(self, f: F) -> EcsError<OutData>
123    where
124        F: FnOnce(Data) -> OutData,
125    {
126        match self {
127            Self::UnknownSystem(reason, old) => EcsError::UnknownSystem(reason, f(old)),
128            Self::UnknownEntity(reason, old) => EcsError::UnknownEntity(reason, f(old)),
129            Self::InvalidEntity(reason, old) => EcsError::InvalidEntity(reason, f(old)),
130            Self::UnknownResource(reason, old) => EcsError::UnknownResource(reason, f(old)),
131            Self::DupResource(reason, old) => EcsError::DupResource(reason, f(old)),
132            Self::InvalidRequest(reason, old) => EcsError::InvalidRequest(reason, f(old)),
133            Self::Unknown(reason, old) => EcsError::Unknown(reason, f(old)),
134        }
135    }
136}
137
138pub mod stat {
139    macro_rules! decl_counter {
140        ($name:ident, $id:ident) => {
141            paste::paste! {
142                #[cfg(feature = "stat")]
143                pub(crate) static $id: std::sync::LazyLock<std::sync::atomic::AtomicI64> =
144                    std::sync::LazyLock::new(|| std::sync::atomic::AtomicI64::new(0));
145
146                pub fn [<current _$name>]() -> i64 {
147                    #[cfg(feature = "stat")]
148                    { $id.load(std::sync::atomic::Ordering::Relaxed) }
149
150                    #[cfg(not(feature = "stat"))]
151                    { -1 }
152                }
153
154                pub fn [<reset _$name>]() {
155                    #[cfg(feature = "stat")]
156                    $id.store(0, std::sync::atomic::Ordering::Relaxed);
157                }
158
159                pub(crate) fn [<increase _$name>]() {
160                    #[cfg(feature = "stat")]
161                    $id.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
162                }
163
164                pub fn [<assert_eq _$name>](_value: i64) {
165                    #[cfg(feature = "stat")]
166                    assert_eq!([<current _$name>](), _value);
167                }
168
169                pub fn [<assert_ne _$name>](_value: i64) {
170                    #[cfg(feature = "stat")]
171                    assert_ne!([<current _$name>](), _value);
172                }
173            }
174        };
175    }
176
177    decl_counter!(system_task_count, SYS_CNT);
178    decl_counter!(future_task_count, FUT_CNT);
179    decl_counter!(parallel_task_count, PAR_CNT);
180}