Repository: Ralith/hecs
Pull request #213 (2021-11-29 00:37:22)

Miscellaneous cleanup


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 67aae24..f49018f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+# Unreleased
+
+### Added
+- `EntityBuilderClone::add_bundle` accepting bundles of `Clone` components
+
 # 0.7.0
 
 ### Added
diff --git a/src/bundle.rs b/src/bundle.rs
index 7f8bc61..9eb5158 100644
--- a/src/bundle.rs
+++ b/src/bundle.rs
@@ -6,7 +6,6 @@
 // copied, modified, or distributed except according to those terms.
 
 use crate::alloc::{vec, vec::Vec};
-use crate::entity_builder::Cloneable;
 use core::any::{type_name, TypeId};
 use core::ptr::NonNull;
 use core::{fmt, mem};
@@ -31,8 +30,7 @@ pub unsafe trait DynamicBundle {
     fn type_info(&self) -> Vec<TypeInfo>;
     /// Allow a callback to move all components out of the bundle
     ///
-    /// Must invoke `f` only with a valid pointer and the pointee's type and size. `put` may only be
-    /// called at most once on any given value.
+    /// Must invoke `f` only with a valid pointer and the pointee's type and size.
     #[doc(hidden)]
     unsafe fn put(self, f: impl FnMut(*mut u8, TypeInfo));
 }
