specs/storage/
deref_flagged.rs

1use std::{
2    marker::PhantomData,
3    ops::{Deref, DerefMut},
4};
5
6use hibitset::BitSetLike;
7
8use crate::{
9    storage::{
10        AccessMut, ComponentEvent, DenseVecStorage, Tracked, TryDefault, UnprotectedStorage,
11    },
12    world::{Component, Index},
13};
14
15use shrev::EventChannel;
16
17/// Wrapper storage that tracks modifications, insertions, and removals of
18/// components through an `EventChannel`, in a similar manner to
19/// `FlaggedStorage`.
20///
21/// Unlike `FlaggedStorage`, this storage uses a wrapper type for mutable
22/// accesses that only emits modification events when the component is actually
23/// used mutably. This means that simply performing a mutable join or calling
24/// `WriteStorage::get_mut` will not, by itself, trigger a modification event.
25pub struct DerefFlaggedStorage<C, T = DenseVecStorage<C>> {
26    channel: EventChannel<ComponentEvent>,
27    storage: T,
28    #[cfg(feature = "storage-event-control")]
29    event_emission: bool,
30    phantom: PhantomData<C>,
31}
32
33impl<C, T> DerefFlaggedStorage<C, T> {
34    #[cfg(feature = "storage-event-control")]
35    fn emit_event(&self) -> bool {
36        self.event_emission
37    }
38
39    #[cfg(not(feature = "storage-event-control"))]
40    fn emit_event(&self) -> bool {
41        true
42    }
43}
44
45impl<C, T> Default for DerefFlaggedStorage<C, T>
46where
47    T: TryDefault,
48{
49    fn default() -> Self {
50        Self {
51            channel: EventChannel::<ComponentEvent>::default(),
52            storage: T::unwrap_default(),
53            #[cfg(feature = "storage-event-control")]
54            event_emission: true,
55            phantom: PhantomData,
56        }
57    }
58}
59
60impl<C: Component, T: UnprotectedStorage<C>> UnprotectedStorage<C> for DerefFlaggedStorage<C, T> {
61    type AccessMut<'a> = FlaggedAccessMut<'a, <T as UnprotectedStorage<C>>::AccessMut<'a>, C>
62        where T: 'a;
63
64    unsafe fn clean<B>(&mut self, has: B)
65    where
66        B: BitSetLike,
67    {
68        // SAFETY: Requirements passed to caller.
69        unsafe { self.storage.clean(has) };
70    }
71
72    unsafe fn get(&self, id: Index) -> &C {
73        // SAFETY: Requirements passed to caller.
74        unsafe { self.storage.get(id) }
75    }
76
77    unsafe fn get_mut(&mut self, id: Index) -> Self::AccessMut<'_> {
78        let emit = self.emit_event();
79        FlaggedAccessMut {
80            channel: &mut self.channel,
81            emit,
82            id,
83            // SAFETY: Requirements passed to caller.
84            access: unsafe { self.storage.get_mut(id) },
85            phantom: PhantomData,
86        }
87    }
88
89    unsafe fn insert(&mut self, id: Index, comp: C) {
90        if self.emit_event() {
91            self.channel.single_write(ComponentEvent::Inserted(id));
92        }
93        // SAFETY: Requirements passed to caller.
94        unsafe { self.storage.insert(id, comp) };
95    }
96
97    unsafe fn remove(&mut self, id: Index) -> C {
98        if self.emit_event() {
99            self.channel.single_write(ComponentEvent::Removed(id));
100        }
101        // SAFETY: Requirements passed to caller.
102        unsafe { self.storage.remove(id) }
103    }
104}
105
106impl<C, T> Tracked for DerefFlaggedStorage<C, T> {
107    fn channel(&self) -> &EventChannel<ComponentEvent> {
108        &self.channel
109    }
110
111    fn channel_mut(&mut self) -> &mut EventChannel<ComponentEvent> {
112        &mut self.channel
113    }
114
115    #[cfg(feature = "storage-event-control")]
116    fn set_event_emission(&mut self, emit: bool) {
117        self.event_emission = emit;
118    }
119
120    #[cfg(feature = "storage-event-control")]
121    fn event_emission(&self) -> bool {
122        self.event_emission
123    }
124}
125
126/// Wrapper type only emits modificaition events when the component is accessed
127/// via mutably dereferencing. Also see [`DerefFlaggedStorage`] documentation.
128pub struct FlaggedAccessMut<'a, A, C> {
129    channel: &'a mut EventChannel<ComponentEvent>,
130    emit: bool,
131    id: Index,
132    access: A,
133    phantom: PhantomData<C>,
134}
135
136impl<'a, A, C> Deref for FlaggedAccessMut<'a, A, C>
137where
138    A: Deref<Target = C>,
139{
140    type Target = C;
141
142    fn deref(&self) -> &Self::Target {
143        self.access.deref()
144    }
145}
146
147impl<'a, A, C> DerefMut for FlaggedAccessMut<'a, A, C>
148where
149    A: AccessMut<Target = C>,
150{
151    fn deref_mut(&mut self) -> &mut Self::Target {
152        if self.emit {
153            self.channel.single_write(ComponentEvent::Modified(self.id));
154        }
155        self.access.access_mut()
156    }
157}