steel_registry/data_components/registry/
patch.rs1use super::{
2 Component, ComponentData, DataComponentMap, DataComponentType, Debug, DowncastType, FxHashMap,
3 Identifier,
4};
5
6#[derive(Debug, Clone)]
8pub enum ComponentPatchEntry {
9 Set(ComponentData),
11 Removed,
13}
14
15impl PartialEq for ComponentPatchEntry {
16 fn eq(&self, other: &Self) -> bool {
17 match (self, other) {
18 (Self::Removed, Self::Removed) => true,
19 (Self::Set(a), Self::Set(b)) => a == b,
20 _ => false,
21 }
22 }
23}
24
25#[derive(Debug, Default, Clone, PartialEq)]
31pub struct DataComponentPatch {
32 pub(super) entries: FxHashMap<Identifier, ComponentPatchEntry>,
33}
34
35impl DataComponentPatch {
36 #[must_use]
37 pub fn new() -> Self {
38 Self {
39 entries: FxHashMap::default(),
40 }
41 }
42
43 #[must_use]
44 pub fn is_empty(&self) -> bool {
45 self.entries.is_empty()
46 }
47
48 #[must_use]
49 pub fn len(&self) -> usize {
50 self.entries.len()
51 }
52
53 pub fn set<T: Component + DowncastType>(&mut self, component: DataComponentType<T>, value: T) {
55 self.entries.insert(
56 component.key.clone(),
57 ComponentPatchEntry::Set(ComponentData::new(value)),
58 );
59 }
60
61 pub(crate) fn set_component_data(&mut self, key: Identifier, data: ComponentData) {
62 self.entries.insert(key, ComponentPatchEntry::Set(data));
63 }
64
65 pub fn set_raw(&mut self, key: Identifier, data: ComponentData) -> bool {
72 use crate::{REGISTRY, RegistryExt};
73
74 let Some(entry) = REGISTRY.data_components.by_key(&key) else {
75 return false;
76 };
77 if !entry.validates(&data) {
78 return false;
79 }
80
81 self.entries.insert(key, ComponentPatchEntry::Set(data));
82 true
83 }
84
85 pub fn remove<T>(&mut self, component: DataComponentType<T>) {
87 self.entries
88 .insert(component.key.clone(), ComponentPatchEntry::Removed);
89 }
90
91 pub fn remove_raw(&mut self, key: Identifier) -> bool {
93 use crate::{REGISTRY, RegistryExt};
94
95 if REGISTRY.data_components.by_key(&key).is_none() {
96 return false;
97 }
98 self.entries.insert(key, ComponentPatchEntry::Removed);
99 true
100 }
101
102 pub fn clear<T>(&mut self, component: DataComponentType<T>) {
104 self.entries.remove(&component.key);
105 }
106
107 #[must_use]
109 pub fn get_entry(&self, key: &Identifier) -> Option<&ComponentPatchEntry> {
110 self.entries.get(key)
111 }
112
113 #[must_use]
115 pub fn is_removed(&self, key: &Identifier) -> bool {
116 matches!(self.entries.get(key), Some(ComponentPatchEntry::Removed))
117 }
118
119 #[must_use]
121 pub fn count_set(&self) -> usize {
122 self.entries
123 .values()
124 .filter(|e| matches!(e, ComponentPatchEntry::Set(_)))
125 .count()
126 }
127
128 #[must_use]
130 pub fn count_removed(&self) -> usize {
131 self.entries
132 .values()
133 .filter(|e| matches!(e, ComponentPatchEntry::Removed))
134 .count()
135 }
136
137 pub fn iter(&self) -> impl Iterator<Item = (&Identifier, &ComponentPatchEntry)> {
139 self.entries.iter()
140 }
141
142 pub fn apply(&mut self, added: &Self) {
144 self.entries.extend(
145 added
146 .entries
147 .iter()
148 .map(|(key, entry)| (key.clone(), entry.clone())),
149 );
150 }
151
152 pub(crate) fn sanitize_against(&mut self, prototype: &DataComponentMap) {
153 self.entries.retain(|key, entry| {
154 let default = prototype.get_raw(key);
155 match entry {
156 ComponentPatchEntry::Set(value) => default != Some(value),
157 ComponentPatchEntry::Removed => default.is_some(),
158 }
159 });
160 }
161}