Repository: Ralith/hecs
Pull request #208 (2021-11-26 20:27:27)

Miscellaneous cleanup


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a3da19e..cb9c16c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,14 +4,18 @@
 - `Or` query combinator, allowing a single query to select entities that satisfy at least one of two
   sub-queries.
 - `EntityRef::has` to efficiently check for the presence of a component without borrowing it
-- `EntityBulider::new_cloneable` constructs an `EntityBuilder` that builds a `ReusableBuiltEntity`,
-  which can be spawned repeatedly by reference.
+- `EntityBuliderClone` helper for working with dynamic collections of
+  components that may be used repeatedly
 - `Satisfies` query combinator, which yields a `bool` without borrowing any components
+- `World::column` and `column_mut` for efficient random access within
+  a single component type
+- `CommandBuffer` helper for recording operations on a world in advance
 
 ### Changed
 - Added a niche to `Entity`, making `Option<Entity>` the same size as a bare `Entity`. As a
   consequence, `Entity::from_bits` is now fallible, and deserialization of `Entity` values from
   older versions may fail.
+- `ColumnRef` renamed to `ArchetypeColumn`
 
 # 0.6.5
 
diff --git a/benches/bench.rs b/benches/bench.rs
index aac9c70..997f402 100644
--- a/benches/bench.rs
+++ b/benches/bench.rs
@@ -199,7 +199,7 @@ fn build(b: &mut Bencher) {
 
 fn build_cloneable(b: &mut Bencher) {
     let mut world = World::new();
-    let mut builder = EntityBuilder::new_cloneable();
+    let mut builder = EntityBuilderClone::new();
     builder.add(Position(0.0)).add(Velocity(0.0));
     let bundle = builder.build();
     b.iter(|| {
@@ -223,7 +223,7 @@ fn spawn_buffered(b: &mut Bencher) {
     let mut buffer = CommandBuffer::new();
     let ent = world.reserve_entity();
     b.iter(|| {
-        buffer.spawn_at(ent, (Position(0.0), Velocity(0.0)));
+        buffer.insert(ent, (Position(0.0), Velocity(0.0)));
         buffer.run_on(&mut world);
     });
 }
diff --git a/src/archetype.rs b/src/archetype.rs
index 656259c..6e5c39b 100644
--- a/src/archetype.rs
+++ b/src/archetype.rs
@@ -115,12 +115,12 @@ impl Archetype {
     /// Get the `T` components of these entities, if present
     ///
     /// Useful for efficient serialization.
-    pub fn get<T: Component>(&self) -> Option<ColumnRef<'_, T>> {
+    pub fn get<T: Component>(&self) -> Option<ArchetypeColumn<'_, T>> {
         let state = self.get_state::<T>()?;
         let ptr = self.get_base::<T>(state);
         let column = unsafe { slice::from_raw_parts_mut(ptr.as_ptr(), self.len as usize) };
         self.borrow::<T>(state);
-        Some(ColumnRef {
+        Some(ArchetypeColumn {
             archetype: self,
             column,
         })
@@ -591,26 +591,26 @@ impl PartialEq for TypeInfo {
 impl Eq for TypeInfo {}
 
 /// Shared reference to a single column of component data in an [`Archetype`]
-pub struct ColumnRef<'a, T: Component> {
+pub struct ArchetypeColumn<'a, T: Component> {
     archetype: &'a Archetype,
     column: &'a [T],
 }
 
-impl<T: Component> Deref for ColumnRef<'_, T> {
+impl<T: Component> Deref for ArchetypeColumn<'_, T> {
     type Target = [T];
     fn deref(&self) -> &[T] {
         self.column
     }
 }
 
-impl<T: Component> Drop for ColumnRef<'_, T> {
+impl<T: Component> Drop for ArchetypeColumn<'_, T> {
     fn drop(&mut self) {
         let state = self.archetype.get_state::<T>().unwrap();
         self.archetype.release::<T>(state);
     }
 }
 
-impl<T: Component> Clone for ColumnRef<'_, T> {
+impl<T: Component> Clone for ArchetypeColumn<'_, T> {
     fn clone(&self) -> Self {
         let state = self.archetype.get_state::<T>().unwrap();
         self.archetype.borrow::<T>(state);
@@ -621,7 +621,7 @@ impl<T: Component> Clone for ColumnRef<'_, T> {
     }
 }
 
-impl<T: Component + fmt::Debug> fmt::Debug for ColumnRef<'_, T> {
+impl<T: Component + fmt::Debug> fmt::Debug for ArchetypeColumn<'_, T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.column.fmt(f)
     }
diff --git a/src/column.rs b/src/column.rs
index a68e4cf..9b8b130 100644
--- a/src/column.rs
+++ b/src/column.rs
@@ -5,11 +5,11 @@ use alloc::vec::Vec;
 use crate::entities::{EntityMeta, NoSuchEntity};
 use crate::{Archetype, Component, ComponentError, Entity, MissingComponent};
 
-/// Column of a single component
+/// Borrows every `T` component in a world
 pub struct Column<'a, T: Component> {
     entities: &'a [EntityMeta],
     archetypes: &'a [Archetype],
-    archetype_column_indices: Vec<Option<usize>>,
+    archetype_state: Vec<Option<usize>>,
     _marker: PhantomData<T>,
 }
 
@@ -19,26 +19,24 @@ impl<'a, T: Component> Column<'a, T> {
         archetypes: &'a [Archetype],
         _marker: PhantomData<T>,
     ) -> Self {
-        let mut archetype_column_indices: Vec<Option<usize>> = Vec::new();
-        for i in archetypes.iter() {
-            archetype_column_indices.push(i.get_state::<T>());
-        }
-        for val in archetypes.iter() {
-            if val.has::<T>() {
-                let state = val.get_state::<T>().unwrap();
-                val.borrow::<T>(state);
+        let mut archetype_state = Vec::with_capacity(archetypes.len());
+        for archetype in archetypes.iter() {
+            let state = archetype.get_state::<T>();
+            archetype_state.push(state);
+            if let Some(state) = state {
+                archetype.borrow::<T>(state);
             }
         }
 
         Self {
             entities,
             archetypes,
-            archetype_column_indices,
+            archetype_state,
             _marker,
         }
     }
 
-    /// Get this column's component from entity if it exist
+    /// Access the `T` component of `entity`
     pub fn get(&self, entity: Entity) -> Result<&T, ComponentError> {
         let meta = self
             .entities
@@ -49,7 +47,7 @@ impl<'a, T: Component> Column<'a, T> {
             .archetypes
             .get(meta.location.archetype as usize)
             .unwrap();
-        let state = self.archetype_column_indices[meta.location.archetype as usize]
+        let state = self.archetype_state[meta.location.archetype as usize]
             .ok_or_else(MissingComponent::new::<T>)?;
         unsafe {
             let target = archetype
@@ -67,21 +65,19 @@ unsafe impl<'a, T: Component> Sync for Column<'a, T> {}
 
 impl<'a, T: Component> Drop for Column<'a, T> {
     fn drop(&mut self) {
-        self.archetype_column_indices.clear();
-        for val in self.archetypes.iter() {
-            if val.has::<T>() {
-                let state = val.get_state::<T>().unwrap();
-                val.release::<T>(state);
+        for (archetype, &state) in self.archetypes.iter().zip(&self.archetype_state) {
+            if let Some(state) = state {
+                archetype.release::<T>(state);
             }
         }
     }
 }
 
-/// Mutable column of a single component
+/// Uniquely borrows every `T` component in a world
 pub struct ColumnMut<'a, T: Component> {
     entities: &'a [EntityMeta],
     archetypes: &'a [Archetype],
-    archetype_column_indices: Vec<Option<usize>>,
+    archetype_state: Vec<Option<usize>>,
     _marker: PhantomData<T>,
 }
 
@@ -91,26 +87,24 @@ impl<'a, T: Component> ColumnMut<'a, T> {
         archetypes: &'a [Archetype],
         _marker: PhantomData<T>,
     ) -> Self {
-        let mut archetype_column_indices: Vec<Option<usize>> = Vec::new();
-        for i in archetypes.iter() {
-            archetype_column_indices.push(i.get_state::<T>());
-        }
-        for val in archetypes.iter() {
-            if val.has::<T>() {
-                let state = val.get_state::<T>().unwrap();
-                val.borrow_mut::<T>(state);
+        let mut archetype_state = Vec::with_capacity(archetypes.len());
+        for archetype in archetypes.iter() {
+            let state = archetype.get_state::<T>();
+            archetype_state.push(state);
+            if let Some(state) = state {
+                archetype.borrow_mut::<T>(state);
             }
         }
         Self {
             entities,
             archetypes,
-            archetype_column_indices,
+            archetype_state,
             _marker,
         }
     }
 
-    /// Mutably get this column's component from entity if it exist
-    pub fn get(&self, entity: Entity) -> Result<&mut T, ComponentError> {
+    /// Access the `T` component of `entity`
+    pub fn get(&mut self, entity: Entity) -> Result<&mut T, ComponentError> {
         let meta = self
             .entities
             .get(entity.id as usize)
@@ -120,7 +114,7 @@ impl<'a, T: Component> ColumnMut<'a, T> {
             .archetypes
             .get(meta.location.archetype as usize)
             .unwrap();
-        let state = self.archetype_column_indices[meta.location.archetype as usize]
+        let state = self.archetype_state[meta.location.archetype as usize]
             .ok_or_else(MissingComponent::new::<T>)?;
         unsafe {
             let target = archetype
@@ -137,12 +131,44 @@ unsafe impl<'a, T: Component> Sync for ColumnMut<'a, T> {}
 
 impl<'a, T: Component> Drop for ColumnMut<'a, T> {
     fn drop(&mut self) {
-        self.archetype_column_indices.clear();
-        for val in self.archetypes.iter() {
-            if val.has::<T>() {
-                let state = val.get_state::<T>().unwrap();
-                val.release_mut::<T>(state);
+        for (archetype, &state) in self.archetypes.iter().zip(&self.archetype_state) {
+            if let Some(state) = state {
+                archetype.release_mut::<T>(state);
             }
         }
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use crate::World;
+
+    #[test]
+    fn borrow_twice() {
+        let mut world = World::new();
+        world.spawn((true, "abc"));
+        let c = world.column_mut::<bool>();
+        drop(c);
+        world.column::<bool>();
+    }
+
+    #[test]
+    #[should_panic(expected = "bool already borrowed uniquely")]
+    fn mut_shared_overlap() {
+        let mut world = World::new();
+        world.spawn((true, "abc"));
+        let c = world.column_mut::<bool>();
+        world.column::<bool>();
+        drop(c);
+    }
+
+    #[test]
+    #[should_panic(expected = "bool already borrowed")]
+    fn shared_mut_overlap() {
+        let mut world = World::new();
+        world.spawn((true, "abc"));
+        let c = world.column::<bool>();
+        world.column_mut::<bool>();
+        drop(c);
+    }
+}
diff --git a/src/command_buffer.rs b/src/command_buffer.rs
index 6aa2188..fa1813c 100644
--- a/src/command_buffer.rs
+++ b/src/command_buffer.rs
@@ -15,28 +15,30 @@ use crate::Entity;
 use crate::World;
 use crate::{align, DynamicBundle};
 
-/// Allows spawn operations to be buffered for future application to a ['World']
+/// Records operations for future application to a ['World']
+///
+/// Useful when operations cannot be applied directly due to ordering concerns or borrow checking.
 ///
 /// ```
 /// # use hecs::*;
 /// let mut world = World::new();
-/// let reserved_ent = world.reserve_entity();
-/// let mut entity_buffer = CommandBuffer::new();
-/// entity_buffer.spawn_at(reserved_ent,(true,0.10));
-/// entity_buffer.run_on(&mut world); // buffer can now be reused
-/// assert!(world.contains(reserved_ent));
+/// let entity = world.reserve_entity();
+/// let mut cmd = CommandBuffer::new();
+/// cmd.insert(entity, (true, 42));
+/// cmd.run_on(&mut world); // cmd can now be reused
+/// assert_eq!(*world.get::<i32>(entity).unwrap(), 42);
 /// ```
 pub struct CommandBuffer {
     entities: Vec<EntityIndex>,
     storage: NonNull<u8>,
     layout: Layout,
     cursor: usize,
-    info: Vec<ComponentInfo>,
+    components: Vec<ComponentInfo>,
     ids: Vec<TypeId>,
 }
 
 impl CommandBuffer {
-    /// Create an empty buffer
+    /// Create an empty command buffer
     pub fn new() -> Self {
         Self::default()
     }
@@ -69,79 +71,81 @@ impl CommandBuffer {
 
         let addr = self.storage.as_ptr().add(offset);
         ptr::copy_nonoverlapping(ptr, addr, ty.layout().size());
-        self.info.push(ComponentInfo {
-            ty_info: ty,
-            offset,
-        });
+        self.components.push(ComponentInfo { ty, offset });
         self.cursor = end;
     }
 
-    /// Record an entity spawn operation
-    pub fn spawn_at(&mut self, ent: Entity, bundle: impl DynamicBundle) {
-        let len = bundle.type_info().len();
+    /// Add components from `bundle` to `entity`, if it exists
+    ///
+    /// Pairs well with [`World::reserve_entity`] to spawn entities with a known handle.
+    pub fn insert(&mut self, entity: Entity, components: impl DynamicBundle) {
+        let first_component = self.components.len();
         unsafe {
-            bundle.put(|ptr, ty| self.add_inner(ptr, ty));
+            components.put(|ptr, ty| self.add_inner(ptr, ty));
         }
-        let begin = self.entities.last().map_or(0, |x| x.end);
-        let end = begin + len;
         self.entities.push(EntityIndex {
-            entity: ent,
-            begin,
-            end,
+            entity: Some(entity),
+            first_component,
         });
     }
 
-    /// Spawn every entity recorded with their components
+    /// Spawn a new entity with `components`
     ///
-    /// # Example
-    /// ```
-    /// # use hecs::*;
-    /// let mut world = World::new();
-    /// let a = world.reserve_entity();
-    /// let mut recorder = CommandBuffer::new();
-    /// recorder.spawn_at(a, (false,0.0));
-    /// recorder.run_on(&mut world);
-    /// assert!(world.contains(a));
-    /// ```
-    pub fn run_on(&mut self, world: &mut World) {
-        let mut mark = self.entities.len() - 1;
+    /// If the [`Entity`] is needed immediately, consider combining [`World::reserve_entity`] with
+    /// [`insert`](CommandBuffer::insert) instead.
+    pub fn spawn(&mut self, components: impl DynamicBundle) {
+        let first_component = self.components.len();
+        unsafe {
+            components.put(|ptr, ty| self.add_inner(ptr, ty));
+        }
+        self.entities.push(EntityIndex {
+            entity: None,
+            first_component,
+        });
+    }
 
-        for index in self.entities.iter() {
-            self.info[index.begin..index.end].sort_unstable_by_key(|z| z.ty_info);
+    /// Run recorded commands on `world`, clearing the command buffer
+    pub fn run_on(&mut self, world: &mut World) {
+        let mut end = self.components.len();
+        for entity in self.entities.iter().rev() {
+            self.components[entity.first_component..end].sort_unstable_by_key(|z| z.ty);
+            end = entity.first_component;
         }
 
-        for _ in 0..self.entities.len() {
-            let (ent, comps) = self.build(mark);
-            world.spawn_at(ent, comps);
-            if mark != 0 {
-                mark -= 1;
+        for index in (0..self.entities.len()).rev() {
+            let (entity, components) = self.build(index);
+            match entity {
+                Some(entity) => {
+                    // If `entity` no longer exists, quietly drop the components.
+                    let _ = world.insert(entity, components);
+                }
+                None => {
+                    world.spawn(components);
+                }
             }
         }
         self.clear();
     }
 
-    fn build(&mut self, mark: usize) -> (Entity, ReadyBuffer<'_>) {
+    fn build(&mut self, index: usize) -> (Option<Entity>, RecordedEntity<'_>) {
         self.ids.clear();
         self.ids.extend(
-            self.info[self.entities[mark].begin..self.entities[mark].end]
+            self.components[self.entities[index].first_component..]
                 .iter()
-                .map(|x| x.ty_info.id()),
+                .map(|x| x.ty.id()),
         );
-        let entity = self.entities[mark].entity;
-        (entity, ReadyBuffer { buffer: self, mark })
+        let entity = self.entities[index].entity;
+        (entity, RecordedEntity { cmd: self, index })
     }
 
-    /// Drop previously `recorded` entities and their components
-    ///
-    /// Recorder is cleared implicitly when entities are spawned, so usually this doesn't need to
-    /// be called
+    /// Drop all recorded commands
     pub fn clear(&mut self) {
         self.ids.clear();
         self.entities.clear();
         self.cursor = 0;
         unsafe {
-            for info in self.info.drain(..) {
-                info.ty_info.drop(self.storage.as_ptr().add(info.offset));
+            for info in self.components.drain(..) {
+                info.ty.drop(self.storage.as_ptr().add(info.offset));
             }
         }
     }
@@ -169,7 +173,7 @@ impl Default for CommandBuffer {
             storage: NonNull::dangling(),
             layout: Layout::from_size_align(0, 8).unwrap(),
             cursor: 0,
-            info: Vec::new(),
+            components: Vec::new(),
             ids: Vec::new(),
         }
     }
@@ -177,47 +181,47 @@ impl Default for CommandBuffer {
 
 /// The output of an '[CommandBuffer]` suitable for passing to
 /// [`World::spawn_into`](crate::World::spawn_into)
-struct ReadyBuffer<'a> {
-    buffer: &'a mut CommandBuffer,
-    mark: usize,
+struct RecordedEntity<'a> {
+    cmd: &'a mut CommandBuffer,
+    index: usize,
 }
-unsafe impl DynamicBundle for ReadyBuffer<'_> {
+
+unsafe impl DynamicBundle for RecordedEntity<'_> {
     fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T {
-        f(&self.buffer.ids)
+        f(&self.cmd.ids)
     }
 
     fn type_info(&self) -> Vec<TypeInfo> {
-        self.buffer.info[self.buffer.entities[self.mark].begin..self.buffer.entities[self.mark].end]
+        self.cmd.components[self.cmd.entities[self.index].first_component..]
             .iter()
-            .map(|x| x.ty_info)
+            .map(|x| x.ty)
             .collect()
     }
 
     unsafe fn put(self, mut f: impl FnMut(*mut u8, TypeInfo)) {
         for info in self
-            .buffer
-            .info
-            .drain(self.buffer.entities[self.mark].begin..self.buffer.entities[self.mark].end)
+            .cmd
+            .components
+            .drain(self.cmd.entities[self.index].first_component..)
         {
-            let ptr = self.buffer.storage.as_ptr().add(info.offset);
-            f(ptr, info.ty_info);
+            let ptr = self.cmd.storage.as_ptr().add(info.offset);
+            f(ptr, info.ty);
         }
     }
 }
 
 /// Data required to store components and their offset  
 struct ComponentInfo {
-    ty_info: TypeInfo,
+    ty: TypeInfo,
     // Position in 'storage'
     offset: usize,
 }
 
 /// Data of buffered 'entity' and its relative position in component data
 struct EntityIndex {
-    entity: Entity,
-    // Range of associated indices in `CommandBuffer`'s `info` member
-    begin: usize,
-    end: usize,
+    entity: Option<Entity>,
+    // Position of this entity's first component in `CommandBuffer::info`
+    first_component: usize,
 }
 
 #[cfg(test)]
@@ -232,10 +236,10 @@ mod tests {
         let enta = world.reserve_entity();
         let entb = world.reserve_entity();
         let entc = world.reserve_entity();
-        buffer.spawn_at(ent, (true, "a"));
-        buffer.spawn_at(entc, (true, "a"));
-        buffer.spawn_at(enta, (1, 1.0));
-        buffer.spawn_at(entb, (1.0, "a"));
+        buffer.insert(ent, (true, "a"));
+        buffer.insert(entc, (true, "a"));
+        buffer.insert(enta, (1, 1.0));
+        buffer.insert(entb, (1.0, "a"));
         buffer.run_on(&mut world);
         assert_eq!(world.archetypes().len(), 4);
     }
diff --git a/src/entity_builder.rs b/src/entity_builder.rs
index ee39986..190590f 100644
--- a/src/entity_builder.rs
+++ b/src/entity_builder.rs
@@ -28,25 +28,226 @@ use crate::{align, Component, DynamicBundle};
 /// assert_eq!(*world.get::<i32>(e).unwrap(), 123);
 /// assert_eq!(*world.get::<&str>(e).unwrap(), "abc");
 /// ```
-///
-/// `EntityBuilder<()>`s make no assumptions about components types. `EntityBuilder<Cloneable>` can
-/// be used instead to manage groups of components that all implement [`Clone`], allowing the built
-/// entity to be spawned repeatedly by reference.
+#[derive(Default)]
+pub struct EntityBuilder {
+    inner: Common<()>,
+}
+
+impl EntityBuilder {
+    /// Create a builder representing an entity with no components
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    /// Add `component` to the entity.
+    ///
+    /// If the bundle already contains a component of type `T`, it will
+    /// be dropped and replaced with the most recently added one.
+    pub fn add<T: Component>(&mut self, component: T) -> &mut Self {
+        self.add_bundle((component,))
+    }
+
+    /// Add all components in `bundle` to the entity.
+    ///
+    /// If the bundle contains any component which matches the type of a component
+    /// already in the `EntityBuilder`, the newly added component from the bundle
+    /// will replace the old component and the old component will be dropped.
+    pub fn add_bundle(&mut self, bundle: impl DynamicBundle) -> &mut Self {
+        unsafe {
+            bundle.put(|ptr, ty| self.inner.add(ptr, ty, ()));
+        }
+        self
+    }
+
+    /// Construct a `Bundle` suitable for spawning
+    pub fn build(&mut self) -> BuiltEntity<'_> {
+        self.inner.info.sort_unstable_by_key(|x| x.0);
+        self.inner
+            .ids
+            .extend(self.inner.info.iter().map(|x| x.0.id()));
+        BuiltEntity {
+            builder: &mut self.inner,
+        }
+    }
+
+    /// Checks to see if the component of type `T` exists
+    pub fn has<T: Component>(&self) -> bool {
+        self.inner.has::<T>()
+    }
+
+    /// Borrow the component of type `T`, if it exists
+    pub fn get<T: Component>(&self) -> Option<&T> {
+        self.inner.get::<T>()
+    }
+
+    /// Uniquely borrow the component of type `T`, if it exists
+    pub fn get_mut<T: Component>(&mut self) -> Option<&mut T> {
+        self.inner.get_mut::<T>()
+    }
+
+    /// Enumerate the types of the entity builder's components
+    pub fn component_types(&self) -> impl Iterator<Item = TypeId> + '_ {
+        self.inner.component_types()
+    }
+
+    /// Drop previously `add`ed components
+    ///
+    /// The builder is cleared implicitly when an entity is built, so this doesn't usually need to
+    /// be called.
+    pub fn clear(&mut self) {
+        self.inner.clear()
+    }
+}
+
+/// The output of an [`EntityBuilder`], suitable for passing to
+/// [`World::spawn`](crate::World::spawn) or [`World::insert`](crate::World::insert)
+pub struct BuiltEntity<'a> {
+    builder: &'a mut Common<()>,
+}
+
+unsafe impl DynamicBundle for BuiltEntity<'_> {
+    fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T {
+        f(&self.builder.ids)
+    }
+
+    #[doc(hidden)]
+    fn type_info(&self) -> Vec<TypeInfo> {
+        self.builder.info.iter().map(|x| x.0).collect()
+    }
+
+    unsafe fn put(self, mut f: impl FnMut(*mut u8, TypeInfo)) {
+        for (ty, offset, ()) in self.builder.info.drain(..) {
+            let ptr = self.builder.storage.as_ptr().add(offset);
+            f(ptr, ty);
+        }
+    }
+}
+
+impl Drop for BuiltEntity<'_> {
+    fn drop(&mut self) {
+        // Ensures components aren't leaked if `store` was never called, and prepares the builder
+        // for reuse.
+        self.builder.clear();
+    }
+}
+
+/// Variant of [`EntityBuilder`] that clones components on use
 ///
 /// ```
 /// # use hecs::*;
 /// let mut world = World::new();
-/// let mut builder = EntityBuilder::new_cloneable();
+/// let mut builder = EntityBuilderClone::new();
 /// builder.add(123).add("abc");
 /// let bundle = builder.build();
 /// let e = world.spawn(&bundle);
-/// let f = world.spawn(&bundle);
+/// let f = world.spawn(&bundle); // `&bundle` can be used many times
 /// assert_eq!(*world.get::<i32>(e).unwrap(), 123);
 /// assert_eq!(*world.get::<&str>(e).unwrap(), "abc");
 /// assert_eq!(*world.get::<i32>(f).unwrap(), 123);
 /// assert_eq!(*world.get::<&str>(f).unwrap(), "abc");
 /// ```
-pub struct EntityBuilder<M = ()> {
+#[derive(Clone, Default)]
+pub struct EntityBuilderClone {
+    inner: Common<Cloneable>,
+}
+
+impl EntityBuilderClone {
+    /// Create a builder representing an entity with no components
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    /// Add `component` to the entity.
+    ///
+    /// If the bundle already contains a component of type `T`, it will be dropped and replaced with
+    /// the most recently added one.
+    pub fn add<T: Component + Clone>(&mut self, mut component: T) -> &mut Self {
+        unsafe {
+            self.inner.add(
+                (&mut component as *mut T).cast(),
+                TypeInfo::of::<T>(),
+                Cloneable::new::<T>(),
+            );
+            core::mem::forget(component);
+        }
+        self
+    }
+
+    /// Convert into a value whose shared references are [`DynamicBundle`]s suitable for repeated
+    /// spawning
+    pub fn build(self) -> BuiltEntityClone {
+        self.into()
+    }
+
+    /// Checks to see if the component of type `T` exists
+    pub fn has<T: Component>(&self) -> bool {
+        self.inner.has::<T>()
+    }
+
+    /// Borrow the component of type `T`, if it exists
+    pub fn get<T: Component>(&self) -> Option<&T> {
+        self.inner.get::<T>()
+    }
+
+    /// Uniquely borrow the component of type `T`, if it exists
+    pub fn get_mut<T: Component>(&mut self) -> Option<&mut T> {
+        self.inner.get_mut::<T>()
+    }
+
+    /// Enumerate the types of the entity builder's components
+    pub fn component_types(&self) -> impl Iterator<Item = TypeId> + '_ {
+        self.inner.component_types()
+    }
+
+    /// Drop previously `add`ed components
+    ///
+    /// The builder is cleared implicitly when an entity is built, so this doesn't usually need to
+    /// be called.
+    pub fn clear(&mut self) {
+        self.inner.clear()
+    }
+}
+
+/// A collection of components that implement [`Clone`]
+///
+/// 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>);
+
+unsafe impl DynamicBundle for &'_ BuiltEntityClone {
+    fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T {
+        f(&self.0.ids)
+    }
+
+    fn type_info(&self) -> Vec<TypeInfo> {
+        self.0.info.iter().map(|x| x.0).collect()
+    }
+
+    unsafe fn put(self, mut f: impl FnMut(*mut u8, TypeInfo)) {
+        for &(_, offset, ref clone) in &self.0.info {
+            let ptr = self.0.storage.as_ptr().add(offset);
+            (clone.0)(ptr, &mut f);
+        }
+    }
+}
+
+impl From<EntityBuilderClone> for BuiltEntityClone {
+    fn from(mut x: EntityBuilderClone) -> Self {
+        x.inner.info.sort_unstable_by_key(|y| y.0);
+        x.inner.ids.extend(x.inner.info.iter().map(|y| y.0.id()));
+        Self(x.inner)
+    }
+}
+
+impl From<BuiltEntityClone> for EntityBuilderClone {
+    fn from(mut x: BuiltEntityClone) -> Self {
+        x.0.ids.clear();
+        EntityBuilderClone { inner: x.0 }
+    }
+}
+
+struct Common<M> {
     storage: NonNull<u8>,
     layout: Layout,
     cursor: usize,
@@ -55,14 +256,12 @@ pub struct EntityBuilder<M = ()> {
     indices: TypeIdMap<usize>,
 }
 
-impl<M> EntityBuilder<M> {
-    /// Checks to see if the component of type `T` exists
-    pub fn has<T: Component>(&self) -> bool {
+impl<M> Common<M> {
+    fn has<T: Component>(&self) -> bool {
         self.indices.contains_key(&TypeId::of::<T>())
     }
 
-    /// Borrow the component of type `T`, if it exists
-    pub fn get<T: Component>(&self) -> Option<&T> {
+    fn get<T: Component>(&self) -> Option<&T> {
         let index = self.indices.get(&TypeId::of::<T>())?;
         let (_, offset, _) = self.info[*index];
         unsafe {
@@ -71,8 +270,7 @@ impl<M> EntityBuilder<M> {
         }
     }
 
-    /// Uniquely borrow the component of type `T`, if it exists
-    pub fn get_mut<T: Component>(&mut self) -> Option<&mut T> {
+    fn get_mut<T: Component>(&mut self) -> Option<&mut T> {
         let index = self.indices.get(&TypeId::of::<T>())?;
         let (_, offset, _) = self.info[*index];
         unsafe {
@@ -81,8 +279,7 @@ impl<M> EntityBuilder<M> {
         }
     }
 
-    /// Enumerate the types of the entity builder's components
-    pub fn component_types(&self) -> impl Iterator<Item = TypeId> + '_ {
+    fn component_types(&self) -> impl Iterator<Item = TypeId> + '_ {
         self.info.iter().map(|(info, _, _)| info.id())
     }
 
@@ -98,11 +295,7 @@ impl<M> EntityBuilder<M> {
         (new_storage, layout)
     }
 
-    /// Drop previously `add`ed components
-    ///
-    /// The builder is cleared implicitly when an entity is built, so this doesn't usually need to
-    /// be called.
-    pub fn clear(&mut self) {
+    fn clear(&mut self) {
         self.ids.clear();
         self.indices.clear();
         self.cursor = 0;
@@ -113,7 +306,7 @@ impl<M> EntityBuilder<M> {
         }
     }
 
-    unsafe fn add_inner(&mut self, ptr: *mut u8, ty: TypeInfo, meta: M) {
+    unsafe fn add(&mut self, ptr: *mut u8, ty: TypeInfo, meta: M) {
         match self.indices.entry(ty.id()) {
             Entry::Occupied(occupied) => {
                 let index = *occupied.get();
@@ -151,99 +344,10 @@ impl<M> EntityBuilder<M> {
     }
 }
 
-impl EntityBuilder<()> {
-    /// Create a builder representing an entity with no components
-    pub fn new() -> Self {
-        Self::default()
-    }
-
-    /// Add `component` to the entity.
-    ///
-    /// If the bundle already contains a component of type `T`, it will
-    /// be dropped and replaced with the most recently added one.
-    pub fn add<T: Component>(&mut self, component: T) -> &mut Self {
-        self.add_bundle((component,))
-    }
-
-    /// Add all components in `bundle` to the entity.
-    ///
-    /// If the bundle contains any component which matches the type of a component
-    /// already in the `EntityBuilder`, the newly added component from the bundle
-    /// will replace the old component and the old component will be dropped.
-    pub fn add_bundle(&mut self, bundle: impl DynamicBundle) -> &mut Self {
-        unsafe {
-            bundle.put(|ptr, ty| self.add_inner(ptr, ty, ()));
-        }
-        self
-    }
-
-    /// Construct a `Bundle` suitable for spawning
-    pub fn build(&mut self) -> BuiltEntity<'_> {
-        self.info.sort_unstable_by_key(|x| x.0);
-        self.ids.extend(self.info.iter().map(|x| x.0.id()));
-        BuiltEntity { builder: self }
-    }
-}
-
-impl EntityBuilder<Cloneable> {
-    /// Create a builder representing an entity with no components, and which can only accept
-    /// components that implement `Clone`
-    pub fn new_cloneable() -> Self {
-        Self::default()
-    }
+unsafe impl<M> Send for Common<M> {}
+unsafe impl<M> Sync for Common<M> {}
 
-    /// Add `component` to the entity.
-    ///
-    /// If the bundle already contains a component of type `T`, it will be dropped and replaced with
-    /// the most recently added one.
-    pub fn add<T: Component + Clone>(&mut self, mut component: T) -> &mut Self {
-        unsafe {
-            self.add_inner(
-                (&mut component as *mut T).cast(),
-                TypeInfo::of::<T>(),
-                Cloneable::new::<T>(),
-            );
-            core::mem::forget(component);
-        }
-        self
-    }
-
-    /// Convert into a value whose shared references are [`DynamicBundle`]s suitable for repeated
-    /// spawning
-    pub fn build(self) -> ReusableBuiltEntity {
-        self.into()
-    }
-}
-
-impl Clone for EntityBuilder<Cloneable> {
-    fn clone(&self) -> Self {
-        unsafe {
-            let result = Self {
-                storage: NonNull::new_unchecked(alloc(self.layout)),
-                layout: self.layout,
-                cursor: self.cursor,
-                info: self.info.clone(),
-                ids: Vec::new(),
-                indices: self.indices.clone(),
-            };
-            for &(_, offset, ref clone) in &self.info {
-                (clone.0)(self.storage.as_ptr().add(offset), &mut |src, ty| {
-                    result
-                        .storage
-                        .as_ptr()
-                        .add(offset)
-                        .copy_from_nonoverlapping(src, ty.layout().size())
-                });
-            }
-            result
-        }
-    }
-}
-
-unsafe impl<M> Send for EntityBuilder<M> {}
-unsafe impl<M> Sync for EntityBuilder<M> {}
-
-impl<M> Drop for EntityBuilder<M> {
+impl<M> Drop for Common<M> {
     fn drop(&mut self) {
         // Ensure buffered components aren't leaked
         self.clear();
@@ -255,7 +359,7 @@ impl<M> Drop for EntityBuilder<M> {
     }
 }
 
-impl<M> Default for EntityBuilder<M> {
+impl<M> Default for Common<M> {
     /// Create a builder representing an entity with no components
     fn default() -> Self {
         Self {
@@ -283,72 +387,27 @@ impl Cloneable {
     }
 }
 
-/// The output of an [`EntityBuilder`], suitable for passing to
-/// [`World::spawn`](crate::World::spawn) or [`World::insert`](crate::World::insert)
-pub struct BuiltEntity<'a> {
-    builder: &'a mut EntityBuilder<()>,
-}
-
-unsafe impl DynamicBundle for BuiltEntity<'_> {
-    fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T {
-        f(&self.builder.ids)
-    }
-
-    #[doc(hidden)]
-    fn type_info(&self) -> Vec<TypeInfo> {
-        self.builder.info.iter().map(|x| x.0).collect()
-    }
-
-    unsafe fn put(self, mut f: impl FnMut(*mut u8, TypeInfo)) {
-        for (ty, offset, ()) in self.builder.info.drain(..) {
-            let ptr = self.builder.storage.as_ptr().add(offset);
-            f(ptr, ty);
-        }
-    }
-}
-
-impl Drop for BuiltEntity<'_> {
-    fn drop(&mut self) {
-        // Ensures components aren't leaked if `store` was never called, and prepares the builder
-        // for reuse.
-        self.builder.clear();
-    }
-}
-
-/// A collection of components that implement [`Clone`]
-///
-/// Built from, and convertible back into, [`EntityBuilder<Cloneable>`]
-#[derive(Clone)]
-pub struct ReusableBuiltEntity(EntityBuilder<Cloneable>);
-
-unsafe impl DynamicBundle for &'_ ReusableBuiltEntity {
-    fn with_ids<T>(&self, f: impl FnOnce(&[TypeId]) -> T) -> T {
-        f(&self.0.ids)
-    }
-
-    fn type_info(&self) -> Vec<TypeInfo> {
-        self.0.info.iter().map(|x| x.0).collect()
-    }
-
-    unsafe fn put(self, mut f: impl FnMut(*mut u8, TypeInfo)) {
-        for &(_, offset, ref clone) in &self.0.info {
-            let ptr = self.0.storage.as_ptr().add(offset);
-            (clone.0)(ptr, &mut f);
+impl Clone for Common<Cloneable> {
+    fn clone(&self) -> Self {
+        unsafe {
+            let result = Common {
+                storage: NonNull::new_unchecked(alloc(self.layout)),
+                layout: self.layout,
+                cursor: self.cursor,
+                info: self.info.clone(),
+                ids: Vec::new(),
+                indices: self.indices.clone(),
+            };
+            for &(_, offset, ref clone) in &self.info {
+                (clone.0)(self.storage.as_ptr().add(offset), &mut |src, ty| {
+                    result
+                        .storage
+                        .as_ptr()
+                        .add(offset)
+                        .copy_from_nonoverlapping(src, ty.layout().size())
+                });
+            }
+            result
         }
     }
 }
-
-impl From<EntityBuilder<Cloneable>> for ReusableBuiltEntity {
-    fn from(mut x: EntityBuilder<Cloneable>) -> Self {
-        x.info.sort_unstable_by_key(|y| y.0);
-        x.ids.extend(x.info.iter().map(|y| y.0.id()));
-        Self(x)
-    }
-}
-
-impl From<ReusableBuiltEntity> for EntityBuilder<Cloneable> {
-    fn from(mut x: ReusableBuiltEntity) -> Self {
-        x.0.ids.clear();
-        x.0
-    }
-}
diff --git a/src/lib.rs b/src/lib.rs
index 38e9579..ba014ad 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -71,13 +71,13 @@ mod query_one;
 pub mod serialize;
 mod world;
 
-pub use archetype::{Archetype, ColumnRef};
+pub use archetype::{Archetype, ArchetypeColumn};
 pub use batch::{BatchIncomplete, BatchWriter, ColumnBatch, ColumnBatchBuilder, ColumnBatchType};
 pub use bundle::{Bundle, DynamicBundle, MissingComponent};
 pub use column::{Column, ColumnMut};
 pub use command_buffer::CommandBuffer;
 pub use entities::{Entity, NoSuchEntity};
-pub use entity_builder::{BuiltEntity, Cloneable, EntityBuilder, ReusableBuiltEntity};
+pub use entity_builder::{BuiltEntity, BuiltEntityClone, EntityBuilder, EntityBuilderClone};
 pub use entity_ref::{EntityRef, Ref, RefMut};
 pub use query::{
     Access, Batch, BatchedIter, Or, PreparedQuery, PreparedQueryBorrow, PreparedQueryIter, Query,
diff --git a/src/world.rs b/src/world.rs
index b74c641..71e8ee4 100644
--- a/src/world.rs
+++ b/src/world.rs
@@ -775,29 +775,31 @@ impl World {
         self.archetypes_inner().iter()
     }
 
-    /// Efficient random access within a single component type
-    pub fn column<T: Component>(&self) -> Column<'_, T> {
-        let archetypes = self.archetypes.archetypes.as_slice();
-        let entities = self.entities.meta.as_slice();
-        Column::new(entities, archetypes, PhantomData)
-    }
-
-    /// Efficient random access within a single component type
+    /// Borrow every `T` component for efficient random access
     ///
-    /// It's useful for applications that do large amount of random
-    /// access to same Component type
+    /// [`Column::get`] is semantically equivalent to [`World::get`], except that every `T`
+    /// component is borrowed in advance, and repeated calls are much cheaper, at the cost of
+    /// additional work when the [`Column`] is fetched.
     ///
-    /// Since Column borrows every component T in all archetypes
-    /// borrow checker will panic if you try to borrow T before column goes out of scope
+    /// Panics if a unique borrow is outstanding for any `T` component.
     ///
     /// # Example
     /// ```
     /// use::hecs::*;
     /// let mut world = World::new();
     /// let ent = world.spawn((123, "abc"));
-    /// let column_mut = world.column_mut::<i32>();
-    /// assert_eq!(*column_mut.get(ent).unwrap(), 123);
+    /// let column = world.column::<i32>();
+    /// assert_eq!(*column.get(ent).unwrap(), 123);
     /// ```
+    pub fn column<T: Component>(&self) -> Column<'_, T> {
+        let archetypes = self.archetypes.archetypes.as_slice();
+        let entities = self.entities.meta.as_slice();
+        Column::new(entities, archetypes, PhantomData)
+    }
+
+    /// Uniquely borrows every `T` component for efficient random access
+    ///
+    /// See [`World::column`].
     pub fn column_mut<T: Component>(&self) -> ColumnMut<'_, T> {
         let archetypes = self.archetypes.archetypes.as_slice();
         let entities = self.entities.meta.as_slice();


Test patch:
diff --git a/tests/tests.rs b/tests/tests.rs
index e09c7f3..b533b06 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -281,10 +281,10 @@ fn spawn_buffered_entity() {
     let ent2 = world.reserve_entity();
     let ent3 = world.reserve_entity();
 
-    buffer.spawn_at(ent, (1, true));
-    buffer.spawn_at(ent1, (13, 7.11, "hecs"));
-    buffer.spawn_at(ent2, (17 as i8, false, 'o'));
-    buffer.spawn_at(ent3, (2 as u8, "qwe", 101.103, false));
+    buffer.insert(ent, (1, true));
+    buffer.insert(ent1, (13, 7.11, "hecs"));
+    buffer.insert(ent2, (17 as i8, false, 'o'));
+    buffer.insert(ent3, (2 as u8, "qwe", 101.103, false));
 
     buffer.run_on(&mut world);
 
@@ -623,7 +623,7 @@ fn column_get_mut() {
     let mut world = World::new();
     let ent = world.spawn((0, true));
     {
-        let column = world.column_mut::<i32>();
+        let mut column = world.column_mut::<i32>();
         *column.get(ent).unwrap() = 99;
         assert_eq!(*column.get(ent).unwrap(), 99);
     }