Skip to content

Commit

Permalink
feat(await): add await class
Browse files Browse the repository at this point in the history
  • Loading branch information
tusharmath committed May 29, 2019
1 parent e7ad928 commit 2343eaf
Show file tree
Hide file tree
Showing 2 changed files with 169 additions and 0 deletions.
63 changes: 63 additions & 0 deletions src/main/Await.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {LinkedList} from 'dbl-linked-list-ds'
import {CB} from '../internals/CB'
import {FIO, IO, UIO} from './FIO'

export class Await<E, A> {
private readonly Q = new LinkedList<[CB<E>, CB<A>]>()
private result: A | undefined
private flag = false
private resolved = false

public static of<E = never, A = never>(): UIO<Await<E, A>> {
return FIO.uio(() => new Await())
}

public set(io: IO<E, A>): UIO<boolean> {
return this.isSet().chain(flag =>
flag
? FIO.of(false)
: this.setFlag(true)
.and(io.chain(result => this.update(result)))
.const(true)
)
}

public isSet(): UIO<boolean> {
return FIO.uio(() => this.flag)
}

public get(): IO<E, A | undefined> {
return this.isResolved().chain(resolved =>
resolved ? FIO.of(this.result) : this.addListener()
)
}

private addListener(): FIO<unknown, E, A> {
return FIO.asyncIO((rej, res) => {
const id = this.Q.add([rej, res])

return {cancel: () => this.Q.remove(id)}
})
}

private setFlag(value: boolean): UIO<void> {
return FIO.uio(() => void (this.flag = value))
}

private isResolved(): UIO<boolean> {
return FIO.uio(() => this.resolved)
}

private update(result: A): UIO<void> {
return FIO.uio(() => {
this.result = result
this.resolved = true
if (this.result !== undefined) {
while (this.Q.length > 0) {
const cb = this.Q.shift() as [CB<E>, CB<A>]
cb[1](this.result)
}
}
})
}
}
106 changes: 106 additions & 0 deletions test/Await.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import {assert} from 'chai'
import {Await} from '../src/main/Await'
import {FIO} from '../src/main/FIO'
import {testRuntime} from '../src/runtimes/TestRuntime'

describe('Await', () => {
describe('of', () => {
it('should create an instance of Await', () => {
const actual = testRuntime({color: 'red'}).executeSync(Await.of())
assert.instanceOf(actual, Await)
})
})

describe('set', () => {
it('should return true', () => {
const actual = testRuntime({color: 'red'}).executeSync(
Await.of<never, string>().chain(await => await.set(FIO.of('Hi')))
)
assert.ok(actual)
})
})

describe('set', () => {
it('should return true', () => {
const actual = testRuntime({color: 'red'}).executeSync(
Await.of<never, string>().chain(await => await.set(FIO.of('Hi')))
)
assert.ok(actual)
})
it('should set only once', () => {
const runtime = testRuntime({color: 'red'})
const actual = runtime.executeSync(
Await.of<never, string>().chain(await =>
await
.set(FIO.of('Hi'))
.and(await.set(FIO.of('Bye')))
.and(await.get())
)
)
assert.strictEqual(actual, 'Hi')
})

it('should return false if its not set', () => {
const runtime = testRuntime({color: 'red'})
const actual = runtime.executeSync(
Await.of<never, string>().chain(await =>
await.set(FIO.of('Hi')).and(await.set(FIO.of('Bye')))
)
)
assert.notOk(actual)
})
})

describe('get', () => {
it('should return the IO value', () => {
const actual = testRuntime({color: 'red'}).executeSync(
Await.of<never, string>().chain(await =>
await.set(FIO.of('Hi')).and(await.get())
)
)
assert.strictEqual(actual, 'Hi')
})

it('should not resolve unless set', () => {
const actual = testRuntime({color: 'red'}).executeSync(
Await.of<never, string>().chain(await => await.get())
)
assert.isUndefined(actual)
})

it('should not return', () => {
const runtime = testRuntime({color: 'red'})
const await = runtime.executeSync(Await.of<never, string>()) as Await<
never,
string
>
let actual: string | undefined
runtime.execute(await.get(), r => (actual = r))
runtime.execute(await.set(FIO.timeout('Hey', 1000)))

assert.isUndefined(actual)
runtime.scheduler.run()
assert.strictEqual(actual, 'Hey')
})
})

describe('isSet()', () => {
it('should return false initially', () => {
const actual = testRuntime({color: 'red'}).executeSync(
Await.of<never, string>().chain(await => await.isSet())
)

assert.notOk(actual)
})

it('should return true after setting', () => {
const actual = testRuntime({color: 'red'}).executeSync(
Await.of<never, number>().chain(await =>
await.set(FIO.of(100)).and(await.isSet())
)
)

assert.ok(actual)
})
})
})

0 comments on commit 2343eaf

Please sign in to comment.