Entity
経由のイテレータを作ります。
ポイントだけメモしたので、何を言っているのか伝わらないかもしれません。実装も酷いものですみません 🙇
例
Comp<T>
や CompMut<T>
の組からイテレータが作れるようになります:
fn add_system(mut us: CompMut<usize>, is: Comp<isize>, add: Res<usize>) {
for (u, i) in (&mut us, &is).iter() {
*u += (-*i) as usize + *add;
}
}
add_system.run(&world);
なお &CompMut<T>
は &Comp<T>
と同じ扱いとし、 &mut CompMut<T>
から区別します。
1 種類の component のイテレータ
こちらは [T]::iter
に準じる速いイテレータです。
Comp<T>
と CompMut<T>
を抽象する
trait View
を追加しました。 View
は SparseSet<T>
を 2 つに分解します:
/// `&Comp<T>` | `&CompMut<T>` | `&mut CompMut<T>`
pub unsafe trait View<'a> {
type Binding: AnyBinding;
fn into_parts(self) -> (&'a [Entity], Self::Binding);
}
/// Shorthand
type ViewItem<'a, V> = <<V as View<'a>>::Binding as AnyBinding>::Item;
/// `Binding<&[T]>` | `Binding<&mut [T]>`
///
/// `usize` か `Entity` で中のデータにアクセスできる
pub trait AnyBinding {
type Item;
fn get(&mut self, ent: Entity) -> Option<Self::Item>;
unsafe fn get_by_slot_unchecked(&mut self, slot: usize) -> Self::Item;
}
#[derive(Clone)]
pub struct Binding<'a, Slice> {
to_dense: &'a [Option<DenseIndex>],
data: Slice,
}
sparsey
やshipyard
では、そもそもComp<T>
とCompMut<T>
を同じstruct ComponentView<T>
で表しています。
AnyBinding
を通じてイテレータを実装します。
Lifetime を誤魔化す
Mutable iterator の実装が難しく、ズルをしました 🙇
// `&'_ mut self` から `&'a mut T` を返すアクセサ
impl<'a, T> AnyBinding for Binding<'a, &'a mut [T]> {
type Item = &'a mut T;
// ポインタ経由のキャストで実装
fn get(&mut self, ent: Entity) -> Option<Self::Item> { /* ~~ * /}
unsafe fn get_by_slot_unchecked(&mut self, slot: usize) -> Self::Item { /* ~~ * /}
}
miri には怒られなかったので、極端に酷い間違いはしていない……と思いたいです……
(Entity, Item)
のイテレータも作れるようにする
sparsey
を真似て (&a, &b).iter().entities()
と書けるようにしました。
InteIterator
は実装できない?
Unconstrained lifetime と言われたのでライフタイム付きの IntoIterator
を作りました:
pub trait Iter<'a> {
type I;
fn iter(self) -> Self::I;
}
ユーザは必ず .iter()
を呼びます。
IntoIterator
を実装する良いトリックがあるかもしれませんが、 Bevy の API もこんな感じだったので無理かもしれません。
リファレンス実装: 6b94be6
複数種類の component のイテレータ
SparseIndex
経由のイテレータです。速度は残念ですが、イテレーションの API は完成します。
複数種類の component の高速なイテレーションは『グループ』の章で扱います。
関連型を使ってコンパイルが通らないときは generics を使う
もう Rust 分からないですね……
ゼロコスト具象
Const generics で脳筋しました。
リファレンス実装: fdd3534