#promise #js #approximation #bad #completer #scheduler

swear

A bad implementation in Rust of an approximation of a JS A+ Promise

1 unstable release

Uses old Rust 2015

0.1.0 Feb 25, 2018

#15 in #bad

MIT license

14KB
292 lines

Swear

Build Status

This is intended to be a bad implementation in Rust of some approximation of JS A+ Promises.

This is not implemented precisely to spec, modifications have been made in an attempt to make the API slightly more Rust-idiomatic, or altered for other opinionated reasons.

It is only intended to be used in single-threaded applications (none of the types implement Sync), and code is written with a bias for simplicity over performance.

You probably want to take at Futures for a more widely supported implementation Promises / Futures / Deferreds in Rust.

Motivation

I was playing around with stdweb and wasm32-unknown-unknown, and discovered that out of the box, I was unable to use futures::unsync utilities out of the box. As an exercise in exploring lifetime management in Rust, and to create a utility I could use with stdweb, I created Swear.

The design is largely catered toward creating a utility that will be useful in writing wasm-unknown-unknown frontends in rust, following Promise patterns used in JS.

Concepts

Swear

The core utility in this package is a Swear, akin to a javascript Promise. A Swear can have .then called on it exactly once, with a FnOnce callback that is called once the Swear is fulfilled.

When you construct a Swear from scratch with make_swear, you will also receive a Completer, an object that you call complete (again exactly once) in order to fulfill the swear.

Scheduler

There is some question as to from which stack callbacks should be called from once a swear is fulfilled.

One option is always calling it from whichever stack is active as soon as the swear is fulfilled

Note that this may behave subtly differently in different situations:

Option A:

  • Swear is created.
  • Swear has then called on it with callback.
  • Swear is fulfilled. <-- swear callback is called from this stack

Option B:

  • Swear is created.
  • Swear is fulfilled.
  • Swear has then called on it with callback. <-- swear callback is called from this stack

Wanting to avoid confusion about when the callback would be called (and subsequently lifetimes of all variables captured by the closure), this implementation opts to instead always "schedule" the callback for running from some outside scheduler.

An equivalent analysis:

Option A:

  • Swear is created.
  • Swear has then called on it with callback.
  • Swear is fulfilled. <-- swear callback is scheduled from this stack
  • Once current callback/task has completed, swear callback is called from the scheduler directly.

Option B:

  • Swear is created.
  • Swear is fulfilled.
  • Swear has then called on it with callback. <-- swear callback is scheduled from this stack
  • Once current callback/task has completed, swear callback is called from the scheduler directly.

This might be worse for cache-consistency, but unifies the

Provided in the crate is an implementation of a simple "runqueue", a similar JS implementation would be "window.setTimeout(callback, 0)".

This requires that the lifetime of closure (and it's references) usually has to outlive the current stack (in fact, objects that are referenced must be alive for the entire lifetime of the runqueue, not knowing when it will execute the scheduled callback).

Examples

The tests/ directory has two simple examples of how to do simple thenning on Swears. and_then is used if the callback returns another Swear, then is used if the callback returns a non-swear value.

Dependencies

~17KB