1use core::fmt::{Debug, Formatter};
2
3use bevy_reflect_derive::impl_type_path;
4use bevy_utils::hashbrown::{hash_table::OccupiedEntry as HashTableOccupiedEntry, HashTable};
5
6use crate::generics::impl_generic_info_methods;
7use crate::{
8 self as bevy_reflect, hash_error, type_info::impl_type_methods, ApplyError, Generics,
9 PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type, TypeInfo,
10 TypePath,
11};
12
13pub trait Set: PartialReflect {
49 fn get(&self, value: &dyn PartialReflect) -> Option<&dyn PartialReflect>;
53
54 fn len(&self) -> usize;
56
57 fn is_empty(&self) -> bool {
59 self.len() == 0
60 }
61
62 fn iter(&self) -> Box<dyn Iterator<Item = &dyn PartialReflect> + '_>;
64
65 fn drain(&mut self) -> Vec<Box<dyn PartialReflect>>;
69
70 fn clone_dynamic(&self) -> DynamicSet;
72
73 fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) -> bool;
78
79 fn remove(&mut self, value: &dyn PartialReflect) -> bool;
84
85 fn contains(&self, value: &dyn PartialReflect) -> bool;
87}
88
89#[derive(Clone, Debug)]
91pub struct SetInfo {
92 ty: Type,
93 generics: Generics,
94 value_ty: Type,
95 #[cfg(feature = "documentation")]
96 docs: Option<&'static str>,
97}
98
99impl SetInfo {
100 pub fn new<TSet: Set + TypePath, TValue: Reflect + TypePath>() -> Self {
102 Self {
103 ty: Type::of::<TSet>(),
104 generics: Generics::new(),
105 value_ty: Type::of::<TValue>(),
106 #[cfg(feature = "documentation")]
107 docs: None,
108 }
109 }
110
111 #[cfg(feature = "documentation")]
113 pub fn with_docs(self, docs: Option<&'static str>) -> Self {
114 Self { docs, ..self }
115 }
116
117 impl_type_methods!(ty);
118
119 pub fn value_ty(&self) -> Type {
123 self.value_ty
124 }
125
126 #[cfg(feature = "documentation")]
128 pub fn docs(&self) -> Option<&'static str> {
129 self.docs
130 }
131
132 impl_generic_info_methods!(generics);
133}
134
135#[derive(Default)]
137pub struct DynamicSet {
138 represented_type: Option<&'static TypeInfo>,
139 hash_table: HashTable<Box<dyn PartialReflect>>,
140}
141
142impl DynamicSet {
143 pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
151 if let Some(represented_type) = represented_type {
152 assert!(
153 matches!(represented_type, TypeInfo::Set(_)),
154 "expected TypeInfo::Set but received: {:?}",
155 represented_type
156 );
157 }
158
159 self.represented_type = represented_type;
160 }
161
162 pub fn insert<V: Reflect>(&mut self, value: V) {
164 self.insert_boxed(Box::new(value));
165 }
166
167 fn internal_hash(value: &dyn PartialReflect) -> u64 {
168 value.reflect_hash().expect(hash_error!(value))
169 }
170
171 fn internal_eq(
172 value: &dyn PartialReflect,
173 ) -> impl FnMut(&Box<dyn PartialReflect>) -> bool + '_ {
174 |other| {
175 value
176 .reflect_partial_eq(&**other)
177 .expect("Underlying type does not reflect `PartialEq` and hence doesn't support equality checks")
178 }
179 }
180}
181
182impl Set for DynamicSet {
183 fn get(&self, value: &dyn PartialReflect) -> Option<&dyn PartialReflect> {
184 self.hash_table
185 .find(Self::internal_hash(value), Self::internal_eq(value))
186 .map(|value| &**value)
187 }
188
189 fn len(&self) -> usize {
190 self.hash_table.len()
191 }
192
193 fn iter(&self) -> Box<dyn Iterator<Item = &dyn PartialReflect> + '_> {
194 let iter = self.hash_table.iter().map(|v| &**v);
195 Box::new(iter)
196 }
197
198 fn drain(&mut self) -> Vec<Box<dyn PartialReflect>> {
199 self.hash_table.drain().collect::<Vec<_>>()
200 }
201
202 fn clone_dynamic(&self) -> DynamicSet {
203 let mut hash_table = HashTable::new();
204 self.hash_table
205 .iter()
206 .map(|value| value.clone_value())
207 .for_each(|value| {
208 hash_table.insert_unique(Self::internal_hash(value.as_ref()), value, |boxed| {
209 Self::internal_hash(boxed.as_ref())
210 });
211 });
212
213 DynamicSet {
214 represented_type: self.represented_type,
215 hash_table,
216 }
217 }
218
219 fn insert_boxed(&mut self, value: Box<dyn PartialReflect>) -> bool {
220 assert_eq!(
221 value.reflect_partial_eq(&*value),
222 Some(true),
223 "Values inserted in `Set` like types are expected to reflect `PartialEq`"
224 );
225 match self
226 .hash_table
227 .find_mut(Self::internal_hash(&*value), Self::internal_eq(&*value))
228 {
229 Some(old) => {
230 *old = value;
231 false
232 }
233 None => {
234 self.hash_table.insert_unique(
235 Self::internal_hash(value.as_ref()),
236 value,
237 |boxed| Self::internal_hash(boxed.as_ref()),
238 );
239 true
240 }
241 }
242 }
243
244 fn remove(&mut self, value: &dyn PartialReflect) -> bool {
245 self.hash_table
246 .find_entry(Self::internal_hash(value), Self::internal_eq(value))
247 .map(HashTableOccupiedEntry::remove)
248 .is_ok()
249 }
250
251 fn contains(&self, value: &dyn PartialReflect) -> bool {
252 self.hash_table
253 .find(Self::internal_hash(value), Self::internal_eq(value))
254 .is_some()
255 }
256}
257
258impl PartialReflect for DynamicSet {
259 #[inline]
260 fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
261 self.represented_type
262 }
263
264 #[inline]
265 fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
266 self
267 }
268
269 #[inline]
270 fn as_partial_reflect(&self) -> &dyn PartialReflect {
271 self
272 }
273
274 #[inline]
275 fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
276 self
277 }
278
279 #[inline]
280 fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
281 Err(self)
282 }
283
284 #[inline]
285 fn try_as_reflect(&self) -> Option<&dyn Reflect> {
286 None
287 }
288
289 #[inline]
290 fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
291 None
292 }
293
294 fn apply(&mut self, value: &dyn PartialReflect) {
295 set_apply(self, value);
296 }
297
298 fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
299 set_try_apply(self, value)
300 }
301
302 fn reflect_kind(&self) -> ReflectKind {
303 ReflectKind::Set
304 }
305
306 fn reflect_ref(&self) -> ReflectRef {
307 ReflectRef::Set(self)
308 }
309
310 fn reflect_mut(&mut self) -> ReflectMut {
311 ReflectMut::Set(self)
312 }
313
314 fn reflect_owned(self: Box<Self>) -> ReflectOwned {
315 ReflectOwned::Set(self)
316 }
317
318 fn clone_value(&self) -> Box<dyn PartialReflect> {
319 Box::new(self.clone_dynamic())
320 }
321
322 fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
323 set_partial_eq(self, value)
324 }
325
326 fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
327 write!(f, "DynamicSet(")?;
328 set_debug(self, f)?;
329 write!(f, ")")
330 }
331
332 #[inline]
333 fn is_dynamic(&self) -> bool {
334 true
335 }
336}
337
338impl_type_path!((in bevy_reflect) DynamicSet);
339
340impl Debug for DynamicSet {
341 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
342 self.debug(f)
343 }
344}
345
346impl FromIterator<Box<dyn PartialReflect>> for DynamicSet {
347 fn from_iter<I: IntoIterator<Item = Box<dyn PartialReflect>>>(values: I) -> Self {
348 let mut this = Self {
349 represented_type: None,
350 hash_table: HashTable::new(),
351 };
352
353 for value in values {
354 this.insert_boxed(value);
355 }
356
357 this
358 }
359}
360
361impl<T: Reflect> FromIterator<T> for DynamicSet {
362 fn from_iter<I: IntoIterator<Item = T>>(values: I) -> Self {
363 let mut this = Self {
364 represented_type: None,
365 hash_table: HashTable::new(),
366 };
367
368 for value in values {
369 this.insert(value);
370 }
371
372 this
373 }
374}
375
376impl IntoIterator for DynamicSet {
377 type Item = Box<dyn PartialReflect>;
378 type IntoIter = bevy_utils::hashbrown::hash_table::IntoIter<Self::Item>;
379
380 fn into_iter(self) -> Self::IntoIter {
381 self.hash_table.into_iter()
382 }
383}
384
385impl<'a> IntoIterator for &'a DynamicSet {
386 type Item = &'a dyn PartialReflect;
387 type IntoIter = core::iter::Map<
388 bevy_utils::hashbrown::hash_table::Iter<'a, Box<dyn PartialReflect>>,
389 fn(&'a Box<dyn PartialReflect>) -> Self::Item,
390 >;
391
392 fn into_iter(self) -> Self::IntoIter {
393 self.hash_table.iter().map(|v| v.as_ref())
394 }
395}
396
397#[inline]
407pub fn set_partial_eq<M: Set>(a: &M, b: &dyn PartialReflect) -> Option<bool> {
408 let ReflectRef::Set(set) = b.reflect_ref() else {
409 return Some(false);
410 };
411
412 if a.len() != set.len() {
413 return Some(false);
414 }
415
416 for value in a.iter() {
417 if let Some(set_value) = set.get(value) {
418 let eq_result = value.reflect_partial_eq(set_value);
419 if let failed @ (Some(false) | None) = eq_result {
420 return failed;
421 }
422 } else {
423 return Some(false);
424 }
425 }
426
427 Some(true)
428}
429
430#[inline]
448pub fn set_debug(dyn_set: &dyn Set, f: &mut Formatter<'_>) -> core::fmt::Result {
449 let mut debug = f.debug_set();
450 for value in dyn_set.iter() {
451 debug.entry(&value as &dyn Debug);
452 }
453 debug.finish()
454}
455
456#[inline]
464pub fn set_apply<M: Set>(a: &mut M, b: &dyn PartialReflect) {
465 if let ReflectRef::Set(set_value) = b.reflect_ref() {
466 for b_value in set_value.iter() {
467 if a.get(b_value).is_none() {
468 a.insert_boxed(b_value.clone_value());
469 }
470 }
471 } else {
472 panic!("Attempted to apply a non-set type to a set type.");
473 }
474}
475
476#[inline]
486pub fn set_try_apply<S: Set>(a: &mut S, b: &dyn PartialReflect) -> Result<(), ApplyError> {
487 let set_value = b.reflect_ref().as_set()?;
488
489 for b_value in set_value.iter() {
490 if a.get(b_value).is_none() {
491 a.insert_boxed(b_value.clone_value());
492 }
493 }
494
495 Ok(())
496}
497
498#[cfg(test)]
499mod tests {
500 use super::DynamicSet;
501
502 #[test]
503 fn test_into_iter() {
504 let expected = ["foo", "bar", "baz"];
505
506 let mut set = DynamicSet::default();
507 set.insert(expected[0].to_string());
508 set.insert(expected[1].to_string());
509 set.insert(expected[2].to_string());
510
511 for item in set.into_iter() {
512 let value = item
513 .try_take::<String>()
514 .expect("couldn't downcast to String");
515 let index = expected
516 .iter()
517 .position(|i| *i == value.as_str())
518 .expect("Element found in expected array");
519 assert_eq!(expected[index], value);
520 }
521 }
522}