Aktueller Stand

This commit is contained in:
2026-01-23 01:33:35 +01:00
parent 082dc5e110
commit 2766dd12c5
10109 changed files with 1578841 additions and 77685 deletions

View File

@@ -0,0 +1,60 @@
import { scheduleCommands } from './commands/ScheduledCommand.js';
const genericModelRun = (s, cmds, initialValue, runCmd, then) => {
return s.then((o) => {
const { model, real } = o;
let state = initialValue;
for (const c of cmds) {
state = then(state, () => {
return runCmd(c, model, real);
});
}
return state;
});
};
const internalModelRun = (s, cmds) => {
const then = (_p, c) => c();
const setupProducer = {
then: (fun) => {
fun(s());
return undefined;
},
};
const runSync = (cmd, m, r) => {
if (cmd.check(m))
cmd.run(m, r);
return undefined;
};
return genericModelRun(setupProducer, cmds, undefined, runSync, then);
};
const isAsyncSetup = (s) => {
return typeof s.then === 'function';
};
const internalAsyncModelRun = async (s, cmds, defaultPromise = Promise.resolve()) => {
const then = (p, c) => p.then(c);
const setupProducer = {
then: (fun) => {
const out = s();
if (isAsyncSetup(out))
return out.then(fun);
else
return fun(out);
},
};
const runAsync = async (cmd, m, r) => {
if (await cmd.check(m))
await cmd.run(m, r);
};
return await genericModelRun(setupProducer, cmds, defaultPromise, runAsync, then);
};
export function modelRun(s, cmds) {
internalModelRun(s, cmds);
}
export async function asyncModelRun(s, cmds) {
await internalAsyncModelRun(s, cmds);
}
export async function scheduledModelRun(scheduler, s, cmds) {
const scheduledCommands = scheduleCommands(scheduler, cmds);
const out = internalAsyncModelRun(s, scheduledCommands, scheduler.schedule(Promise.resolve(), 'startModel'));
await scheduler.waitFor(out);
await scheduler.waitAll();
}

View File

@@ -0,0 +1,78 @@
export class ReplayPath {
static parse(replayPathStr) {
const [serializedCount, serializedChanges] = replayPathStr.split(':');
const counts = this.parseCounts(serializedCount);
const changes = this.parseChanges(serializedChanges);
return this.parseOccurences(counts, changes);
}
static stringify(replayPath) {
const occurences = this.countOccurences(replayPath);
const serializedCount = this.stringifyCounts(occurences);
const serializedChanges = this.stringifyChanges(occurences);
return `${serializedCount}:${serializedChanges}`;
}
static intToB64(n) {
if (n < 26)
return String.fromCharCode(n + 65);
if (n < 52)
return String.fromCharCode(n + 97 - 26);
if (n < 62)
return String.fromCharCode(n + 48 - 52);
return String.fromCharCode(n === 62 ? 43 : 47);
}
static b64ToInt(c) {
if (c >= 'a')
return c.charCodeAt(0) - 97 + 26;
if (c >= 'A')
return c.charCodeAt(0) - 65;
if (c >= '0')
return c.charCodeAt(0) - 48 + 52;
return c === '+' ? 62 : 63;
}
static countOccurences(replayPath) {
return replayPath.reduce((counts, cur) => {
if (counts.length === 0 || counts[counts.length - 1].count === 64 || counts[counts.length - 1].value !== cur)
counts.push({ value: cur, count: 1 });
else
counts[counts.length - 1].count += 1;
return counts;
}, []);
}
static parseOccurences(counts, changes) {
const replayPath = [];
for (let idx = 0; idx !== counts.length; ++idx) {
const count = counts[idx];
const value = changes[idx];
for (let num = 0; num !== count; ++num)
replayPath.push(value);
}
return replayPath;
}
static stringifyChanges(occurences) {
let serializedChanges = '';
for (let idx = 0; idx < occurences.length; idx += 6) {
const changesInt = occurences
.slice(idx, idx + 6)
.reduceRight((prev, cur) => prev * 2 + (cur.value ? 1 : 0), 0);
serializedChanges += this.intToB64(changesInt);
}
return serializedChanges;
}
static parseChanges(serializedChanges) {
const changesInt = serializedChanges.split('').map((c) => this.b64ToInt(c));
const changes = [];
for (let idx = 0; idx !== changesInt.length; ++idx) {
let current = changesInt[idx];
for (let n = 0; n !== 6; ++n, current >>= 1) {
changes.push(current % 2 === 1);
}
}
return changes;
}
static stringifyCounts(occurences) {
return occurences.map(({ count }) => this.intToB64(count - 1)).join('');
}
static parseCounts(serializedCount) {
return serializedCount.split('').map((c) => this.b64ToInt(c) + 1);
}
}

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,35 @@
import { asyncToStringMethod, hasAsyncToStringMethod, hasToStringMethod, toStringMethod, } from '../../../utils/stringify.js';
import { cloneMethod, hasCloneMethod } from '../../symbols.js';
export class CommandWrapper {
constructor(cmd) {
this.cmd = cmd;
this.hasRan = false;
if (hasToStringMethod(cmd)) {
const method = cmd[toStringMethod];
this[toStringMethod] = function toStringMethod() {
return method.call(cmd);
};
}
if (hasAsyncToStringMethod(cmd)) {
const method = cmd[asyncToStringMethod];
this[asyncToStringMethod] = function asyncToStringMethod() {
return method.call(cmd);
};
}
}
check(m) {
return this.cmd.check(m);
}
run(m, r) {
this.hasRan = true;
return this.cmd.run(m, r);
}
clone() {
if (hasCloneMethod(this.cmd))
return new CommandWrapper(this.cmd[cloneMethod]());
return new CommandWrapper(this.cmd);
}
toString() {
return this.cmd.toString();
}
}

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,21 @@
import { cloneMethod } from '../../symbols.js';
export class CommandsIterable {
constructor(commands, metadataForReplay) {
this.commands = commands;
this.metadataForReplay = metadataForReplay;
}
[Symbol.iterator]() {
return this.commands[Symbol.iterator]();
}
[cloneMethod]() {
return new CommandsIterable(this.commands.map((c) => c.clone()), this.metadataForReplay);
}
toString() {
const serializedCommands = this.commands
.filter((c) => c.hasRan)
.map((c) => c.toString())
.join(',');
const metadata = this.metadataForReplay();
return metadata.length !== 0 ? `${serializedCommands} /*${metadata}*/` : serializedCommands;
}
}

View File

@@ -0,0 +1,53 @@
export class ScheduledCommand {
constructor(s, cmd) {
this.s = s;
this.cmd = cmd;
}
async check(m) {
let error = null;
let checkPassed = false;
const status = await this.s.scheduleSequence([
{
label: `check@${this.cmd.toString()}`,
builder: async () => {
try {
checkPassed = await Promise.resolve(this.cmd.check(m));
}
catch (err) {
error = err;
throw err;
}
},
},
]).task;
if (status.faulty) {
throw error;
}
return checkPassed;
}
async run(m, r) {
let error = null;
const status = await this.s.scheduleSequence([
{
label: `run@${this.cmd.toString()}`,
builder: async () => {
try {
await this.cmd.run(m, r);
}
catch (err) {
error = err;
throw err;
}
},
},
]).task;
if (status.faulty) {
throw error;
}
}
}
export const scheduleCommands = function* (s, cmds) {
for (const cmd of cmds) {
yield new ScheduledCommand(s, cmd);
}
};