| 1 | import * as Effect from "../../Effect.ts" |
| 2 | import type { EntityAddress } from "../EntityAddress.ts" |
| 3 | import type { ShardId } from "../ShardId.ts" |
| 4 | |
| 5 | const counts = new Map<string, number>() |
| 6 | |
| 7 | const acquire = (key: string) => { |
| 8 | counts.set(key, (counts.get(key) ?? 0) + 1) |
| 9 | } |
| 10 | |
| 11 | const release = (key: string) => { |
| 12 | const n = counts.get(key) |
| 13 | if (n === undefined) return |
| 14 | if (n <= 1) counts.delete(key) |
| 15 | else counts.set(key, n - 1) |
| 16 | } |
| 17 | |
| 18 | const around = <A, E, R>(key: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> => |
| 19 | Effect.suspend(() => { |
| 20 | acquire(key) |
| 21 | return Effect.ensuring(effect, Effect.sync(() => release(key))) |
| 22 | }) |
| 23 | |
| 24 | const entityKey = (address: EntityAddress): string => |
| 25 | `entity:${address.entityType}:${address.entityId}:${address.shardId.toString()}` |
| 26 | |
| 27 | const shardKey = (shardId: ShardId): string => `shard:${shardId.toString()}` |
| 28 | |
| 29 | const entityTypeKey = (entityType: string): string => `type:${entityType}` |
| 30 | |
| 31 | /** |
| 32 | * @internal |
| 33 | */ |
| 34 | export const acquireEntity = (address: EntityAddress): void => acquire(entityKey(address)) |
| 35 | |
| 36 | /** |
| 37 | * @internal |
| 38 | */ |
| 39 | export const releaseEntity = (address: EntityAddress): void => release(entityKey(address)) |
| 40 | |
| 41 | /** |
| 42 | * @internal |
| 43 | */ |
| 44 | export const acquireEntityType = (entityType: string): void => acquire(entityTypeKey(entityType)) |
| 45 | |
| 46 | /** |
| 47 | * @internal |
| 48 | */ |
| 49 | export const releaseEntityType = (entityType: string): void => release(entityTypeKey(entityType)) |
| 50 | |
| 51 | /** |
| 52 | * @internal |
| 53 | */ |
| 54 | export const aroundEntity = <A, E, R>( |
| 55 | address: EntityAddress, |
| 56 | effect: Effect.Effect<A, E, R> |
| 57 | ): Effect.Effect<A, E, R> => around(entityKey(address), effect) |
| 58 | |
| 59 | /** |
| 60 | * @internal |
| 61 | */ |
| 62 | export const aroundShard = <A, E, R>( |
| 63 | shardId: ShardId, |
| 64 | effect: Effect.Effect<A, E, R> |
| 65 | ): Effect.Effect<A, E, R> => around(shardKey(shardId), effect) |
| 66 | |
| 67 | /** |
| 68 | * @internal |
| 69 | */ |
| 70 | export const aroundEntityType = <A, E, R>( |
| 71 | entityType: string, |
| 72 | effect: Effect.Effect<A, E, R> |
| 73 | ): Effect.Effect<A, E, R> => around(entityTypeKey(entityType), effect) |
| 74 | |
| 75 | /** |
| 76 | * @internal |
| 77 | */ |
| 78 | export const isActive = (address: EntityAddress): boolean => |
| 79 | counts.has(entityKey(address)) || |
| 80 | counts.has(shardKey(address.shardId)) || |
| 81 | counts.has(entityTypeKey(address.entityType)) |
| 82 | |
| 83 | /** |
| 84 | * @internal |
| 85 | */ |
| 86 | export const isShardActive = (shardId: ShardId): boolean => counts.has(shardKey(shardId)) |