UNPKG

state-trooper

Version:
112 lines (95 loc) • 2.56 kB
"use strict"; var Box = require("./channels").Box; var AltHandler = function(flag, f) { this.f = f; this.flag = flag; }; AltHandler.prototype.is_active = function() { return this.flag.value; }; AltHandler.prototype.is_blockable = function() { return true; }; AltHandler.prototype.commit = function() { this.flag.value = false; return this.f; }; var AltResult = function(value, channel) { this.value = value; this.channel = channel; }; function rand_int(n) { return Math.floor(Math.random() * (n + 1)); } function random_array(n) { var a = new Array(n); var i; for (i = 0; i < n; i++) { a[i] = 0; } for (i = 1; i < n; i++) { var j = rand_int(i); a[i] = a[j]; a[j] = i; } return a; } var hasOwnProperty = Object.prototype.hasOwnProperty; var DEFAULT = { toString: function() { return "[object DEFAULT]"; } }; // TODO: Accept a priority function or something exports.do_alts = function(operations, callback, options) { var length = operations.length; // XXX Hmm if (length === 0) { throw new Error("Empty alt list"); } var priority = (options && options.priority) ? true : false; if (!priority) { var indexes = random_array(length); } var flag = new Box(true); for (var i = 0; i < length; i++) { var operation = operations[priority ? i : indexes[i]]; var port, result; // XXX Hmm if (operation instanceof Array) { var value = operation[1]; port = operation[0]; // We wrap this in a function to capture the value of "port", // because js' closure captures vars by "references", not // values. "let port" would have worked, but I don't want to // raise the runtime requirement yet. TODO: So change this when // most runtimes are modern enough. result = port._put(value, (function(port) { return new AltHandler(flag, function(ok) { callback(new AltResult(ok, port)); }); })(port)); } else { port = operation; result = port._take((function(port) { return new AltHandler(flag, function(value) { callback(new AltResult(value, port)); }); })(port)); } // XXX Hmm if (result instanceof Box) { callback(new AltResult(result.value, port)); break; } } if (!(result instanceof Box) && options && hasOwnProperty.call(options, "default")) { if (flag.value) { flag.value = false; callback(new AltResult(options["default"], DEFAULT)); } } }; exports.DEFAULT = DEFAULT;