11.6.0 • Published 4 years ago

@typed/future v11.6.0

Weekly downloads
134
License
Parity-6.0.0
Repository
github
Last release
4 years ago

@typed/future -- 4.0.0

Small future implemenatation

Get it

yarn add @typed/future
# or
npm install --save @typed/future

API Documentation

All functions are curried!

Fork

Fork function signature used by Future.

export type Fork<A, B> = (reject: (value: A) => void, resolve: (value: B) => void) => Disposable

Future

Asynchronous data-structure similar to a Promise, but lazy.

export interface Future<A, B> {
  readonly fork: Fork<A, B>
}

Future.create\<A, B>(fork: Fork\<A, B>): Future\<A, B>

Creates a Future given a Fork function.

Note: It is the responsibility of the caller to Future.create that neither of the 2 supplied functions will be invoked until the caller has been able to return it's Disposable. If you looking to use Future for something naturally synchronous, @typed/either is likely a better choice for your use case.

export function create<A, B>(fork: Fork<A, B>): Future<A, B> {
  return {
    fork: (reject: (value: A) => void, resolve: (value: B) => void): Disposable => {
      let settled = false
      function isUnsettled(): boolean {
        if (settled) return false

        settled = true

        return true
      }

      const disposable = disposeOnce(
        fork(value => isUnsettled() && reject(value), value => isUnsettled() && resolve(value))
      )

      const dispose = () => disposable.dispose()

      return { dispose }
    },
  }
}

Future.of\<A, B = any>(value: A): Future\<B, A>

Creates a Future which will always fork to the right with the given value.

export function of<A, B = any>(value: A): Future<B, A> {
  return create((_, resolve) => defer(resolve, value))
}

Future.reject\<A, B = any>(value: A): Future\<A, B>

Creates a Future which will always fork to the left with the given value.

export function reject<A, B = any>(value: A): Future<A, B> {
  return create(reject => defer(reject, value))
}
}

function defer<A>(f: (value: A) => void, value: A): Disposable {
const id = setTimeout(f, 0, value)
const dispose = () => clearTimeout(id)

return { dispose }
}

all\<A, B>(futures: ArrayLike\<Future\<A, B>>): Future\<A, ReadonlyArray\<B>>

Creates a Future that concurrently forks all of the given Futures resolving with an Array of their values, or rejecting if any of the futures reject. Conceptually the same as to Promise.all.

export function all<A, B>(futures: ArrayLike<Future<A, B>>): Future<A, ReadonlyArray<B>> {
  const { length: futureCount } = futures
  const values: Array<B> = Array(futureCount)
  const remaining: Remaining = { count: futureCount }

  return Future.create<A, ReadonlyArray<B>>((reject, resolve) =>
    disposeAll(reduce(forkFuture<A, B>(reject, resolve, values, remaining), [], futures))
  )
}

type Remaining = { count: number }

function forkFuture<A, B>(
  reject: (value: A) => void,
  resolve: (value: ReadonlyArray<B>) => void,
  values: Array<B>,
  remaining: Remaining
) {
  return (disposables: Array<Disposable>, future: Future<A, B>, index: number): Array<Disposable> =>
    append(
      fork(
        reject,
        value => {
          values[index] = value
          remaining.count--

          if (remaining.count === 0) resolve(values)
        },
        future
      ),
      disposables
    )
}

ap\<A, B, C>(fn: Future\<A, (value: B) => C>, value: Future\<A, B>): Future\<A, C>

Applies the function resolved from a Future to the value resolved from a second Future.

export const ap: FutureAp = curry2(__ap)

function __ap<A, B, C>(fn: Future<A, (value: B) => C>, value: Future<A, B>): Future<A, C> {
  return chain(f => map(f, value), fn)
}

export type FutureAp = {
  <A, B, C>(fn: Future<A, (value: B) => C>, value: Future<A, B>): Future<A, C>
  <A, B, C>(fn: Future<A, (value: B) => C>): (value: Future<A, B>) => Future<A, C>
}

chain\<A, B, C>(f: (value: B) => Future\<A, C>, future: Future\<A, B>): Future\<A C>

Returns a Future that is the result of calling f with the resolved value of another future. Similar to Promise.then.

export const chain: FutureChain = curry2(__chain)

function __chain<A, B, C>(f: (value: B) => Future<A, C>, future: Future<A, B>): Future<A, C> {
  return Future.create((reject, resolve) =>
    future.fork(reject, value => f(value).fork(reject, resolve))
  )
}

export type FutureChain = {
  <A, B, C>(f: (value: B) => Future<A, C>, future: Future<A, B>): Future<A, C>
  <A, B, C>(f: (value: B) => Future<A, C>): (future: Future<A, B>) => Future<A, C>
}

chainLeft\<A, B, C>(f: (value: A) => Future\<C, B>, future: Future\<A, B>): Future\<C, B>

