From a18f62d109dcad26e940029f7743d80fca16dff5 Mon Sep 17 00:00:00 2001 From: torkleyy Date: Mon, 25 Dec 2017 10:57:01 +0100 Subject: [PATCH] Document aliasing rules for resources --- book/src/06_system_data.md | 24 ++++++++++++++++++++++++ src/storage/data.rs | 20 ++++++++++++++++++++ src/world/mod.rs | 4 ++-- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/book/src/06_system_data.md b/book/src/06_system_data.md index 2a5aaf38e..d390fa79f 100644 --- a/book/src/06_system_data.md +++ b/book/src/06_system_data.md @@ -1,5 +1,29 @@ # [DRAFT] System Data +Every system can request data which it needs to run. This data can be specified +using the `System::SystemData` type. Typical implementors of the `SystemData` trait +are `ReadStorage`, `WriteStorage`, `Fetch`, `FetchMut` and `Entities`. +A tuple of types implementing `SystemData` automatically also implements `SystemData`. +This means you can specify your `System::SystemData` as follows: + +```rust +struct Sys; + +impl<'a> System<'a> for Sys { + type SystemData = (WriteStorage<'a, Pos>, ReadStorage<'a, Vel>); + + fn run(&mut self, (pos, vel): Self::SystemData) { + /* ... */ + } +} +``` + +It is very important that you don't fetch both a `ReadStorage` and a `WriteStorage` +for the same component or a `Fetch` and a `FetchMut` for the same resource. +This is just like the borrowing rules of Rust, where you can't borrow something +mutably and immutably at the same time. In Specs, we have to check this at +runtime, thus you'll get a panic if you don't follow this rule. + ## Accessing Entities You want to create/delete entities from a system? There is diff --git a/src/storage/data.rs b/src/storage/data.rs index 394d4758f..b6c353f5d 100644 --- a/src/storage/data.rs +++ b/src/storage/data.rs @@ -11,6 +11,16 @@ use storage::MaskedStorage; /// however make sure to also check out the documentation for the /// respective methods on `Storage`. /// +/// ## Aliasing +/// +/// **It is strictly disallowed to fetch both a `ReadStorage` and a `WriteStorage` +/// of the same component.** +/// Because Specs uses interior mutability for its resources, we can't check +/// this at compile time. If you try to do this, you will get a panic. +/// +/// It is explicitly allowed to fetch multiple `ReadStorage`s for the same +/// component. +/// /// ## Joining storages /// /// `&ReadStorage` implements `Join`, which allows to do @@ -124,6 +134,16 @@ where /// /// Additionally to what `ReadStorage` can do a storage with mutable access allows: /// +/// ## Aliasing +/// +/// **It is strictly disallowed to fetch both a `ReadStorage` and a `WriteStorage` +/// of the same component.** +/// Because Specs uses interior mutability for its resources, we can't check +/// this at compile time. If you try to do this, you will get a panic. +/// +/// It is also disallowed to fetch multiple `WriteStorage`s for the same +/// component. +/// /// ## Retrieve components mutably /// /// This works just like `Storage::get`, but returns a mutable reference: diff --git a/src/world/mod.rs b/src/world/mod.rs index f3483bdcf..6a1cb0dea 100644 --- a/src/world/mod.rs +++ b/src/world/mod.rs @@ -399,7 +399,7 @@ impl World { /// /// ## Panics /// - /// Panics if it is already borrowed. + /// Panics if it is already borrowed (either immutably or mutably). /// Panics if the component has not been registered. pub fn write(&self) -> WriteStorage { self.write_with_id(0) @@ -426,7 +426,7 @@ impl World { /// /// # Panics /// - /// Panics if it is already borrowed. + /// Panics if it is already borrowed (either immutably or mutably). /// Also panics if the component is not registered with `World::register`. pub fn write_with_id(&self, id: usize) -> WriteStorage { let entities = self.entities();