Last active
December 15, 2018 22:08
-
-
Save mizchi/bdaa2250f1707d6fb09f4115644da0aa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// impl | |
type AnyMsg = { | |
msg: string; | |
}; | |
type AnyCmd = { | |
cmd: string; | |
next: (...args: any) => Msg; | |
}; | |
class Platform<Model, Msg extends AnyMsg, Cmd extends AnyCmd> { | |
_queue: Array<Msg | Cmd> = []; | |
constructor( | |
public _model: Model, | |
public _update: (model: Model, msg: Msg) => [Model, Cmd | null] | |
) {} | |
getModel(): Model { | |
return this._model; | |
} | |
dispatch(msg: Msg | Cmd) { | |
this._queue.push(msg); | |
this._drainQueue(); | |
} | |
_drainQueue() { | |
if (this._queue.length === 0) { | |
return; | |
} | |
const [newQueue, ...restQueue] = this._queue; | |
this._queue = restQueue; | |
let currentCmd: Cmd | null = null; | |
if ((newQueue as any).msg) { | |
const [nextModel, newCmd] = this._update(this._model, newQueue as Msg); | |
this._model = nextModel; | |
currentCmd = newCmd; | |
} else { | |
currentCmd = newQueue as Cmd; | |
} | |
if (currentCmd) { | |
const newMsg = currentCmd.next(); | |
this._queue.push(newMsg as Msg); | |
} | |
this._drainQueue(); | |
} | |
} | |
type Model = { | |
face: number; | |
history: Array<number>; | |
}; | |
// msg | |
function roll(): { | |
msg: "roll"; | |
} { | |
return { | |
msg: "roll" | |
}; | |
} | |
function newFace( | |
n: number | |
): { | |
msg: "newFace"; | |
payload: number; | |
} { | |
return { | |
msg: "newFace", | |
payload: n | |
}; | |
} | |
type Msg = ReturnType<typeof roll> | ReturnType<typeof newFace>; | |
// cmd | |
function random( | |
next: (n: number) => Msg | |
): { | |
cmd: "random"; | |
next: () => Msg; | |
} { | |
return { | |
cmd: random.name as "random", | |
next() { | |
return next(Math.floor(Math.random() * 10)); | |
} | |
}; | |
} | |
type Cmd = ReturnType<typeof random>; | |
const init = () => ({ | |
face: 0, | |
history: [0] | |
}); | |
function update(model: Model, msg: Msg): [Model, Cmd | null] { | |
switch (msg.msg) { | |
case "roll": { | |
return [model, random(newFace)]; | |
} | |
case "newFace": { | |
return [ | |
{ face: msg.payload, history: [msg.payload, ...model.history] }, | |
null | |
]; | |
} | |
default: { | |
return [model, null]; | |
} | |
} | |
} | |
const platform = new Platform<Model, Msg, Cmd>(init(), update); | |
platform.dispatch(roll()); | |
platform.dispatch(roll()); | |
console.log("model", platform.getModel()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment