@fine-js/channels
Version:
Bits of Clojure's `core.async` ported to JS
116 lines (97 loc) • 2.37 kB
JavaScript
const rename = (func, name, arity = func.length) => Object.defineProperties(func, {
name: {value: name},
length: {value: arity},
})
const createBuffer = (name, blocking, impl) => rename((capacity = 1) => {
const buf = impl(capacity)
const kind = buf.kind || `${name}(${capacity})`
return {
kind,
load: buf.load,
capacity,
blocking,
readable: buf.readable,
writable: buf.writable,
peek: () => {
if (!buf.readable())
throw new Error(`${kind} is empty`)
return buf.peek()
},
read: () => {
if (!buf.readable())
throw new Error(`${kind} is empty`)
return buf.read()
},
write: (val) => {
if (!buf.writable())
throw new Error(`${kind} is full`)
buf.write(val)
},
status: () => ({
kind,
load: buf.load(),
capacity,
blocking,
readable: buf.readable(),
writable: buf.writable(),
}),
}
}, name)
const buffer = createBuffer('buffer', true, (capacity) => {
const buf = []
return {
load: () => buf.length,
peek: () => buf[0],
read: () => buf.shift(),
write: (val) => buf.push(val),
readable: () => buf.length > 0,
writable: () => buf.length < capacity,
}
})
const dropping = createBuffer('dropping', false, (capacity) => {
const buf = []
return {
load: () => buf.length,
peek: () => buf[0],
read: () => buf.shift(),
write: (val) => {
if (capacity > buf.length)
buf.push(val)
},
readable: () => buf.length > 0,
writable: () => true,
}
})
const sliding = createBuffer('sliding', false, (capacity) => {
const buf = []
return {
load: () => buf.length,
peek: () => buf[0],
read: () => buf.shift(),
write: (val) => {
if (buf.push(val) > capacity)
buf.shift()
},
readable: () => buf.length > 0,
writable: () => true,
}
})
const unbuffered = () => Object.freeze({
kind: 'unbuffered()',
load: () => 0,
capacity: 0,
blocking: true,
readable: () => false,
writable: () => false,
peek: () => { throw new Error('peeking into unbuffered()') },
read: () => { throw new Error('reading from unbuffered()') },
write: () => { throw new Error('writing to unbuffered()') },
status: () => null,
})
module.exports = {
unbuffered,
buffer,
dropping,
sliding,
}