diff --git a/src/core/commands/functional.spec.ts b/src/core/commands/functional.spec.ts new file mode 100644 index 0000000..3eedbe0 --- /dev/null +++ b/src/core/commands/functional.spec.ts @@ -0,0 +1,60 @@ +import { CommandQueue } from '../command-queue'; +import { mapParallel, mapSequential } from './functional'; +import { sequence, waitForSeconds } from '../commands'; + +describe('mapParallel', () => { + it('executes all generated commands in parallel', () => { + const items = [{ x: 1 }, { x: 2 }, { x: 3 }, { x: 4 }]; + const queue = new CommandQueue(); + queue.enqueue( + mapParallel(items, item => + sequence(waitForSeconds(1), () => { + item.x++; + }) + ) + ); + queue.update(0.5); + expect(items).toEqual([{ x: 1 }, { x: 2 }, { x: 3 }, { x: 4 }]); + queue.update(0.5); + expect(items).toEqual([{ x: 2 }, { x: 3 }, { x: 4 }, { x: 5 }]); + }); + + it('skips undefined return values', () => { + const items = [{ x: 1 }, { x: 2 }, { x: 3 }, { x: 4 }]; + const queue = new CommandQueue(); + queue.enqueue( + mapParallel(items, (item, index) => { + if (index % 2 === 0) { + return undefined; + } + return sequence(waitForSeconds(1), () => { + item.x++; + }); + }) + ); + queue.update(0.5); + expect(items).toEqual([{ x: 1 }, { x: 2 }, { x: 3 }, { x: 4 }]); + queue.update(0.5); + expect(items).toEqual([{ x: 1 }, { x: 3 }, { x: 3 }, { x: 5 }]); + }); +}); + +describe('mapSequential', () => { + it('executes all generated commands in sequence', () => { + const items = [{ x: 1 }, { x: 2 }, { x: 3 }, { x: 4 }]; + const queue = new CommandQueue(); + queue.enqueue( + mapSequential(items, item => + sequence(waitForSeconds(1), () => { + item.x++; + }) + ) + ); + queue.update(1); + expect(items).toEqual([{ x: 2 }, { x: 2 }, { x: 3 }, { x: 4 }]); + queue.update(1); + expect(items).toEqual([{ x: 2 }, { x: 3 }, { x: 3 }, { x: 4 }]); + queue.update(2); + expect(items).toEqual([{ x: 2 }, { x: 3 }, { x: 4 }, { x: 5 }]); + }); +}); diff --git a/src/core/commands/functional.ts b/src/core/commands/functional.ts new file mode 100644 index 0000000..b270dca --- /dev/null +++ b/src/core/commands/functional.ts @@ -0,0 +1,25 @@ +import { CommandFactory, Command, parallel, sequence } from '../commands'; + +export function mapParallel(items: Iterable, factory: (item: T, index: number) => Command | undefined): Command { + return parallel(...mapToCommands(items, factory)); +} + +export function mapSequential( + items: Iterable, + factory: (item: T, index: number) => Command | undefined +): Command { + return sequence(...mapToCommands(items, factory)); +} + +function mapToCommands(items: Iterable, factory: (item: T, index: number) => Command | undefined): Command[] { + const commands = []; + let index = 0; + for (const item of items) { + const command = factory(item, index); + ++index; + if (command !== undefined) { + commands.push(command); + } + } + return commands; +}