外部クレートから見た toecs
を考えて実装を進めます。
World
へのデータ挿入・削除には、 World
への排他的アクセスが必要だということにしました。
World
の API を作る
Integration test を追加する
-
src/tests.rs
からはlib.rs
の中身とpub(crate)
なアイテムが見えます。
内部実装のテストに適しています。 -
一方
tests/
以下のファイルは外部クレートとして扱われるため、 public なアイテムしか見えません。
API のテストに適しています。
.
├── src
└── tests/it
└── main.rs
Integration test は外部クレートとして扱われるので、コンパイル時間短縮のために it
1 つに集約します [1] 。
toecs
はtests/
以下に 1 つしかファイルを持ちませんが、良い習慣としてtests/it/main.rs
にしました。
内部可変性を使ったアクセサを公開
-
&World
から内部データが取れます。
AtomicRefCell
の中に入っているので可変参照も取れます。 -
ただしデータの追加・削除には必ず
&mut World
が必要であるとしました。
ComponentPool::insert
などはユーザから隠しています。
prelude
モジュールも追加しました。
リファレンス実装: 0651328
World::despawn(Entity)
Entity
を削除するときはその component も削除します:
component_pools_mut()
.for_each(|component_pool: &mut Box<dyn Any>| {
/** 削除する処理 **/
});
この component_pool
には 2 つの機能が必要です:
. dyn Any
のようにアップキャストする機能
. Component を削除する機能
downcast_rs を使って上 2 つを満たす型 (dyn ErasedComponentPool
) を作りました:
use downcast_rs::Downcast;
pub(crate) trait ErasedComponentPool: Downcast {
fn erased_remove(&mut self, entity: Entity);
}
リファレンス実装: 65ce774
ComponentPool
を dyn ErasedComponentPool
として持つことで、 component を一括削除ができるようにできます:
component_pools_mut()
.for_each(|component_pool: &mut dyn ErasedComponentPool| {
component_pool.erased_remove(entity);
});
リファレンス実装: bc3af90