@@ -62,11 +60,28 @@ pub unsafe trait Bundle: DynamicBundle {
 pub unsafe trait DynamicBundleClone: DynamicBundle {
     /// Allow a callback to move all components out of the bundle
     ///
-    /// Must invoke `f` only with a valid pointer and the pointee's type and size. `put` may only be
-    /// called at most once on any given value. Provides helper type for cloning
-    /// each type.
+    /// Must invoke `f` only with a valid pointer, the pointee's type and size, and a `DynamicClone`
+    /// constructed for the pointee's type.
     #[doc(hidden)]
-    unsafe fn put_with_clone(self, f: impl FnMut(*mut u8, TypeInfo, Cloneable));
+    unsafe fn put_with_clone(self, f: impl FnMut(*mut u8, TypeInfo, DynamicClone));
+}
+
+#[derive(Copy, Clone)]
+/// Type-erased [`Clone`] implementation
+pub struct DynamicClone {
+    pub(crate) func: unsafe fn(*const u8, &mut dyn FnMut(*mut u8, TypeInfo)),
+}
+
+impl DynamicClone {
+    pub(crate) fn new<T: Component + Clone>() -> Self {
+        Self {
+            func: |src, f| unsafe {
+                let mut tmp = (*src.cast::<T>()).clone();
+                f((&mut tmp as *mut T).cast(), TypeInfo::of::<T>());
+                core::mem::forget(tmp);
+            },
+        }
+    }
 }
 
 /// Error indicating that an entity did not have a required component
@@ -121,14 +136,14 @@ macro_rules! tuple_impl {
         unsafe impl<$($name: Component + Clone),*> DynamicBundleClone for ($($name,)*) {
             // Compiler false positive warnings
             #[allow(unused_variables, unused_mut)]
-            unsafe fn put_with_clone(self, mut f: impl FnMut(*mut u8, TypeInfo, Cloneable)) {
+            unsafe fn put_with_clone(self, mut f: impl FnMut(*mut u8, TypeInfo, DynamicClone)) {
                 #[allow(non_snake_case)]
                 let ($(mut $name,)*) = self;
                 $(
                     f(
                         (&mut $name as *mut $name).cast::<u8>(),
                         TypeInfo::of::<$name>(),
-                        Cloneable::new::<$name>()
+                        DynamicClone::new::<$name>()
                     );
                     mem::forget($name);
                 )*
diff --git a/src/entity_builder.rs b/src/entity_builder.rs
index 7e1822a..70e835f 100644
--- a/src/entity_builder.rs
+++ b/src/entity_builder.rs
@@ -7,7 +7,7 @@
 
 use crate::alloc::alloc::{alloc, dealloc, Layout};
 use crate::alloc::vec::Vec;
-use crate::bundle::DynamicBundleClone;
+use crate::bundle::{DynamicBundleClone, DynamicClone};
 use core::any::TypeId;
 use core::ptr::{self, NonNull};
 
@@ -149,7 +149,7 @@ impl Drop for BuiltEntity<'_> {
 /// ```
 #[derive(Clone, Default)]
 pub struct EntityBuilderClone {
-    inner: Common<Cloneable>,
+    inner: Common<DynamicClone>,
 }
 
 impl EntityBuilderClone {
@@ -167,7 +167,7 @@ impl EntityBuilderClone {
             self.inner.add(
                 (&mut component as *mut T).cast(),
                 TypeInfo::of::<T>(),
-                Cloneable::new::<T>(),
+                DynamicClone::new::<T>(),
             );
             core::mem::forget(component);
         }
@@ -226,7 +226,7 @@ impl EntityBuilderClone {
 /// Built from, and convertible back into, [`EntityBuilderClone`]. `DynamicBundle` is implemented
 /// for *references to* this type, allowing it to be e.g. spawned repeatedly.
 #[derive(Clone)]
-pub struct BuiltEntityClone(Common<Cloneable>);
+pub struct BuiltEntityClone(Common<DynamicClone>);
 
 unsafe impl DynamicBundle for &'_ BuiltEntityClone {
     fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T {
@@ -238,13 +238,22 @@ unsafe impl DynamicBundle for &'_ BuiltEntityClone {
     }
 
     unsafe fn put(self, mut f: impl FnMut(*mut u8, TypeInfo)) {
-        for &(_, offset, ref clone) in &self.0.info {
+        for &(_, offset, clone) in &self.0.info {
             let ptr = self.0.storage.as_ptr().add(offset);
             (clone.func)(ptr, &mut f);
         }
     }
 }
 
+unsafe impl DynamicBundleClone for &'_ BuiltEntityClone {
+    unsafe fn put_with_clone(self, mut f: impl FnMut(*mut u8, TypeInfo, DynamicClone)) {
+        for &(_, offset, clone) in &self.0.info {
+            let ptr = self.0.storage.as_ptr().add(offset);
+            (clone.func)(ptr, &mut |src, ty| f(src, ty, clone));
+        }
+    }
+}
+
 impl From<EntityBuilderClone> for BuiltEntityClone {
     fn from(mut x: EntityBuilderClone) -> Self {
         x.inner.info.sort_unstable_by_key(|y| y.0);
@@ -386,25 +395,7 @@ impl<M> Default for Common<M> {
     }
 }
 
-#[derive(Clone)]
-/// Struct providing dynamic clone via callback
-pub struct Cloneable {
-    func: unsafe fn(*const u8, &mut dyn FnMut(*mut u8, TypeInfo)),
-}
-
-impl Cloneable {
-    pub(crate) fn new<T: Component + Clone>() -> Self {
-        Self {
-            func: |src, f| unsafe {
-                let mut tmp = (*src.cast::<T>()).clone();
-                f((&mut tmp as *mut T).cast(), TypeInfo::of::<T>());
-                core::mem::forget(tmp);
-            },
-        }
-    }
-}
-
-impl Clone for Common<Cloneable> {
+impl Clone for Common<DynamicClone> {
     fn clone(&self) -> Self {
         unsafe {
             let result = Common {


Test patch:
diff --git a/tests/tests.rs b/tests/tests.rs
index 9dc7048..f0e1877 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -232,6 +232,18 @@ fn build_entity_clone() {
     assert_eq!(*world.get::<Cow<'static, str>>(g).unwrap(), "after");
 }
 
+#[test]
+fn build_builder_clone() {
+    let mut a = EntityBuilderClone::new();
+    a.add(String::from("abc"));
+    a.add(123);
+    let mut b = EntityBuilderClone::new();
+    b.add(String::from("def"));
+    b.add_bundle(&a.build());
+    assert_eq!(b.get::<String>(), Some(&String::from("abc")));
+    assert_eq!(b.get::<i32>(), Some(&123));
+}
+
 #[test]
 fn access_builder_components() {
     let mut world = World::new();