Remove catchall lookup type on root Data

This commit is contained in:
Tangent Wantwight 2020-01-16 01:08:15 -05:00
parent a080dabc67
commit 8d83917286
1 changed files with 42 additions and 38 deletions

View File

@ -19,10 +19,22 @@ export type Store<T> = (T & HasGeneration)[];
export type SparseStore<T> = Record<number, T & HasGeneration>;
export class Data {
entity: Store<EntityState> = [];
[name: string]: Store<{}> | SparseStore<{}>;
}
// Ergonomic Lookup typings
type StoreKeysOf<DATA> = {
[K in keyof DATA]: DATA[K] extends Record<number, infer T & HasGeneration> ? K : never;
};
type StoreKeys<DATA extends Data> = StoreKeysOf<DATA>[keyof DATA];
type ItemType<S> = S extends Record<number, infer T & HasGeneration> ? T : never;
type StoreType<DATA extends Data, K> = K extends keyof DATA ? ItemType<DATA[K]> : never;
type StoreTypes<DATA extends Data, K> = {
[I in keyof K]: StoreType<DATA, K[I]>;
};
type MaybeStoreTypes<DATA extends Data, K> = {
[I in keyof K]: StoreType<DATA, K[I]> | null;
};
/**
* Create an entity in the store
* @param data store
@ -31,7 +43,7 @@ export class Data {
* @returns the new entity's ID and generation
*/
type Assigner<DATA extends Data> = {
[S in keyof DATA]?: Pick<DATA[S][number], Exclude<keyof DATA[S][number], "generation">>
[S in StoreKeys<DATA>]?: StoreType<DATA, S>
};
export function Create<DATA extends Data>(data: DATA, assign: Assigner<DATA>, state = Liveness.ALIVE): Id {
const entities = data.entity;
@ -57,7 +69,8 @@ export function Create<DATA extends Data>(data: DATA, assign: Assigner<DATA>, st
};
for(const key in assign) {
data[key][freeId] = {...(assign[key] as {}), generation};
const store = data[key as keyof Data] as Store<{}>|SparseStore<{}>;
store[freeId] = {...(assign as Record<string, HasGeneration>)[key] as {}, generation};
}
return [freeId, generation];
@ -76,16 +89,6 @@ export function Remove<DATA extends Data>(data: DATA, [id, generation]: Id, stat
}
}
// Ergonomic Lookup typings
type ItemType<S> = S extends Record<number, infer T> ? T : never;
type StoreType<DATA extends Data, K> = K extends keyof DATA ? ItemType<DATA[K]> : never;
type StoreTypes<DATA extends Data, K extends (keyof DATA)[]> = {
[I in keyof K]: StoreType<DATA, K[I]>;
};
type MaybeStoreTypes<DATA extends Data, K extends (keyof DATA)[]> = {
[I in keyof K]: StoreType<DATA, K[I]> | null;
};
/**
* Look up components that may or may not exist for an entity
* @param data store
@ -93,12 +96,13 @@ type MaybeStoreTypes<DATA extends Data, K extends (keyof DATA)[]> = {
* @param components names of components to look for
* @returns the cooresponding components, with unfound ones replaced by nulls
*/
export function Lookup<DATA extends Data, K extends (keyof DATA)[]>(data: DATA, [id, generation]: Id, ...components: K): MaybeStoreTypes<DATA, K> {
export function Lookup<DATA extends Data, K extends StoreKeys<DATA>[]>(data: DATA, [id, generation]: Id, ...components: K): MaybeStoreTypes<DATA, K> {
const entity = data.entity[id];
// inactive entities are fine to lookup, but dead ones are not
if(entity && entity.generation == generation && entity.alive != Liveness.DEAD) {
return components.map(storeName => {
const component = data[storeName][id];
const store = data[storeName] as unknown as Store<{}>|SparseStore<{}>;
const component = store[id];
if(component && component.generation == generation) {
return component;
} else {
@ -113,32 +117,32 @@ export function Lookup<DATA extends Data, K extends (keyof DATA)[]>(data: DATA,
// Ergonomic Join typings
export function Join<
DATA extends Data,
A extends keyof DATA,
A extends StoreKeys<DATA>,
> (
data: DATA,
a: A,
): [
Id,
DATA[A][number]
StoreType<DATA, A> & {}
][];
export function Join<
DATA extends Data,
A extends keyof DATA,
B extends keyof DATA,
A extends StoreKeys<DATA>,
B extends StoreKeys<DATA>,
> (
data: DATA,
a: A,
b: B,
): [
Id,
DATA[A][number],
DATA[B][number]
StoreType<DATA, A> & {},
StoreType<DATA, B> & {},
][];
export function Join<
DATA extends Data,
A extends keyof DATA,
B extends keyof DATA,
C extends keyof DATA,
A extends StoreKeys<DATA>,
B extends StoreKeys<DATA>,
C extends StoreKeys<DATA>,
> (
data: DATA,
a: A,
@ -146,16 +150,16 @@ export function Join<
c: C,
): [
Id,
DATA[A][number],
DATA[B][number],
DATA[C][number]
StoreType<DATA, A> & {},
StoreType<DATA, B> & {},
StoreType<DATA, C> & {},
][];
export function Join<
DATA extends Data,
A extends keyof DATA,
B extends keyof DATA,
C extends keyof DATA,
D extends keyof DATA,
A extends StoreKeys<DATA>,
B extends StoreKeys<DATA>,
C extends StoreKeys<DATA>,
D extends StoreKeys<DATA>,
> (
data: DATA,
a: A,
@ -164,18 +168,18 @@ export function Join<
d: D,
): [
Id,
DATA[A][number],
DATA[B][number],
DATA[C][number],
DATA[D][number]
StoreType<DATA, A> & {},
StoreType<DATA, B> & {},
StoreType<DATA, C> & {},
StoreType<DATA, D> & {},
][];
/**
* Query a Data collection for all Alive entities possessing the named set of Components.
* @returns an array of tuples containing the matching entity [ID, generation]s & associated Components
*/
export function Join<DATA extends Data, K extends keyof DATA>(data: DATA, ...components: K[]): [Id, ...{}[]][] {
export function Join<DATA extends Data, K extends StoreKeys<DATA>[]>(data: DATA, ...components: K): [Id, ...{}[]][] {
const entities = data.entity;
const stores: (Store<{}>|SparseStore<{}>)[] = components.map(name => data[name]);
const stores = components.map(name => data[name] as unknown as (Store<{}>|SparseStore<{}>));
const results: [Id, ...{}[]][] = [];
const firstStore = stores[0];