// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
/// Component storage wrapper around `SparseSet` that also tracks change ticks.
///|
pub struct ComponentStore[T] {
storage : SparseSet[T]
ticks : Array[ComponentTicks]
}
///|
pub fn[T] ComponentStore::new() -> ComponentStore[T] {
{ storage: SparseSet::new(), ticks: [] }
}
///|
pub fn[T] ComponentStore::len(self : ComponentStore[T]) -> Int {
self.storage.len()
}
///|
pub fn[T] ComponentStore::contains(
self : ComponentStore[T],
entity : Entity,
) -> Bool {
self.storage.contains(entity)
}
///|
pub fn[T] ComponentStore::get(self : ComponentStore[T], entity : Entity) -> T? {
self.storage.get(entity)
}
///|
pub fn[T] ComponentStore::get_ticks(
self : ComponentStore[T],
entity : Entity,
) -> ComponentTicks? {
match self.storage.index_of(entity) {
None => None
Some(i) => self.ticks.get(i)
}
}
///|
pub fn[T] ComponentStore::set(
self : ComponentStore[T],
entity : Entity,
value : T,
change_tick : Tick,
) -> Bool {
match self.storage.index_of(entity) {
None => false
Some(i) => {
self.storage.set(entity, value) |> ignore
self.ticks[i].set_changed(change_tick)
true
}
}
}
///|
pub fn[T] ComponentStore::insert(
self : ComponentStore[T],
entity : Entity,
value : T,
change_tick : Tick,
) -> Unit {
match self.storage.index_of(entity) {
Some(i) => {
self.storage.insert(entity, value)
self.ticks[i].set_changed(change_tick)
}
None => {
let before = self.storage.len()
self.storage.insert(entity, value)
// `SparseSet::insert` appends for new entities.
if self.storage.len() == before + 1 {
self.ticks.push(ComponentTicks::new(change_tick))
}
}
}
}
///|
pub fn[T] ComponentStore::remove(
self : ComponentStore[T],
entity : Entity,
) -> T? {
match self.storage.index_of(entity) {
None => None
Some(i) => {
let last = self.storage.len() - 1
if i != last {
self.ticks[i] = self.ticks[last]
}
self.ticks.pop() |> ignore
self.storage.remove(entity)
}
}
}
///|
pub fn[T] ComponentStore::for_each(
self : ComponentStore[T],
f : (Entity, T) -> Unit,
) -> Unit {
let len = self.storage.len()
for i in 0.. Unit,
) -> Unit {
let len = self.storage.len()
for i in 0.. Unit,
) -> Unit {
let len = self.storage.len()
for i in 0..