hephae_utils/
query_ext.rs1use std::{
2 mem::MaybeUninit,
3 ops::{Deref, DerefMut},
4};
5
6use bevy_ecs::prelude::*;
7
8pub trait ComponentOption<T: Deref<Target: Component + Sized>>: Sized {
10 fn get_or_insert_with(self, commands: EntityCommands, insert: impl FnOnce() -> T::Target) -> RefOrInsert<T>;
12
13 #[inline]
15 fn get_or_insert(self, commands: EntityCommands, insert: T::Target) -> RefOrInsert<T> {
16 self.get_or_insert_with(commands, || insert)
17 }
18
19 #[inline]
21 fn get_or_default(self, commands: EntityCommands) -> RefOrInsert<T>
22 where
23 T::Target: Default,
24 {
25 self.get_or_insert_with(commands, T::Target::default)
26 }
27}
28
29impl<T: Deref<Target: Component + Sized>> ComponentOption<T> for Option<T> {
30 #[inline]
31 fn get_or_insert_with(self, commands: EntityCommands, insert: impl FnOnce() -> <T as Deref>::Target) -> RefOrInsert<T> {
32 RefOrInsert(match self {
33 Some(val) => RefOrInsertInner::Ref(val),
34 None => RefOrInsertInner::Spawn(MaybeUninit::new(insert()), commands),
35 })
36 }
37}
38
39pub struct RefOrInsert<'a, T: Deref<Target: Component + Sized>>(RefOrInsertInner<'a, T>);
41impl<T: Deref<Target: Component + Sized>> Deref for RefOrInsert<'_, T> {
42 type Target = T::Target;
43
44 #[inline]
45 fn deref(&self) -> &Self::Target {
46 match self.0 {
47 RefOrInsertInner::Ref(ref val) => val,
48 RefOrInsertInner::Spawn(ref val, ..) => unsafe { val.assume_init_ref() },
49 }
50 }
51}
52
53impl<T: DerefMut<Target: Component + Sized>> DerefMut for RefOrInsert<'_, T> {
54 #[inline]
55 fn deref_mut(&mut self) -> &mut Self::Target {
56 match self.0 {
57 RefOrInsertInner::Ref(ref mut val) => val,
58 RefOrInsertInner::Spawn(ref mut val, ..) => unsafe { val.assume_init_mut() },
59 }
60 }
61}
62
63impl<T: Deref<Target: Component + Sized>> Drop for RefOrInsert<'_, T> {
64 fn drop(&mut self) {
65 if let RefOrInsertInner::Spawn(insert, commands) = &mut self.0 {
66 commands.insert(unsafe { insert.assume_init_read() });
67 }
68 }
69}
70
71enum RefOrInsertInner<'a, T: Deref<Target: Component + Sized>> {
72 Ref(T),
73 Spawn(MaybeUninit<T::Target>, EntityCommands<'a>),
74}