Returns a Future that is the result of calling f with the rejected value of another future. Similar to Promise.catch.

export const chainLeft: FutureChainLeft = curry2(__chainLeft)

function __chainLeft<A, B, C>(f: (value: A) => Future<C, B>, future: Future<A, B>): Future<C, B> {
  return Future.create((reject, resolve) =>
    future.fork(value => f(value).fork(reject, resolve), resolve)
  )
}

export type FutureChainLeft = {
  <A, B, C>(f: (value: A) => Future<C, B>, future: Future<A, B>): Future<C, B>
  <A, B, C>(f: (value: A) => Future<C, B>): (future: Future<A, B>) => Future<C, B>
}

fork\<A, B>(left: (value: A) => any, right: (value: B) => any, future: Future\<A, B>): Disposable

Activates a future (side-effectful).

export const fork: ForkFn = curry3(forkFuture)

function forkFuture<A, B>(
  left: (value: A) => any,
  right: (value: B) => any,
  future: Future<A, B>
): Disposable {
  return future.fork(left, right)
}

export interface ForkFn {
  <A, B>(left: (value: A) => any, right: (value: B) => any, future: Future<A, B>): Disposable
  <A, B>(left: (value: A) => any): (right: (value: B) => any, future: Future<A, B>) => Disposable
  <A, B>(left: (value: A) => any, right: (value: B) => any): (future: Future<A, B>) => Disposable
  <A, B>(left: (value: A) => any): (
    right: (value: B) => any
  ) => (future: Future<A, B>) => Disposable
}

map\<A, B, C>(f: (value: B) => C, future: Future\<A, B>): Future\<A, C>

Maps the value of a Future. Similar to Promise.then.

export const map: FutureMap = curry2(__map)

function __map<A, B, C>(f: (value: B) => C, future: Future<A, B>): Future<A, C> {
  return chain(b => Future.of(f(b)), future)
}

export type FutureMap = {
  <A, B, C>(f: (value: B) => C, future: Future<A, B>): Future<A, C>
  <A, B, C>(f: (value: B) => C): (future: Future<A, B>) => Future<A, C>
}

mapLeft\<A, B, C>(f: (value: A) => C, future: Future\<A, B>): Future\<C, B>

Returns a Future that is the result of calling f with the rejected value of another future. Similar to Promise.catch.

export const mapLeft: FutureMapLeft = curry2(__mapLeft)

function __mapLeft<A, B, C>(f: (value: A) => C, future: Future<A, B>): Future<C, B> {
  return chainLeft(value => Future.reject(f(value)), future)
}

export type FutureMapLeft = {
  <A, B, C>(f: (value: A) => C, future: Future<A, B>): Future<C, B>
  <A, B, C>(f: (value: A) => C): (future: Future<A, B>) => Future<C, B>
}

sequence\<A, B>(futures: ArrayLike\<Future\<A, B>>): Future\<A, ReadonlyArray\<B>>

Creates a Future that will lazily fork each Future one after another. Similar to all except that concurrency is always 1.

export function sequence<A, B>(futures: ArrayLike<Future<A, B>>): Future<A, ReadonlyArray<B>> {
  let seed = Future.of<Array<B>, A>([])

  for (let i = 0; i < futures.length; ++i) {
    const future = futures[i]

    seed = chain(values => map(value => values.concat(value), future), seed)
  }

  return seed
}

toPromise\<A>(future: Future\<any, A>): Promise\<A>

Forks a Future into a Promise

export function toPromise<A>(future: Future<any, PromiseLike<A>>): Promise<A>
export function toPromise<A>(future: Future<any, A>): Promise<A>
export function toPromise<A>(future: Future<any, A>): Promise<A> {
  return new Promise<A>((resolve, reject) => future.fork(reject, resolve))
}
11.6.0

4 years ago

11.5.4

4 years ago

11.5.3

4 years ago

11.5.2

4 years ago

11.5.1

4 years ago

11.5.0

4 years ago

11.4.1

4 years ago

11.4.0

4 years ago

11.3.0

4 years ago

11.2.1

4 years ago

11.2.0

4 years ago

11.1.1

4 years ago

11.1.0

4 years ago

11.0.0

4 years ago

10.2.0

4 years ago

10.1.0

4 years ago

10.0.0

4 years ago

9.0.1

4 years ago

9.0.0

4 years ago

8.1.0

4 years ago

8.0.0

4 years ago

7.0.0

4 years ago

6.3.0

4 years ago

6.2.0

4 years ago

6.1.0

4 years ago

6.0.2

4 years ago

6.0.1

4 years ago

6.0.0

4 years ago

5.0.0

5 years ago

4.0.0

7 years ago

3.2.0

7 years ago

3.1.0

7 years ago

3.0.0

7 years ago

2.1.0

7 years ago

2.0.0

7 years ago

1.0.1

7 years ago

1.0.0

7 years ago