Use Dependency Injection for global emit_* state
Summary:
OCaml conveniently avoids *circularly* depending on higher-level modules
(`emit_*`) by having each `emit_*` use **its own** global mutable state.
However, porting this directly to Rust would require mutexes or `unsafe`,
which impacts performance and/or safety and it is an anti-pattern.
Achieve a similar behavior safely via dynamic dispatch through `Any`,
and let each stateful `emit_*` crate attach its own hidden state
to the emitter by implementing a one-off trait via a convenience macro
(this is required due to the orphan rule for traits in Rust):
struct FooState { ... } // this is crate-private
env::lazy_emit_state!(foo_state, FooState, FooState::init);
This essentially provides a dependency injection mechanism,
since emitter env does not need to know nor initialize any states.
Instead, each stateful crate that already depends on emitter/env
and has access to `e: &mut Emitter` will simply do:
e.emit_state_mut()
*Note*: I made a design decision to panic if `DynState` slot is overtaken
(i.e., two crates using the same `foo_state` field, as this is more fool proof
than silently stomping over a state from the other crate by re-initializing.
Reviewed By: shiqicao
Differential Revision:
D17974004
fbshipit-source-id:
aa59c5487343cf818e76c16ba6aaafd6d5288f97