Chapter 08

World の API - 1

toyboot 4e
toyboot 4e
2022.02.18に更新

外部クレートから見た 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]

toecstests/ 以下に 1 つしかファイルを持ちませんが、良い習慣として tests/it/main.rs にしました。

内部可変性を使ったアクセサを公開

  • &World から内部データが取れます。
    AtomicRefCell の中に入っているので可変参照も取れます。

  • ただしデータの追加・削除には必ず &mut World が必要であるとしました。

ComponentPool::insert などはユーザから隠しています。

prelude モジュールも追加しました。

リファレンス実装: 0651328

World::despawn(Entity)

Entity を削除するときはその component も削除します:

lib.rs(疑似コード)
component_pools_mut()
    .for_each(|component_pool: &mut Box<dyn Any>| {
        /** 削除する処理 **/
    });

この component_pool には 2 つの機能が必要です:

. dyn Any のようにアップキャストする機能
. Component を削除する機能

downcast_rs を使って上 2 つを満たす型 (dyn ErasedComponentPool) を作りました:

comp.rs
use downcast_rs::Downcast;

pub(crate) trait ErasedComponentPool: Downcast {
    fn erased_remove(&mut self, entity: Entity);
}

リファレンス実装: 65ce774

ComponentPooldyn ErasedComponentPool として持つことで、 component を一括削除ができるようにできます:

lib.rs(疑似コード)
component_pools_mut()
    .for_each(|component_pool: &mut dyn ErasedComponentPool| {
        component_pool.erased_remove(entity);
    });

リファレンス実装: bc3af90

脚注
  1. Delete Cargo Integration Tests ↩︎