1use crate::component::RegistrationError;
7use crate::entity::EntityId;
8use crate::time::ChangeTick;
9use alloc::string::String;
10
11#[non_exhaustive]
13#[derive(Clone, Debug, Eq, PartialEq)]
14pub enum WorldAllocatorError {
15 GenerationOverflow,
16 SlotRetired,
17}
18
19#[derive(Copy, Clone, Debug, Eq, PartialEq)]
21pub struct FlushReport {
22 pub commands_applied: usize,
24 pub change_tick: ChangeTick,
26}
27
28#[non_exhaustive]
30#[derive(Clone, Debug, Eq, PartialEq)]
31pub enum FlushError {
32 CommandValidation { index: usize, detail: String },
33 ChangeTickExhausted,
34}
35
36#[non_exhaustive]
38#[derive(Clone, Debug, Eq, PartialEq)]
39pub enum WorldError {
40 EntityOwnerMismatch { entity: EntityId },
41 StaleEntity { entity: EntityId },
42 EntityNotLive { entity: EntityId },
43 UnregisteredComponent { name: String },
44 WrongStorageKind { name: String },
45 Registration(RegistrationError),
46 Allocator(WorldAllocatorError),
47 ChangeTickExhausted,
48 StructuralMutationDuringRun,
49 StructuralCommandsDuringRender,
50 FlushDuringRun,
51 DiscardDuringRun,
52 Flush(FlushError),
53 UnregisteredResource { name: String },
54 ResourceInUse { name: String },
55 ResourceScoped { name: String },
56 UnregisteredEvent { name: String },
57 EventChannelClosed,
58 NestedRun,
59}
60
61impl From<RegistrationError> for WorldError {
62 fn from(value: RegistrationError) -> Self {
63 Self::Registration(value)
64 }
65}
66
67impl From<FlushError> for WorldError {
68 fn from(value: FlushError) -> Self {
69 Self::Flush(value)
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use crate::component::RegistrationError;
77
78 #[test]
79 fn registration_error_converts_into_world_error() {
80 let error: WorldError = RegistrationError::InvalidTag {
81 name: String::from("tag"),
82 detail: String::from("detail"),
83 }
84 .into();
85 assert!(matches!(error, WorldError::Registration(_)));
86 }
87}
88
89#[non_exhaustive]
91#[derive(Clone, Debug, Eq, PartialEq)]
92pub enum EventReadError {
93 Lagged { dropped: u64 },
94 ChannelClosed,
95 UnregisteredEvent { name: String },
96 OwnerMismatch { name: String },
97}
98
99#[cfg(feature = "std")]
100impl core::fmt::Display for WorldAllocatorError {
101 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
102 match self {
103 Self::GenerationOverflow => f.write_str("entity generation overflow"),
104 Self::SlotRetired => f.write_str("entity slot retired"),
105 }
106 }
107}
108
109#[cfg(feature = "std")]
110impl std::error::Error for WorldAllocatorError {}
111
112#[cfg(feature = "std")]
113impl core::fmt::Display for FlushError {
114 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115 match self {
116 Self::CommandValidation { index, detail } => {
117 write!(f, "command {index} failed validation: {detail}")
118 }
119 Self::ChangeTickExhausted => f.write_str("change tick exhausted during flush"),
120 }
121 }
122}
123
124#[cfg(feature = "std")]
125impl std::error::Error for FlushError {}
126
127#[cfg(feature = "std")]
128impl core::fmt::Display for WorldError {
129 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
130 match self {
131 Self::EntityOwnerMismatch { entity } => {
132 write!(
133 f,
134 "entity {:?}:{:?} belongs to another world",
135 entity.slot(),
136 entity.generation()
137 )
138 }
139 Self::StaleEntity { entity } => {
140 write!(
141 f,
142 "stale entity {:?}:{:?}",
143 entity.slot(),
144 entity.generation()
145 )
146 }
147 Self::EntityNotLive { entity } => {
148 write!(
149 f,
150 "entity {:?}:{:?} is not live",
151 entity.slot(),
152 entity.generation()
153 )
154 }
155 Self::UnregisteredComponent { name } => {
156 write!(f, "unregistered component {name}")
157 }
158 Self::WrongStorageKind { name } => {
159 write!(f, "wrong storage kind for {name}")
160 }
161 Self::Registration(error) => write!(f, "component registration failed: {error}"),
162 Self::Allocator(error) => write!(f, "entity allocator failed: {error}"),
163 Self::ChangeTickExhausted => f.write_str("change tick exhausted"),
164 Self::StructuralMutationDuringRun => {
165 f.write_str("structural mutation is deferred while the world is running")
166 }
167 Self::StructuralCommandsDuringRender => {
168 f.write_str("structural commands are unavailable during render")
169 }
170 Self::FlushDuringRun => f.write_str("flush is idle-only"),
171 Self::DiscardDuringRun => f.write_str("discard_commands is idle-only"),
172 Self::Flush(error) => write!(f, "flush failed: {error}"),
173 Self::UnregisteredResource { name } => write!(f, "unregistered resource {name}"),
174 Self::ResourceInUse { name } => write!(f, "resource {name} is in use"),
175 Self::ResourceScoped { name } => write!(f, "resource {name} is scoped"),
176 Self::UnregisteredEvent { name } => write!(f, "unregistered event {name}"),
177 Self::EventChannelClosed => f.write_str("event channel is closed"),
178 Self::NestedRun => f.write_str("nested world execution is not supported"),
179 }
180 }
181}
182
183#[cfg(feature = "std")]
184impl std::error::Error for WorldError {
185 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
186 match self {
187 Self::Registration(error) => Some(error),
188 Self::Allocator(error) => Some(error),
189 Self::Flush(error) => Some(error),
190 _ => None,
191 }
192 }
193}
194
195#[cfg(feature = "std")]
196impl core::fmt::Display for EventReadError {
197 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
198 match self {
199 Self::Lagged { dropped } => write!(f, "event reader lagged by {dropped} events"),
200 Self::ChannelClosed => f.write_str("event channel is closed"),
201 Self::UnregisteredEvent { name } => write!(f, "unregistered event {name}"),
202 Self::OwnerMismatch { name } => write!(f, "event reader owner mismatch for {name}"),
203 }
204 }
205}
206
207#[cfg(feature = "std")]
208impl std::error::Error for EventReadError {}