1use crate::generics::impl_generic_info_methods;
5use crate::{
6 attributes::{impl_custom_attribute_methods, CustomAttributes},
7 type_info::impl_type_methods,
8 ApplyError, Generics, NamedField, PartialReflect, Reflect, ReflectKind, ReflectMut,
9 ReflectOwned, ReflectRef, Type, TypeInfo, TypePath,
10};
11use alloc::{borrow::Cow, boxed::Box, vec::Vec};
12use bevy_platform::collections::HashMap;
13use bevy_platform::sync::Arc;
14use bevy_reflect_derive::impl_type_path;
15use core::{
16 fmt::{Debug, Formatter},
17 slice::Iter,
18};
19
20pub trait Struct: PartialReflect {
52 fn field(&self, name: &str) -> Option<&dyn PartialReflect>;
55
56 fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect>;
59
60 fn field_at(&self, index: usize) -> Option<&dyn PartialReflect>;
63
64 fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect>;
67
68 fn name_at(&self, index: usize) -> Option<&str>;
70
71 fn index_of_name(&self, name: &str) -> Option<usize>;
73
74 fn field_len(&self) -> usize;
76
77 fn iter_fields(&self) -> FieldIter<'_>;
79
80 fn to_dynamic_struct(&self) -> DynamicStruct {
82 let mut dynamic_struct = DynamicStruct::default();
83 dynamic_struct.set_represented_type(self.get_represented_type_info());
84 for (name, value) in self.iter_fields() {
85 dynamic_struct.insert_boxed(name, value.to_dynamic());
86 }
87 dynamic_struct
88 }
89
90 fn get_represented_struct_info(&self) -> Option<&'static StructInfo> {
92 self.get_represented_type_info()?.as_struct().ok()
93 }
94}
95
96impl<'a> IntoIterator for &'a dyn Struct {
97 type Item = (&'a str, &'a dyn PartialReflect);
98 type IntoIter = FieldIter<'a>;
99
100 fn into_iter(self) -> Self::IntoIter {
101 self.iter_fields()
102 }
103}
104
105#[derive(#[automatically_derived]
impl ::core::clone::Clone for StructInfo {
#[inline]
fn clone(&self) -> StructInfo {
StructInfo {
ty: ::core::clone::Clone::clone(&self.ty),
generics: ::core::clone::Clone::clone(&self.generics),
fields: ::core::clone::Clone::clone(&self.fields),
field_names: ::core::clone::Clone::clone(&self.field_names),
field_indices: ::core::clone::Clone::clone(&self.field_indices),
custom_attributes: ::core::clone::Clone::clone(&self.custom_attributes),
docs: ::core::clone::Clone::clone(&self.docs),
}
}
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for StructInfo {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
let names: &'static _ =
&["ty", "generics", "fields", "field_names", "field_indices",
"custom_attributes", "docs"];
let values: &[&dyn ::core::fmt::Debug] =
&[&self.ty, &self.generics, &self.fields, &self.field_names,
&self.field_indices, &self.custom_attributes, &&self.docs];
::core::fmt::Formatter::debug_struct_fields_finish(f, "StructInfo",
names, values)
}
}Debug)]
107pub struct StructInfo {
108 ty: Type,
109 generics: Generics,
110 fields: Box<[NamedField]>,
111 field_names: Box<[&'static str]>,
112 field_indices: HashMap<&'static str, usize>,
113 custom_attributes: Arc<CustomAttributes>,
114 #[cfg(feature = "reflect_documentation")]
115 docs: Option<&'static str>,
116}
117
118impl StructInfo {
119 pub fn new<T: Reflect + TypePath>(fields: &[NamedField]) -> Self {
125 let field_indices = fields
126 .iter()
127 .enumerate()
128 .map(|(index, field)| (field.name(), index))
129 .collect::<HashMap<_, _>>();
130
131 let field_names = fields.iter().map(NamedField::name).collect();
132
133 Self {
134 ty: Type::of::<T>(),
135 generics: Generics::new(),
136 fields: fields.to_vec().into_boxed_slice(),
137 field_names,
138 field_indices,
139 custom_attributes: Arc::new(CustomAttributes::default()),
140 #[cfg(feature = "reflect_documentation")]
141 docs: None,
142 }
143 }
144
145 #[cfg(feature = "reflect_documentation")]
147 pub fn with_docs(self, docs: Option<&'static str>) -> Self {
148 Self { docs, ..self }
149 }
150
151 pub fn with_custom_attributes(self, custom_attributes: CustomAttributes) -> Self {
153 Self {
154 custom_attributes: Arc::new(custom_attributes),
155 ..self
156 }
157 }
158
159 pub fn field_names(&self) -> &[&'static str] {
161 &self.field_names
162 }
163
164 pub fn field(&self, name: &str) -> Option<&NamedField> {
166 self.field_indices
167 .get(name)
168 .map(|index| &self.fields[*index])
169 }
170
171 pub fn field_at(&self, index: usize) -> Option<&NamedField> {
173 self.fields.get(index)
174 }
175
176 pub fn index_of(&self, name: &str) -> Option<usize> {
178 self.field_indices.get(name).copied()
179 }
180
181 pub fn iter(&self) -> Iter<'_, NamedField> {
183 self.fields.iter()
184 }
185
186 pub fn field_len(&self) -> usize {
188 self.fields.len()
189 }
190
191 pub fn ty(&self) -> &crate::type_info::Type { { &self.ty } }
pub fn type_id(&self) -> ::core::any::TypeId { self.ty().id() }
pub fn type_path(&self) -> &'static str { self.ty().path() }
pub fn type_path_table(&self) -> &crate::type_path::TypePathTable {
&self.ty().type_path_table()
}
pub fn is<T: ::core::any::Any>(&self) -> bool { self.ty().is::<T>() }impl_type_methods!(ty);
192
193 #[cfg(feature = "reflect_documentation")]
195 pub fn docs(&self) -> Option<&'static str> {
196 self.docs
197 }
198
199 #[doc = "Returns the custom attributes for this item."]
pub fn custom_attributes(&self) -> &crate::attributes::CustomAttributes {
&self.custom_attributes
}
pub fn get_attribute<T: crate::Reflect>(&self) -> Option<&T> {
self.custom_attributes().get::<T>()
}
pub fn get_attribute_by_id(&self, id: ::core::any::TypeId)
-> Option<&dyn crate::Reflect> {
self.custom_attributes().get_by_id(id)
}
#[doc =
"Returns `true` if this item has a custom attribute of the specified type."]
#[doc =
"\n\nFor dynamically checking if an attribute exists, see [`has_attribute_by_id`](Self::has_attribute_by_id)."]
pub fn has_attribute<T: crate::Reflect>(&self) -> bool {
self.custom_attributes().contains::<T>()
}
#[doc =
"Returns `true` if this item has a custom attribute with the specified [`TypeId`](::core::any::TypeId)."]
#[doc =
"\n\nThis is the dynamic equivalent of [`has_attribute`](Self::has_attribute)"]
pub fn has_attribute_by_id(&self, id: ::core::any::TypeId) -> bool {
self.custom_attributes().contains_by_id(id)
}impl_custom_attribute_methods!(self.custom_attributes, "struct");
200
201 pub fn generics(&self) -> &crate::generics::Generics { &self.generics }
pub fn with_generics(mut self, generics: crate::generics::Generics) -> Self {
self.generics = generics;
self
}impl_generic_info_methods!(generics);
202}
203
204pub struct FieldIter<'a> {
206 pub(crate) struct_val: &'a dyn Struct,
207 pub(crate) index: usize,
208}
209
210impl<'a> FieldIter<'a> {
211 pub fn new(value: &'a dyn Struct) -> Self {
213 FieldIter {
214 struct_val: value,
215 index: 0,
216 }
217 }
218}
219
220impl<'a> Iterator for FieldIter<'a> {
221 type Item = (&'a str, &'a dyn PartialReflect);
222
223 fn next(&mut self) -> Option<Self::Item> {
224 if let Some(name) = self.struct_val.name_at(self.index)
225 && let Some(field) = self.struct_val.field_at(self.index)
226 {
227 self.index += 1;
228 Some((name, field))
229 } else {
230 None
231 }
232 }
233
234 fn size_hint(&self) -> (usize, Option<usize>) {
235 let size = self.struct_val.field_len();
236 (size, Some(size))
237 }
238}
239
240impl<'a> ExactSizeIterator for FieldIter<'a> {}
241
242pub trait GetField {
263 fn get_field<T: Reflect>(&self, name: &str) -> Option<&T>;
266
267 fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T>;
270}
271
272impl<S: Struct> GetField for S {
273 fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
274 self.field(name)
275 .and_then(|value| value.try_downcast_ref::<T>())
276 }
277
278 fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
279 self.field_mut(name)
280 .and_then(|value| value.try_downcast_mut::<T>())
281 }
282}
283
284impl GetField for dyn Struct {
285 fn get_field<T: Reflect>(&self, name: &str) -> Option<&T> {
286 self.field(name)
287 .and_then(|value| value.try_downcast_ref::<T>())
288 }
289
290 fn get_field_mut<T: Reflect>(&mut self, name: &str) -> Option<&mut T> {
291 self.field_mut(name)
292 .and_then(|value| value.try_downcast_mut::<T>())
293 }
294}
295
296#[derive(#[automatically_derived]
impl ::core::default::Default for DynamicStruct {
#[inline]
fn default() -> DynamicStruct {
DynamicStruct {
represented_type: ::core::default::Default::default(),
fields: ::core::default::Default::default(),
field_names: ::core::default::Default::default(),
field_indices: ::core::default::Default::default(),
}
}
}Default)]
298pub struct DynamicStruct {
299 represented_type: Option<&'static TypeInfo>,
300 fields: Vec<Box<dyn PartialReflect>>,
301 field_names: Vec<Cow<'static, str>>,
302 field_indices: HashMap<Cow<'static, str>, usize>,
303}
304
305impl DynamicStruct {
306 pub fn set_represented_type(&mut self, represented_type: Option<&'static TypeInfo>) {
314 if let Some(represented_type) = represented_type {
315 if !#[allow(non_exhaustive_omitted_patterns)] match represented_type {
TypeInfo::Struct(_) => true,
_ => false,
} {
{
::core::panicking::panic_fmt(format_args!("expected TypeInfo::Struct but received: {0:?}",
represented_type));
}
};assert!(
316 matches!(represented_type, TypeInfo::Struct(_)),
317 "expected TypeInfo::Struct but received: {represented_type:?}"
318 );
319 }
320
321 self.represented_type = represented_type;
322 }
323
324 pub fn insert_boxed<'a>(
328 &mut self,
329 name: impl Into<Cow<'a, str>>,
330 field: Box<dyn PartialReflect>,
331 ) {
332 let name: Cow<str> = name.into();
333 if let Some(index) = self.field_indices.get(&name) {
334 self.fields[*index] = field;
335 } else {
336 self.fields.push(field);
337 self.field_indices
338 .insert(Cow::Owned(name.clone().into_owned()), self.fields.len() - 1);
339 self.field_names.push(Cow::Owned(name.into_owned()));
340 }
341 }
342
343 pub fn insert<'a, T: PartialReflect>(&mut self, name: impl Into<Cow<'a, str>>, field: T) {
347 self.insert_boxed(name, Box::new(field));
348 }
349
350 pub fn remove_at(
352 &mut self,
353 index: usize,
354 ) -> Option<(Cow<'static, str>, Box<dyn PartialReflect>)> {
355 let mut i: usize = 0;
356 let mut extract = self.field_names.extract_if(0..self.field_names.len(), |n| {
357 let mut result = false;
358 if i == index {
359 self.field_indices
360 .remove(n)
361 .expect("Invalid name for `field_indices.remove(name)`");
362 result = true;
363 } else if i > index {
364 *self
365 .field_indices
366 .get_mut(n)
367 .expect("Invalid name for `field_indices.get_mut(name)`") -= 1;
368 }
369 i += 1;
370 result
371 });
372
373 let name = extract
374 .nth(0)
375 .expect("Invalid index for `extract.nth(index)`");
376 extract.for_each(drop); Some((name, self.fields.remove(index)))
379 }
380
381 pub fn remove_if<F>(&mut self, mut f: F) -> Option<(Cow<'static, str>, Box<dyn PartialReflect>)>
383 where
384 F: FnMut((&str, &dyn PartialReflect)) -> bool,
385 {
386 if let Some(index) = self
387 .field_names
388 .iter()
389 .zip(self.fields.iter())
390 .position(|(name, field)| f((name.as_ref(), field.as_ref())))
391 {
392 self.remove_at(index)
393 } else {
394 None
395 }
396 }
397
398 pub fn remove_by_name(
400 &mut self,
401 name: &str,
402 ) -> Option<(Cow<'static, str>, Box<dyn PartialReflect>)> {
403 if let Some(index) = self.index_of_name(name) {
404 self.remove_at(index)
405 } else {
406 None
407 }
408 }
409}
410
411impl Struct for DynamicStruct {
412 #[inline]
413 fn field(&self, name: &str) -> Option<&dyn PartialReflect> {
414 self.field_indices
415 .get(name)
416 .map(|index| &*self.fields[*index])
417 }
418
419 #[inline]
420 fn field_mut(&mut self, name: &str) -> Option<&mut dyn PartialReflect> {
421 if let Some(index) = self.index_of_name(name) {
422 Some(self.fields[index].as_mut())
423 } else {
424 None
425 }
426 }
427
428 #[inline]
429 fn field_at(&self, index: usize) -> Option<&dyn PartialReflect> {
430 self.fields.get(index).map(AsRef::as_ref)
431 }
432
433 #[inline]
434 fn field_at_mut(&mut self, index: usize) -> Option<&mut dyn PartialReflect> {
435 self.fields.get_mut(index).map(AsMut::as_mut)
436 }
437
438 #[inline]
439 fn name_at(&self, index: usize) -> Option<&str> {
440 self.field_names.get(index).map(AsRef::as_ref)
441 }
442
443 #[inline]
445 fn index_of_name(&self, name: &str) -> Option<usize> {
446 self.field_indices.get(name).copied()
447 }
448
449 #[inline]
450 fn field_len(&self) -> usize {
451 self.fields.len()
452 }
453
454 #[inline]
455 fn iter_fields(&self) -> FieldIter<'_> {
456 FieldIter::new(self)
457 }
458}
459
460impl PartialReflect for DynamicStruct {
461 #[inline]
462 fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
463 self.represented_type
464 }
465
466 #[inline]
467 fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
468 self
469 }
470
471 #[inline]
472 fn as_partial_reflect(&self) -> &dyn PartialReflect {
473 self
474 }
475
476 #[inline]
477 fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
478 self
479 }
480
481 fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
482 Err(self)
483 }
484 fn try_as_reflect(&self) -> Option<&dyn Reflect> {
485 None
486 }
487 fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
488 None
489 }
490
491 fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
492 let struct_value = value.reflect_ref().as_struct()?;
493
494 for (name, value) in struct_value {
495 if let Some(v) = self.field_mut(name) {
496 v.try_apply(value)?;
497 }
498 }
499
500 Ok(())
501 }
502
503 #[inline]
504 fn reflect_kind(&self) -> ReflectKind {
505 ReflectKind::Struct
506 }
507
508 #[inline]
509 fn reflect_ref(&self) -> ReflectRef<'_> {
510 ReflectRef::Struct(self)
511 }
512
513 #[inline]
514 fn reflect_mut(&mut self) -> ReflectMut<'_> {
515 ReflectMut::Struct(self)
516 }
517
518 #[inline]
519 fn reflect_owned(self: Box<Self>) -> ReflectOwned {
520 ReflectOwned::Struct(self)
521 }
522
523 fn reflect_partial_eq(&self, value: &dyn PartialReflect) -> Option<bool> {
524 struct_partial_eq(self, value)
525 }
526
527 fn reflect_partial_cmp(&self, value: &dyn PartialReflect) -> Option<::core::cmp::Ordering> {
528 struct_partial_cmp(self, value)
529 }
530
531 fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
532 f.write_fmt(format_args!("DynamicStruct("))write!(f, "DynamicStruct(")?;
533 struct_debug(self, f)?;
534 f.write_fmt(format_args!(")"))write!(f, ")")
535 }
536
537 #[inline]
538 fn is_dynamic(&self) -> bool {
539 true
540 }
541}
542
543const _: () =
{
#[allow(deprecated, reason =
"derives on a deprecated type shouldn't be considered a usage")]
impl bevy_reflect::TypePath for DynamicStruct where {
fn type_path() -> &'static str { "bevy_reflect::DynamicStruct" }
fn short_type_path() -> &'static str { "DynamicStruct" }
fn type_ident() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("DynamicStruct")
}
fn crate_name() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_reflect")
}
fn module_path() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_reflect")
}
}
};impl_type_path!((in bevy_reflect) DynamicStruct);
544
545impl Debug for DynamicStruct {
546 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
547 self.debug(f)
548 }
549}
550
551impl<'a, N> FromIterator<(N, Box<dyn PartialReflect>)> for DynamicStruct
552where
553 N: Into<Cow<'a, str>>,
554{
555 fn from_iter<I: IntoIterator<Item = (N, Box<dyn PartialReflect>)>>(fields: I) -> Self {
558 let mut dynamic_struct = Self::default();
559 for (name, value) in fields.into_iter() {
560 dynamic_struct.insert_boxed(name, value);
561 }
562 dynamic_struct
563 }
564}
565
566impl IntoIterator for DynamicStruct {
567 type Item = (Cow<'static, str>, Box<dyn PartialReflect>);
568 type IntoIter = core::iter::Zip<
569 alloc::vec::IntoIter<Cow<'static, str>>,
570 alloc::vec::IntoIter<Box<dyn PartialReflect>>,
571 >;
572
573 fn into_iter(self) -> Self::IntoIter {
574 self.field_names.into_iter().zip(self.fields)
575 }
576}
577
578impl<'a> IntoIterator for &'a DynamicStruct {
579 type Item = (&'a str, &'a dyn PartialReflect);
580 type IntoIter = FieldIter<'a>;
581
582 fn into_iter(self) -> Self::IntoIter {
583 self.iter_fields()
584 }
585}
586
587#[inline(never)]
597pub fn struct_partial_eq(a: &dyn Struct, b: &dyn PartialReflect) -> Option<bool> {
598 let ReflectRef::Struct(struct_value) = b.reflect_ref() else {
599 return Some(false);
600 };
601
602 if a.field_len() != struct_value.field_len() {
603 return Some(false);
604 }
605
606 for (name, value) in struct_value {
607 if let Some(field_value) = a.field(name) {
608 let eq_result = field_value.reflect_partial_eq(value);
609 if let failed @ (Some(false) | None) = eq_result {
610 return failed;
611 }
612 } else {
613 return Some(false);
614 }
615 }
616
617 Some(true)
618}
619
620#[inline(never)]
625pub fn struct_partial_cmp(a: &dyn Struct, b: &dyn PartialReflect) -> Option<::core::cmp::Ordering> {
626 let ReflectRef::Struct(struct_value) = b.reflect_ref() else {
627 return None;
628 };
629
630 if a.field_len() != struct_value.field_len() {
631 return None;
632 }
633
634 partial_cmp_by_field_names(
636 a.field_len(),
637 |i| a.name_at(i),
638 |i| a.field_at(i),
639 |i| struct_value.name_at(i),
640 |i| struct_value.field_at(i),
641 |name| struct_value.field(name),
642 )
643}
644
645pub(crate) fn partial_cmp_by_field_names<'a, NA, FA, NB, FB, FBY>(
655 field_len: usize,
656 name_at_a: NA,
657 field_at_a: FA,
658 name_at_b: NB,
659 field_at_b_index: FB,
660 field_b_by_name: FBY,
661) -> Option<::core::cmp::Ordering>
662where
663 NA: Fn(usize) -> Option<&'a str>,
664 FA: Fn(usize) -> Option<&'a dyn PartialReflect>,
665 NB: Fn(usize) -> Option<&'a str>,
666 FB: Fn(usize) -> Option<&'a dyn PartialReflect>,
667 FBY: Fn(&str) -> Option<&'a dyn PartialReflect>,
668{
669 use ::core::cmp::Ordering;
670
671 let mut same_field_order = true;
672 for i in 0..field_len {
673 if name_at_a(i) != name_at_b(i) {
674 same_field_order = false;
675 break;
676 }
677 }
678
679 if same_field_order {
680 for i in 0..field_len {
681 let a_val = field_at_a(i).unwrap();
682 let b_val = field_at_b_index(i).unwrap();
683 match a_val.reflect_partial_cmp(b_val) {
684 None => return None,
685 Some(Ordering::Equal) => continue,
686 Some(ord) => return Some(ord),
687 }
688 }
689 return Some(Ordering::Equal);
690 }
691
692 let mut all_less_equal = true;
693 let mut all_greater_equal = true;
694 let mut all_equal = true;
695
696 for i in 0..field_len {
697 let field_name = name_at_a(i).unwrap();
698 let a_val = field_at_a(i).unwrap();
699 let b_val = field_b_by_name(field_name)?;
700 match a_val.reflect_partial_cmp(b_val) {
701 None => return None,
702 Some(::core::cmp::Ordering::Less) => {
703 all_greater_equal = false;
704 all_equal = false;
705 }
706 Some(::core::cmp::Ordering::Greater) => {
707 all_less_equal = false;
708 all_equal = false;
709 }
710 Some(::core::cmp::Ordering::Equal) => {}
711 }
712 }
713
714 if all_equal {
715 Some(::core::cmp::Ordering::Equal)
716 } else if all_less_equal {
717 Some(::core::cmp::Ordering::Less)
718 } else if all_greater_equal {
719 Some(::core::cmp::Ordering::Greater)
720 } else {
721 None
722 }
723}
724
725#[inline]
745pub fn struct_debug(dyn_struct: &dyn Struct, f: &mut Formatter<'_>) -> core::fmt::Result {
746 let mut debug = f.debug_struct(
747 dyn_struct
748 .get_represented_type_info()
749 .map(TypeInfo::type_path)
750 .unwrap_or("_"),
751 );
752 for field_index in 0..dyn_struct.field_len() {
753 let field = dyn_struct.field_at(field_index).unwrap();
754 debug.field(
755 dyn_struct.name_at(field_index).unwrap(),
756 &field as &dyn Debug,
757 );
758 }
759 debug.finish()
760}
761
762#[cfg(test)]
763mod tests {
764 use crate::{structs::*, *};
765 use alloc::borrow::ToOwned;
766
767 #[derive(Reflect, Default)]
768 struct MyStruct {
769 a: (),
770 b: (),
771 c: (),
772 }
773
774 #[derive(Reflect, Default)]
775 struct OtherStruct {
776 a: u32,
777 b: u64,
778 c: MyStruct,
779 }
780
781 #[test]
782 fn dynamic_struct_remove_at() {
783 let mut s = OtherStruct::default().to_dynamic_struct();
784
785 assert_eq!(s.field_len(), 3);
786
787 let field_2 = s
788 .remove_at(1)
789 .expect("Invalid index for `s.remove_at(index)`");
790
791 assert_eq!(s.field_len(), 2);
792 assert_eq!(field_2.0, "b");
793
794 let field_3 = s
795 .remove_at(0)
796 .expect("Invalid index for `s.remove_at(index)`");
797
798 assert_eq!(s.field_len(), 1);
799 assert_eq!(field_3.0, "a");
800
801 let field_1 = s
802 .remove_at(0)
803 .expect("Invalid index for `s.remove_at(index)`");
804
805 assert_eq!(s.field_len(), 0);
806 assert_eq!(field_1.0, "c");
807 }
808
809 #[test]
810 fn dynamic_struct_remove_by_name() {
811 let mut s = OtherStruct::default().to_dynamic_struct();
812
813 assert_eq!(s.field_len(), 3);
814
815 let field_3 = s
816 .remove_by_name("b")
817 .expect("Invalid name for `s.remove_by_name(name)`");
818
819 assert_eq!(s.field_len(), 2);
820 assert_eq!(field_3.0, "b");
821
822 let field_2 = s
823 .remove_by_name("c")
824 .expect("Invalid name for `s.remove_by_name(name)`");
825
826 assert_eq!(s.field_len(), 1);
827 assert_eq!(field_2.0, "c");
828
829 let field_1 = s
830 .remove_by_name("a")
831 .expect("Invalid name for `s.remove_by_name(name)`");
832
833 assert_eq!(s.field_len(), 0);
834 assert_eq!(field_1.0, "a");
835 }
836
837 #[test]
838 fn dynamic_struct_remove_if() {
839 let mut s = OtherStruct::default().to_dynamic_struct();
840
841 assert_eq!(s.field_len(), 3);
842
843 let field_3_name = s
844 .name_at(2)
845 .expect("Invalid index for `s.field_at(index)`")
846 .to_owned();
847 let field_3 = s
848 .remove_if(|(name, _field)| name == field_3_name)
849 .expect("No valid name/field found for `s.remove_with(|(name, field)|{})");
850
851 assert_eq!(s.field_len(), 2);
852 assert_eq!(field_3.0, "c");
853 }
854
855 #[test]
856 fn dynamic_struct_remove_combo() {
857 let mut s = OtherStruct::default().to_dynamic_struct();
858
859 assert_eq!(s.field_len(), 3);
860
861 let field_2 = s
862 .remove_at(
863 s.index_of_name("b")
864 .expect("Invalid name for `s.index_of_name(name)`"),
865 )
866 .expect("Invalid index for `s.remove_at(index)`");
867
868 assert_eq!(s.field_len(), 2);
869 assert_eq!(field_2.0, "b");
870
871 let field_3_name = s
872 .name_at(1)
873 .expect("Invalid name for s.name_at(index)")
874 .to_owned();
875
876 let field_3 = s
877 .remove_by_name(field_3_name.as_ref())
878 .expect("Invalid name for `s.remove_by_name(name)`");
879
880 assert_eq!(s.field_len(), 1);
881 assert_eq!(field_3.0, "c");
882
883 let field_1_name = s
884 .name_at(0)
885 .expect("Invalid name for `s.name_at(name)`")
886 .to_owned();
887 let field_1 = s
888 .remove_if(|(name, _field)| name == field_1_name)
889 .expect("No valid name/field found for `s.remove_with(|(name, field)|{})`");
890
891 assert_eq!(s.field_len(), 0);
892 assert_eq!(field_1.0, "a");
893 }
894
895 #[test]
896 fn next_index_increment() {
897 let my_struct = MyStruct::default();
898 let mut iter = my_struct.iter_fields();
899 iter.index = iter.len() - 1;
900 let prev_index = iter.index;
901 assert!(iter.next().is_some());
902 assert_eq!(prev_index, iter.index - 1);
903
904 let prev_index = iter.index;
906 assert!(iter.next().is_none());
907 assert_eq!(prev_index, iter.index);
908 assert!(iter.next().is_none());
909 assert_eq!(prev_index, iter.index);
910 }
911}