1use super::{
2 ent::{component::Component, entity::EntityId},
3 entry::Ecs,
4 post::EntMoveStorage,
5 sched::comm::CommandSender,
6 DynResult,
7};
8use crate::{ds::ReadyFuture, util::macros::impl_from_for_enum};
9use std::{fmt, ptr::NonNull, sync::MutexGuard};
10
11pub mod prelude {
12 pub use super::Command;
13}
14
15pub trait Command: Send + 'static {
36 #[allow(unused_variables)]
40 fn command(&mut self, ecs: Ecs<'_>) -> DynResult<()>;
41
42 fn cancel(&mut self) {}
47}
48
49impl fmt::Debug for dyn Command {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 write!(f, "dyn Command")
52 }
53}
54
55impl<F> Command for Option<F>
56where
57 F: FnOnce(Ecs) -> DynResult<()> + Send + 'static,
58{
59 fn command(&mut self, ecs: Ecs<'_>) -> DynResult<()> {
60 if let Some(f) = self.take() {
61 f(ecs)
62 } else {
63 Err("command has been taken".into())
64 }
65 }
66}
67
68impl<F> Command for F
69where
70 F: FnMut(Ecs) -> DynResult<()> + Send + 'static,
71{
72 fn command(&mut self, ecs: Ecs<'_>) -> DynResult<()> {
73 self(ecs)
74 }
75}
76
77impl<F> Command for DynResult<F>
78where
79 F: FnOnce(Ecs) -> DynResult<()> + Send + 'static,
80{
81 fn command(&mut self, ecs: Ecs<'_>) -> DynResult<()> {
82 let empty = Err("command has been taken".into());
83 let this = std::mem::replace(self, empty);
84
85 match this {
86 Ok(f) => f(ecs),
87 Err(e) => Err(e),
88 }
89 }
90}
91
92impl Command for DynResult<()> {
97 fn command(&mut self, _ecs: Ecs<'_>) -> DynResult<()> {
98 let empty = Err("command has been taken".into());
99 std::mem::replace(self, empty)
100 }
101}
102
103impl Command for () {
108 fn command(&mut self, _ecs: Ecs<'_>) -> DynResult<()> {
109 Ok(())
110 }
111}
112
113#[derive(Debug)]
114pub(crate) enum CommandObject {
115 Boxed(Box<dyn Command>),
117
118 Future(ReadyFuture),
120
121 Raw(RawCommand),
122}
123
124impl_from_for_enum!("outer" = CommandObject; "var" = Boxed; "inner" = Box<dyn Command>);
125impl_from_for_enum!("outer" = CommandObject; "var" = Future; "inner" = ReadyFuture);
126impl_from_for_enum!("outer" = CommandObject; "var" = Raw; "inner" = RawCommand);
127
128impl CommandObject {
129 pub(crate) fn command(self, ecs: Ecs<'_>) -> DynResult<()> {
130 match self {
131 Self::Boxed(mut boxed) => boxed.command(ecs),
132 Self::Future(future) => {
133 unsafe { future.consume::<Ecs<'_>, DynResult<()>>(ecs) }
138 }
139 Self::Raw(raw) => raw.command(ecs),
140 }
141 }
142
143 pub(crate) fn cancel(self) {
144 match self {
145 Self::Boxed(mut boxed) => boxed.cancel(),
146 Self::Future(_future) => {}
147 Self::Raw(raw) => raw.cancel(),
148 }
149 }
150}
151
152#[derive(Debug)]
154pub(crate) struct RawCommand {
155 data: NonNull<u8>,
156 command: unsafe fn(NonNull<u8>, Ecs<'_>) -> DynResult<()>,
157 cancel: unsafe fn(NonNull<u8>),
158}
159
160unsafe impl Send for RawCommand {}
161
162impl RawCommand {
163 pub(crate) unsafe fn new<C: Command>(cmd: &C) -> Self {
164 let data = unsafe { NonNull::new_unchecked((cmd as *const _ as *const u8).cast_mut()) };
165
166 unsafe fn command<C: Command>(data: NonNull<u8>, ecs: Ecs<'_>) -> DynResult<()> {
167 let data = unsafe { data.cast::<C>().as_mut() };
168 data.command(ecs)
169 }
170
171 unsafe fn cancel<C: Command>(data: NonNull<u8>) {
172 let data = unsafe { data.cast::<C>().as_mut() };
173 data.cancel();
174 }
175
176 Self {
177 data,
178 command: command::<C>,
179 cancel: cancel::<C>,
180 }
181 }
182
183 fn command(self, ecs: Ecs<'_>) -> DynResult<()> {
184 unsafe { (self.command)(self.data, ecs) }
187 }
188
189 fn cancel(self) {
190 unsafe { (self.cancel)(self.data) };
193 }
194}
195
196pub struct EntityMoveCommandBuilder<'a> {
210 tx_cmd: &'a CommandSender,
211 guard: MutexGuard<'a, EntMoveStorage>,
212 eid: EntityId,
213 len: usize,
214}
215
216impl<'a> EntityMoveCommandBuilder<'a> {
217 pub(crate) const fn new(
218 tx_cmd: &'a CommandSender,
219 guard: MutexGuard<'a, EntMoveStorage>,
220 eid: EntityId,
221 ) -> Self {
222 Self {
223 tx_cmd,
224 guard,
225 eid,
226 len: 0,
227 }
228 }
229
230 pub fn finish(mut self) -> impl Command + 'static {
232 assert!(self.len > 0);
233
234 let cmd = self._finish();
235
236 self.len = 0;
238 drop(self);
239
240 cmd
241 }
242
243 pub fn attach<C: Component>(mut self, component: C) -> Self {
248 self.guard.insert_addition(self.eid, component);
249 self.len += 1;
250 self
251 }
252
253 pub fn detach<C: Component>(mut self) -> Self {
258 self.guard.insert_removal(self.eid, C::key());
259 self.len += 1;
260 self
261 }
262
263 fn _finish(&mut self) -> EntityMoveCommand {
264 self.guard.set_command_length(self.len);
265 EntityMoveCommand
266 }
267}
268
269impl Drop for EntityMoveCommandBuilder<'_> {
270 fn drop(&mut self) {
271 if self.len > 0 {
272 let cmd = self._finish();
273 self.tx_cmd
275 .send_or_cancel(CommandObject::Boxed(Box::new(cmd)));
276 }
277 }
278}
279
280struct EntityMoveCommand;
281
282impl Command for EntityMoveCommand {
283 fn command(&mut self, ecs: Ecs<'_>) -> DynResult<()> {
284 let post = unsafe { ecs.post_ptr().as_ref() };
285 let mut guard = post.lock_entity_move_storage();
286 guard.consume(ecs);
287 Ok(())
288 }
289}