steel_registry/data_components/registry/
patch.rs1use super::{
2 Component, ComponentData, DataComponentMap, DataComponentType, Debug, DowncastType, FxHashMap,
3 Identifier,
4};
5use rustc_hash::FxBuildHasher;
6
7static EMPTY: DataComponentPatch = DataComponentPatch {
8 entries: FxHashMap::with_hasher(FxBuildHasher),
9};
10
11#[derive(Debug, Clone)]
13pub enum ComponentPatchEntry {
14 Set(ComponentData),
16 Removed,
18}
19
20impl PartialEq for ComponentPatchEntry {
21 fn eq(&self, other: &Self) -> bool {
22 match (self, other) {
23 (Self::Removed, Self::Removed) => true,
24 (Self::Set(a), Self::Set(b)) => a == b,
25 _ => false,
26 }
27 }
28}
29
30#[derive(Debug, Default, Clone, PartialEq)]
36pub struct DataComponentPatch {
37 pub(super) entries: FxHashMap<Identifier, ComponentPatchEntry>,
38}
39
40impl DataComponentPatch {
41 #[must_use]
43 pub fn empty() -> &'static Self {
44 &EMPTY
45 }
46
47 #[must_use]
48 pub fn new() -> Self {
49 Self {
50 entries: FxHashMap::default(),
51 }
52 }
53
54 #[must_use]
55 pub fn is_empty(&self) -> bool {
56 self.entries.is_empty()
57 }
58
59 #[must_use]
60 pub fn len(&self) -> usize {
61 self.entries.len()
62 }
63
64 pub fn set<T: Component + DowncastType>(&mut self, component: DataComponentType<T>, value: T) {
66 self.entries.insert(
67 component.key,
68 ComponentPatchEntry::Set(ComponentData::new(value)),
69 );
70 }
71
72 pub(crate) fn set_component_data(&mut self, key: Identifier, data: ComponentData) {
73 self.entries.insert(key, ComponentPatchEntry::Set(data));
74 }
75
76 pub fn set_raw(&mut self, key: Identifier, data: ComponentData) -> bool {
83 use crate::{REGISTRY, RegistryExt};
84
85 let Some(entry) = REGISTRY.data_components.by_key(&key) else {
86 return false;
87 };
88 if !entry.validates(&data) {
89 return false;
90 }
91
92 self.entries.insert(key, ComponentPatchEntry::Set(data));
93 true
94 }
95
96 pub fn remove<T>(&mut self, component: DataComponentType<T>) {
98 self.entries
99 .insert(component.key, ComponentPatchEntry::Removed);
100 }
101
102 pub fn remove_raw(&mut self, key: Identifier) -> bool {
104 use crate::{REGISTRY, RegistryExt};
105
106 if REGISTRY.data_components.by_key(&key).is_none() {
107 return false;
108 }
109 self.entries.insert(key, ComponentPatchEntry::Removed);
110 true
111 }
112
113 pub fn clear<T>(&mut self, component: DataComponentType<T>) {
115 self.entries.remove(&component.key);
116 }
117
118 #[must_use]
120 pub fn get_entry(&self, key: &Identifier) -> Option<&ComponentPatchEntry> {
121 self.entries.get(key)
122 }
123
124 #[must_use]
126 pub fn is_removed(&self, key: &Identifier) -> bool {
127 matches!(self.entries.get(key), Some(ComponentPatchEntry::Removed))
128 }
129
130 #[must_use]
132 pub fn count_set(&self) -> usize {
133 self.entries
134 .values()
135 .filter(|e| matches!(e, ComponentPatchEntry::Set(_)))
136 .count()
137 }
138
139 #[must_use]
141 pub fn count_removed(&self) -> usize {
142 self.entries
143 .values()
144 .filter(|e| matches!(e, ComponentPatchEntry::Removed))
145 .count()
146 }
147
148 pub fn iter(&self) -> impl Iterator<Item = (&Identifier, &ComponentPatchEntry)> {
150 self.entries.iter()
151 }
152
153 pub fn apply(&mut self, added: &Self) {
155 self.entries.extend(
156 added
157 .entries
158 .iter()
159 .map(|(key, entry)| (key.clone(), entry.clone())),
160 );
161 }
162
163 pub(crate) fn sanitize_against(&mut self, prototype: &DataComponentMap) {
164 self.entries.retain(|key, entry| {
165 let default = prototype.get_raw(key);
166 match entry {
167 ComponentPatchEntry::Set(value) => default != Some(value),
168 ComponentPatchEntry::Removed => default.is_some(),
169 }
170 });
171 }
172}