Skip to content
This repository has been archived by the owner on Mar 28, 2023. It is now read-only.

Commit

Permalink
Fixes cleanup when composing tasks (origamitower/folktale#66)
Browse files Browse the repository at this point in the history
  • Loading branch information
robotlolita committed Jan 17, 2017
1 parent 2135250 commit 1fc974f
Showing 1 changed file with 44 additions and 24 deletions.
68 changes: 44 additions & 24 deletions lib/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@
var Maybe = require('data.maybe')
var compose = require('core.lambda').compose;


// -- Helpers ----------------------------------------------------------
/**
* A helper for delaying the execution of a function.
* @private
* @summary (Any... -> Any) -> Void
*/
var delayed = typeof setImmediate !== 'undefined'? setImmediate
: typeof process !== 'undefined'? process.nextTick
: /* otherwise */ setTimeout


// -- Implementation ---------------------------------------------------
module.exports = function(Future) {
var exports = {}
Expand Down Expand Up @@ -105,31 +117,34 @@ module.exports = function(Future) {
*/
exports.parallel = parallel
function parallel(xs) {
function cleanupAll() {
xs.forEach(function(x){ x.cleanup() }) }
function cleanupAll(state) {
xs.forEach(function(x, i){ x.cleanup(state[i]) }) }

return new Future(function(reject, resolve) {
var len = xs.length
var result = new Array(len)
var state = new Array(len)
var resolved = false

if (xs.length === 0) resolve([])
else xs.forEach(runComputation)

return state

function runComputation(x, i) {
return x.fork( function(e) {
if (resolved) return
resolved = true
cleanupAll()
reject(e) }
state[i] = x.fork( function(e) {
if (resolved) return
resolved = true
delayed(function(){ cleanupAll(state) })
reject(e) }

, function(v) {
if (resolved) return
result[i] = v
len = len - 1
if (len === 0) { resolved = true
cleanupAll()
resolve(result) }})}
, function(v) {
if (resolved) return
result[i] = v
len = len - 1
if (len === 0) { resolved = true
delayed(function(){ cleanupAll(state) })
resolve(result) }})}
}, cleanupAll)}


Expand All @@ -141,21 +156,25 @@ module.exports = function(Future) {
*/
exports.nondeterministicChoice = nondeterministicChoice
function nondeterministicChoice(xs){
function cleanupAll() {
xs.forEach(function(x){ x.cleanup() }) }
function cleanupAll(state) {
xs.forEach(function(x, i){ x.cleanup(state[i]) }) }

return new Future(function(reject, resolve) {
var resolved = false
var state = new Array(xs.length);

if (xs.length === 0)
resolve(Maybe.Nothing())
else
xs.forEach(function(x){ x.fork( function(e){ transition(reject, e) }
xs.forEach(function(x, i){
state[i] = x.fork( function(e){ transition(reject, e) }
, function(v){ transition(compose(resolve, Maybe.of), v) }) })

return state

function transition(f, a) {
if (!resolved) { resolved = true
cleanupAll()
delayed(function(){ cleanupAll(state) })
f(a) }}
}, cleanupAll)}

Expand All @@ -179,20 +198,21 @@ module.exports = function(Future) {
*/
exports.tryAll = tryAll
function tryAll(xs) {
function cleanupAll() {
xs.forEach(function(x){ x.cleanup() }) }
function cleanupAll(state) {
xs.forEach(function(x, i){ x.cleanup(state) }) }

return new Future(function(reject, resolve) {
var resolved = false
var pending = xs.length
var failures = new Array(pending)

if (xs.length === 0)
if (xs.length === 0) {
resolve(Maybe.Nothing())
return [] }
else
xs.forEach(function(x, i){ x.fork( accumulateFailure(i)
, function(v) { resolved = true
resolve(Maybe.of(v)) })})
return xs.map(function(x, i){ return x.fork( accumulateFailure(i)
, function(v) { resolved = true
resolve(Maybe.of(v)) })})

function accumulateFailure(index){ return function(error) {
if (resolved) return
Expand Down

0 comments on commit 1fc974f

Please sign in to comment.