blob: b8d4e3caaa081e6ce5027116af9ee3b45dfabeb2 [file]
import { Layout, Context } from "rive/host";
import { Jobs } from "rive/jobs";
import { Worker } from "rive/workers";
import { Promise, Settled } from "rive/promise";
import { Signal } from "rive/shared";
import { kWaitTimedOut } from "rive/lane_codes";
export class Reply {
value: f64 = 0;
label: string = "";
}
@job export function square(x: f64): f64 {
return x * x;
}
@job export function fails(code: i32): i32 {
if (code > 0) {
throw new Error("bad code " + code.toString());
}
return code;
}
@worker export async function answer(n: i32): Promise<Reply> {
await Worker.sleep(0.001);
let reply = new Reply();
reply.value = <f64>n * 1.5;
reply.label = "answer " + n.toString();
return reply;
}
@worker export async function quiet(): Promise<void> {
await Worker.sleep(0.001);
}
@worker export async function thrower(code: i32): Promise<f64> {
await Worker.sleep(0.001);
throw new Error("worker code " + code.toString());
}
async function chained(context: Context): Promise<void> {
let squared = await Jobs.run(square, 6.0).promise();
let slept = await Worker.sleep(0.005);
context.log("awaited square " + squared.toString() + " then slept " +
(slept == 0 ? "yes" : "no"));
}
const kAwaits: i32 = 10;
// The main lane awaits jobs, workers, signals and sleeps without blocking:
// each promise settles on a later advance.
export class Main extends Layout {
context: Context? = null;
signal: Signal = Signal.create();
answers: Worker<Reply>? = null;
frames: i32 = 0;
peeked: bool = false;
// Awaits settled so far, of kAwaits.
settled: i32 = 0;
done: bool = false;
override init(context: Context): bool {
this.context = context;
let self = this;
Jobs.run(square, 4.0).promise().andThen((value: f64): void => {
context.log("promise square " + value.toString());
self.settled++;
});
let joined = Jobs.run(square, 5.0);
joined.join();
let late = joined.promise();
context.log("joined promise " + late.getStatus());
late.andThen((value: f64): void => {
context.log("joined promise settled " + value.toString());
self.settled++;
});
Jobs.run(fails, 3).promise().catch((error: string): void => {
context.log("promise rejected " + error);
self.settled++;
});
this.signal.next(0).andThen((seq: f64): void => {
context.log("main signal " + seq.toString());
self.settled++;
});
Signal.create().next(0, 0.01).andThen((seq: f64): void => {
context.log("main signal timed out " + (seq == kWaitTimedOut ? "yes" : "no"));
self.settled++;
});
Worker.sleep(0.01).andThen((value: f64): void => {
context.log("main sleep " + (value == 0 ? "completed" : "early"));
self.settled++;
});
chained(context).andThen((): void => {
self.settled++;
});
let answers = Worker.spawn(answer, 4);
this.answers = answers;
answers.promise().andThen((reply: Reply): void => {
context.log("worker result " + reply.label + " " + reply.value.toString());
self.settled++;
});
Worker.spawn(quiet).promise().andThen((): void => {
context.log("worker void done");
self.settled++;
});
Worker.spawn(thrower, 7).promise().settled().andThen((outcome: Settled<f64>): void => {
context.log("worker rejected " +
(outcome.error.indexOf("worker code 7") >= 0 ? "with code" : outcome.error));
self.settled++;
});
return true;
}
override advance(seconds: f64): bool {
let context = this.context!;
this.frames++;
if (this.frames == 3) {
this.signal.notify();
}
let answers = this.answers!;
if (!this.peeked && !answers.running) {
this.peeked = true;
let peek = answers.peek()!;
context.log("worker peek " + (peek.ok ? peek.value.value.toString() : peek.error));
}
if (!this.done && this.peeked && this.settled == kAwaits) {
this.done = true;
context.log("awaits done");
}
return true;
}
}