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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#![doc(test(attr(deny(warnings))))]
// Our program-long snippets are more readable with main
#![allow(clippy::needless_doctest_main)]
#![forbid(unsafe_code)]
#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]

//! Support for tokio inside spirit
//!
//! This provides configuration of the tokio runtime and installer of futures.
//!
//! It also provides few configuration [`Fragment`]s for configuring network primitives.
//!
//! Note that this enables several features of [`tokio`].
//!
//! # Features
//!
//! * `rt-from-cfg`: Allows creating runtime from configuration. Enables the [`Tokio::FromCfg`]
//!   variant and [`Config`][crate::runtime::Config]. Enabled by default.
//! * `cfg-help`: Support for generating help for the configuration options.
//! * `net`: Network primitive configuration [`Fragment`]s in the [`net`] module.
//! * `stream`: Implementations of [`tokio_stream::Stream`] on several types.
//! * `futures`: Support for converting between [`futures`'s][futures_util::future::Either] and our
//!   [`Either`][crate::either::Either].
//! * `either`: Support for converting between our [`Either`][crate::either::Either] and the one
//!   from the [`either`] crate.
//!
//! # Examples
//!
//! ```rust
//! use std::future::Future;
//! use std::pin::Pin;
//! use std::time::Duration;
//!
//! use err_context::AnyError;
//! use serde::{Deserialize, Serialize};
//! use spirit::{Empty, Pipeline, Spirit};
//! use spirit::prelude::*;
//! use spirit::fragment::driver::CacheEq;
//! use spirit_tokio::{FutureInstaller, Tokio};
//! use spirit_tokio::runtime::Config as TokioCfg;
//! use structdoc::StructDoc;
//!
//! #[derive(Clone, Debug, Deserialize, PartialEq, Serialize, StructDoc)]
//! #[serde(default)]
//! struct MsgCfg {
//!     /// A message to print now and then.
//!     msg: String,
//!     /// Time between printing the message.
//!     interval: Duration,
//! }
//!
//! impl MsgCfg {
//!     async fn run(self) {
//!         loop {
//!             println!("{}", self.msg);
//!             tokio::time::sleep(self.interval).await;
//!         }
//!     }
//! }
//!
//! impl Default for MsgCfg {
//!     fn default() -> Self {
//!         MsgCfg {
//!             msg: "Hello".to_owned(),
//!             interval: Duration::from_secs(1),
//!         }
//!     }
//! }
//!
//! spirit::simple_fragment! {
//!     impl Fragment for MsgCfg {
//!         type Driver = CacheEq<MsgCfg>;
//!         type Resource = Pin<Box<dyn Future<Output = ()> + Send>>;
//!         type Installer = FutureInstaller;
//!         fn create(&self, _: &'static str) -> Result<Self::Resource, AnyError> {
//!             let fut = self.clone().run();
//!             Ok(Box::pin(fut))
//!         }
//!     }
//! }
//!
//! /// An application.
//! #[derive(Default, Deserialize, Serialize, StructDoc)]
//! struct AppConfig {
//!     #[serde(flatten)]
//!     msg: MsgCfg,
//!
//!     /// Configuration of the asynchronous tokio runtime.
//!     #[serde(default)]
//!     threadpool: TokioCfg,
//! }
//!
//! impl AppConfig {
//!     fn threadpool(&self) -> TokioCfg {
//!         self.threadpool.clone()
//!     }
//!
//!     fn msg(&self) -> &MsgCfg {
//!         &self.msg
//!     }
//! }
//!
//! fn main() {
//!     Spirit::<Empty, AppConfig>::new()
//!         // Makes sure we have a runtime configured from the config.
//!         // If we don't do this, the pipeline below would insert a default Tokio runtime to make
//!         // it work. If you want to customize the runtime (like here), make sure to insert it
//!         // before any pipelines requiring it (otherwise you get the default one from them).
//!         .with_singleton(Tokio::from_cfg(AppConfig::threadpool))
//!         // Will install and possibly cancel and replace the future if the config changes.
//!         .with(Pipeline::new("Msg").extract_cfg(AppConfig::msg))
//!         // Just an empty body here.
//!         .run(|spirit| {
//!             // Usually, one would terminate by CTRL+C, but we terminate from here to make sure
//!             // the example finishes.
//!             spirit.terminate();
//!             Ok(())
//!         })
//! }
//! ```
//!
//! An alternative approach can be seen at [`handlers::ToFutureUnconfigured`].
//!
//! [`Fragment`]: spirit::fragment::Fragment

pub mod either;
pub mod handlers;
pub mod installer;
#[cfg(feature = "net")]
pub mod net;
pub mod runtime;

pub use crate::installer::FutureInstaller;
#[cfg(feature = "net")]
pub use crate::net::{TcpListen, TcpListenWithLimits, UdpListen};
pub use crate::runtime::Tokio;