dependency injection pattern in rust
When I was in california I met Brian Warner (one of the authors of Tahoe LAFS, and now Magic Wormhole) He told me he was implementing Magic Wormhole in rust, and keeping IO completely separate, which makes both testing should make compiling to web assembly very easy. I'm familiar with the internals of web assembly, but not so much with rust. I have started poking around with rust though, so I asked him about this, his response:
https://github.com/warner/magic-wormhole.rs/blob/master/core/src/lib.rs
is probably the best place to start. The whole "core" crate provides
that sans-io API, where the one real entry point is the WormholeCore
trait in lib.rs . You create one with WormholeCore::new, start it with
start(), then feed it with do_api(APIEvent) or do_io(IOEvent). All three
of those return a vector of "Action"s each time, each of which is either
an APIAction (to deliver to some async API call, maybe triggering a
callback or resolving a Future), or an IOAction (which means your IO
layer needs to do something like initiate a connection or write some
bytes or start a timer). Each time the application layer makes an API
call, your glue layer should call do_api(). Each time your IO layer
makes some progress (timer expires, connection gets established or
drops, data is received), your glue layer calls do_io().I haven't actually tried to compile this into wasm, but I think the
sans-io style is a necessary part of that plan. (We allocate a lot of
vectors, and I don't know if the normal wasm toolchain includes a memory
allocator, so maybe one needs "no_std" to target wasm, in which case we
have a lot more work to do).It's certainly a lot better for testing. The test cases (well, the few
that we've written so far) basically create an API object, feed it an
event, and assert that a specific set of Actions come back out. In the
Python code we have to mock out the IO objects so they won't actually
try to use the network.. in the Rust version, we can just look at the
Actions to see what it would have asked the network to do. (Of course we
still need to write tests for the IO layer, but that's now a lot smaller
than the overall Wormhole protocol).
compiling to web assembly will need the IO to be provided by some polyfill of the stuff that is available in the browser, so something like this is probably a good idea. But also, as he mentions, testing is greatly enhanced by this. You could actually simulate the IO and randomly test everything!