1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! Lifeline is a dependency injection library for message-based applications.  Lifeline produces applications which are:
//! - **Clean:** Bus implementations provide a high-level overview of the application, and services clearly define the messages they send and receive.
//! - **Decoupled:** Services and tasks have no dependency on their peers, as they only depend on the message types they are sending or receiving.
//! - **Stoppable:** Services and tasks are trivially cancellable.  For example, you can terminate all tasks associated with a connection when a client disconnects.
//! - **Greppable:** The impact/reach of a message can be easily understood by searching for the type in the source code.
//! - **Testable:**  Lifeline applications communicate via messages, which makes unit testing easy.  Spawn the service, send a message, and expect a received message.
//!
//! In order to achieve these goals, lifeline provides patterns, traits, and implementations:
//! - The [Bus](./trait.Bus.html), which constructs & distributes channel Senders/Receivers, and Resources.
//! - The [Carrier](./trait.CarryFrom.html), which translates messages between two Bus instances.  Carriers are critical when building large applications, and help minimize the complexity of the messages on each bus.
//! - The [Service](./trait.Service.html), which takes channels from the bus, and spawns tasks which send and receive messages.
//! - The [Task](./trait.Task.html), an async future which returns a lifeline when spawned. When the lifeline is dropped, the future is immedately cancelled.
//! - The [Resource](./trait.Resource.html), a struct which can be stored in the bus, and taken (or cloned) when services spawn.
//!
//! For a quick introduction, see the [hello.rs example.](https://github.com/austinjones/lifeline-rs/blob/master/examples/hello.rs)
//! For a full-scale application see [tab-rs.](https://github.com/austinjones/tab-rs)
//!
//! ## Quickstart
//! Lifeline uses `tokio` as it's default runtime.  Tokio provides a rich set of async channels.
//! ```toml
//! lifeline = "0.3"
//! ```
//!
//! Lifeline also supports the async-std runtime, and it's `mpsc` channel implementation:
//! ```toml
//! lifeline = { version = "0.3", features = ["dyn-bus", "async-std-executor", "async-std-channels"] }
//! ```
//!
//! ## The Bus
//! The [Bus](./trait.Bus.html) carries channels and resources, and allows you to write loosely coupled [Service](./trait.Service.html) implementations which communicate over messages.
//!
//! Channels can be taken from the bus. If the channel endpoint is clonable, it will remain available for other services.  
//! If the channel is not clonable, future calls will receive an `Err` value. The Rx/Tx type parameters are type-safe,
//! and will produce a compile error if you attempt to take a channel for an message type which the bus does not carry.
//!
//! Lifeline provides a [lifeline_bus!](macro.lifeline_bus.html) macro which stores channels and resources in `Box<dyn>` slots:
//! ```
//! use lifeline::lifeline_bus;
//! lifeline_bus!(pub struct MainBus);
//! ```
//!
//! ## The Carrier
//! [Carriers](./trait.CarryFrom.html) provide a way to move messages between busses. [Carriers](./trait.CarryFrom.html) can translate, ignore, or collect information,
//! providing each bus with the messages that it needs.
//!
//! Large applications have a tree of Busses. This is good, it breaks your app into small chunks.
//! ```text
//! - MainBus
//!   | ConnectionListenerBus
//!   |  | ConnectionBus
//!   | DomainSpecificBus
//!   |  | ...
//! ```
//! [Carriers](./trait.CarryFrom.html) allow each bus to define messages that minimally represent the information it's services need to function, and prevent an explosion of messages which are copied to all busses.
//!
//! [Carriers](./trait.CarryFrom.html) centralize the communication between busses, making large applications easier to reason about.
//!
//! ## The Service
//! The [Service](./trait.Service.html) synchronously takes channels from the [Bus](./trait.Bus.html), and spawns a tree of async tasks (which send & receive messages).
//! When spawned, the service returns one or more [Lifeline](./struct.Lifeline.html) values.  When a [Lifeline](./struct.Lifeline.html) is dropped, the associated task is immediately cancelled.
//!
//! It's common for [Service::spawn](./trait.Service.html#tymethod.spawn) to return a Result.  Taking channel endpoints is a fallible operation.  Depending on the channel type, the endpoint may not be clonable.
//! Lifeline clones endpoints when it can (e.g. for `mpsc::Sender`, `broadcast::*`, and `watch::Receiver`).  Other endpoints are taken, removed, and future calls will return an Err.
//!
//! [Service::spawn](./trait.Service.html#tymethod.spawn) takes channels from the bus synchronously, which makes errors occur predictably and early. If you get an Err on an `mpsc::Receiver`,
//! change it's binding in the bus to `broadcast::Sender`.
//!
//! ## The Task
//! The [Task](./trait.Task.html) executes an Future, and returns a [Lifeline](./struct.Lifeline.html) when spawned.  When the lifeline is dropped, the future is immediately cancelled.
//!
//! [Task](./trait.Task.html) trait is implemented for all types - you can import it and use `Self::task` in any type.  In lifeline, it's
//! most commonly used in Service implementations.
//!
//! ## The Resource
//! [Resources](./trait.Resource.html) can be stored on the bus. This is very useful for configuration (e.g MainConfig), or connections (e.g. a TcpStream).
//!
//! [Resources](./trait.Resource.html) implement the [Storage](./trait.Storage.html) trait, which is easy with the [impl_storage_clone!](./macro.impl_storage_clone.html) and [impl_storage_take!](./macro.impl_storage_take.html) macros.

mod bus;
mod channel;

#[cfg(feature = "dyn-bus")]
pub mod dyn_bus;

pub mod error;
pub mod prelude;

#[cfg(feature = "tokio-channels")]
pub mod request;

mod service;
mod spawn;
mod storage;

// TODO: try to get this as cfg(test)
pub mod test;

pub use bus::*;
pub use channel::lifeline::{Receiver, Sender};

#[cfg(all(feature = "subscription-channel", feature = "tokio-channels"))]
pub use channel::subscription;

#[cfg(feature = "barrier-channel")]
pub use channel::barrier;
pub use channel::Channel;
pub use service::*;
pub use storage::Storage;
pub use storage::*;

pub use channel::lifeline::{receiver::LifelineReceiver, sender::LifelineSender};

pub use spawn::Lifeline;