Cargo Format

This commit is contained in:
Richard Bradfield 2020-06-02 12:17:59 +01:00
parent 2c5dadba8d
commit 808bc022f3
No known key found for this signature in database
GPG key ID: 0A10CE15CBC4A23F
4 changed files with 60 additions and 59 deletions

View file

@ -177,43 +177,43 @@ macro_rules! private_define_context {
/// Define a new context. Typically used at the top level of an /// Define a new context. Typically used at the top level of an
/// application to contain the full set of requried dependencies. /// application to contain the full set of requried dependencies.
/// ///
/// Contexts follow a struct-like syntax, although the names of /// Contexts follow a struct-like syntax, although the names of
/// fields are for the most part unimportant. /// fields are for the most part unimportant.
/// ///
/// Contexts automatically implement all applicable interfaces. /// Contexts automatically implement all applicable interfaces.
/// An interface is applicable if all of the dependencies /// An interface is applicable if all of the dependencies
/// required by that interface are present in the context. /// required by that interface are present in the context.
/// ///
/// Dependencies are identified by *type*, not by the field name. /// Dependencies are identified by *type*, not by the field name.
/// Contexts may not contain two fields of the same type. Instead /// Contexts may not contain two fields of the same type. Instead
/// use new-type wrappers to distinguish similar dependencies. /// use new-type wrappers to distinguish similar dependencies.
/// ///
/// Types used in a context must implement `Clone + Debug`, and /// Types used in a context must implement `Clone + Debug`, and
/// `Clone` should be a cheap operation. For this reason it is usual /// `Clone` should be a cheap operation. For this reason it is usual
/// to wrap dependencies in an `Rc` or `Arc`. /// to wrap dependencies in an `Rc` or `Arc`.
/// ///
/// A constructor function will be automatically implemented /// A constructor function will be automatically implemented
/// for contexts, with one parameter for each dependency, to be /// for contexts, with one parameter for each dependency, to be
/// provided in the same order as when the context is defined. /// provided in the same order as when the context is defined.
/// ///
/// ## Example /// ## Example
/// ///
/// ``` /// ```
/// use std::sync::Arc; /// use std::sync::Arc;
/// ///
/// #[derive(Debug)] /// #[derive(Debug)]
/// struct Foo; /// struct Foo;
/// #[derive(Debug)] /// #[derive(Debug)]
/// struct Bar; /// struct Bar;
/// ///
/// aerosol::define_context!( /// aerosol::define_context!(
/// TestContext { /// TestContext {
/// foo: Arc<Foo>, /// foo: Arc<Foo>,
/// bar: Arc<Bar>, /// bar: Arc<Bar>,
/// } /// }
/// ); /// );
/// ///
/// fn main() { /// fn main() {
/// TestContext::new( /// TestContext::new(
/// Arc::new(Foo), /// Arc::new(Foo),
@ -221,51 +221,51 @@ macro_rules! private_define_context {
/// ); /// );
/// } /// }
/// ``` /// ```
/// ///
/// It is also possible to define a factory type to enable /// It is also possible to define a factory type to enable
/// dependencies to be automatically created. /// dependencies to be automatically created.
/// ///
/// When a factory is specified for a dependency, it will be /// When a factory is specified for a dependency, it will be
/// omitted from the parameter list required by the context's /// omitted from the parameter list required by the context's
/// constructor. Instead, the constructor will call the `build` /// constructor. Instead, the constructor will call the `build`
/// method on the specified factory. /// method on the specified factory.
/// ///
/// To conditionally use a factory, or use different factories /// To conditionally use a factory, or use different factories
/// for the same dependency, define separate contexts, or /// for the same dependency, define separate contexts, or
/// call the factory manually and pass the result to the /// call the factory manually and pass the result to the
/// context's constructor in the normal way. /// context's constructor in the normal way.
/// ///
/// ## Example /// ## Example
/// ///
/// ``` /// ```
/// use std::sync::Arc; /// use std::sync::Arc;
/// ///
/// #[derive(Debug)] /// #[derive(Debug)]
/// struct Foo; /// struct Foo;
/// #[derive(Debug)] /// #[derive(Debug)]
/// struct Bar; /// struct Bar;
/// ///
/// struct FooFactory; /// struct FooFactory;
/// impl aerosol::Factory for FooFactory { /// impl aerosol::Factory for FooFactory {
/// type Object = Arc<Foo>; /// type Object = Arc<Foo>;
/// fn build(_: ()) -> Result<Arc<Foo>, anyhow::Error> { Ok(Arc::new(Foo)) } /// fn build(_: ()) -> Result<Arc<Foo>, anyhow::Error> { Ok(Arc::new(Foo)) }
/// } /// }
/// ///
/// aerosol::define_context!( /// aerosol::define_context!(
/// TestContext { /// TestContext {
/// foo: Arc<Foo> [FooFactory], /// foo: Arc<Foo> [FooFactory],
/// bar: Arc<Bar>, /// bar: Arc<Bar>,
/// } /// }
/// ); /// );
/// ///
/// fn main() { /// fn main() {
/// TestContext::new( /// TestContext::new(
/// Arc::new(Bar), /// Arc::new(Bar),
/// ); /// );
/// } /// }
/// ``` /// ```
/// ///
/// ///
#[macro_export] #[macro_export]
macro_rules! define_context { macro_rules! define_context {
($($input:tt)*) => ( ($($input:tt)*) => (

View file

@ -133,49 +133,49 @@ macro_rules! private_define_interface {
/// Define a new interface. Used at any layer of your application /// Define a new interface. Used at any layer of your application
/// to declare what dependencies are required by that part of the /// to declare what dependencies are required by that part of the
/// program. /// program.
/// ///
/// Interfaces follow a trait-like syntax, except that they may /// Interfaces follow a trait-like syntax, except that they may
/// only contain "getter" methods of a particular form. The names /// only contain "getter" methods of a particular form. The names
/// of these methods are for the most part unimportant, but the /// of these methods are for the most part unimportant, but the
/// return types are used to identify dependencies required for /// return types are used to identify dependencies required for
/// a context to implement this interface. /// a context to implement this interface.
/// ///
/// ## Example /// ## Example
/// ///
/// ``` /// ```
/// use std::sync::Arc; /// use std::sync::Arc;
/// ///
/// #[derive(Debug)] /// #[derive(Debug)]
/// struct Foo; /// struct Foo;
/// ///
/// aerosol::define_interface!( /// aerosol::define_interface!(
/// TestInterface { /// TestInterface {
/// fn foo(&self) -> Arc<Foo>; /// fn foo(&self) -> Arc<Foo>;
/// } /// }
/// ); /// );
/// ``` /// ```
/// ///
/// Interfaces may also specify super-traits, which can themselves /// Interfaces may also specify super-traits, which can themselves
/// be interfaces. Interfaces do not need to explicitly list /// be interfaces. Interfaces do not need to explicitly list
/// dependencies if they are transitively required by one of their /// dependencies if they are transitively required by one of their
/// super-traits, but repeating a dependency will still only /// super-traits, but repeating a dependency will still only
/// require it to be provided once. /// require it to be provided once.
/// ///
/// ## Example /// ## Example
/// ///
/// ``` /// ```
/// #![recursion_limit="128"] /// #![recursion_limit="128"]
/// use std::sync::Arc; /// use std::sync::Arc;
/// ///
/// #[derive(Debug)] /// #[derive(Debug)]
/// struct Foo; /// struct Foo;
/// ///
/// aerosol::define_interface!( /// aerosol::define_interface!(
/// FooInterface { /// FooInterface {
/// fn foo(&self) -> Arc<Foo>; /// fn foo(&self) -> Arc<Foo>;
/// } /// }
/// ); /// );
/// ///
/// aerosol::define_interface!( /// aerosol::define_interface!(
/// TestInterface: FooInterface + Clone {} /// TestInterface: FooInterface + Clone {}
/// ); /// );

View file

@ -1,53 +1,53 @@
//! # aerosol //! # aerosol
//! Simple dependency injection for Rust //! Simple dependency injection for Rust
//! //!
//! The two main exports of this crate are the `define_context` //! The two main exports of this crate are the `define_context`
//! and `define_interface` macros. //! and `define_interface` macros.
//! //!
//! Contexts are containers for multiple dependencies, allowing //! Contexts are containers for multiple dependencies, allowing
//! them to be passed around as one with relative ease. Interfaces //! them to be passed around as one with relative ease. Interfaces
//! are specialized traits which place constraints on contexts, //! are specialized traits which place constraints on contexts,
//! indicating exactly what dependencies a context must provide. //! indicating exactly what dependencies a context must provide.
//! //!
//! Contexts are typically created at the top level of an application, //! Contexts are typically created at the top level of an application,
//! as they specify exactly what concrete versions of all dependencies //! as they specify exactly what concrete versions of all dependencies
//! are going to be used. A single context is created with a precise //! are going to be used. A single context is created with a precise
//! set of depenencies, and is then threaded through the rest of the //! set of depenencies, and is then threaded through the rest of the
//! application as a generic parameter. //! application as a generic parameter.
//! //!
//! Interfaces are used at every level of an application, as they //! Interfaces are used at every level of an application, as they
//! allow each piece of code to independently specify what dependencies //! allow each piece of code to independently specify what dependencies
//! are required. Interfaces can "inherit" the dependencies of other //! are required. Interfaces can "inherit" the dependencies of other
//! interfaces, with the idea being that this inheritance will form //! interfaces, with the idea being that this inheritance will form
//! a tree, such that there will be some "root interface" which contains //! a tree, such that there will be some "root interface" which contains
//! the union of all dependencies required by the whole application. //! the union of all dependencies required by the whole application.
//! //!
//! This pattern allows dependencies to be added or removed from any //! This pattern allows dependencies to be added or removed from any
//! part of the application without having to modify the code at every //! part of the application without having to modify the code at every
//! level, to thread or un-thread the new or old dependencies through. //! level, to thread or un-thread the new or old dependencies through.
//! //!
//! ## Example //! ## Example
//! //!
//! ``` //! ```
//! #![recursion_limit="128"] //! #![recursion_limit="128"]
//! use std::sync::Arc; //! use std::sync::Arc;
//! use std::fmt::Debug; //! use std::fmt::Debug;
//! //!
//! // We will depend on some kind of logger //! // We will depend on some kind of logger
//! trait Logger: Debug { //! trait Logger: Debug {
//! fn log(&self, msg: &str); //! fn log(&self, msg: &str);
//! } //! }
//! //!
//! // We have a specific implementation of a stdout logger //! // We have a specific implementation of a stdout logger
//! #[derive(Debug)] //! #[derive(Debug)]
//! struct StdoutLogger; //! struct StdoutLogger;
//! //!
//! impl Logger for StdoutLogger { //! impl Logger for StdoutLogger {
//! fn log(&self, msg: &str) { //! fn log(&self, msg: &str) {
//! println!("{}", msg); //! println!("{}", msg);
//! } //! }
//! } //! }
//! //!
//! struct StdoutLoggerFactory; //! struct StdoutLoggerFactory;
//! impl aerosol::Factory for StdoutLoggerFactory { //! impl aerosol::Factory for StdoutLoggerFactory {
//! type Object = Arc<Logger>; //! type Object = Arc<Logger>;
@ -55,29 +55,29 @@
//! Ok(Arc::new(StdoutLogger)) //! Ok(Arc::new(StdoutLogger))
//! } //! }
//! } //! }
//! //!
//! // Part of our application does some work //! // Part of our application does some work
//! aerosol::define_interface!( //! aerosol::define_interface!(
//! WorkerInterface { //! WorkerInterface {
//! fn logger(&self) -> Arc<Logger>; //! fn logger(&self) -> Arc<Logger>;
//! } //! }
//! ); //! );
//! //!
//! fn do_work<I: WorkerInterface>(iface: I) { //! fn do_work<I: WorkerInterface>(iface: I) {
//! iface.logger().log("Doing some work!"); //! iface.logger().log("Doing some work!");
//! } //! }
//! //!
//! // Our application does multiple pieces of work //! // Our application does multiple pieces of work
//! aerosol::define_interface!( //! aerosol::define_interface!(
//! AppInterface: WorkerInterface + Clone {} //! AppInterface: WorkerInterface + Clone {}
//! ); //! );
//! //!
//! fn run_app<I: AppInterface>(iface: I, num_work_items: usize) { //! fn run_app<I: AppInterface>(iface: I, num_work_items: usize) {
//! for _ in 0..num_work_items { //! for _ in 0..num_work_items {
//! do_work(iface.clone()); //! do_work(iface.clone());
//! } //! }
//! } //! }
//! //!
//! // At the very top level, we specify the implementations //! // At the very top level, we specify the implementations
//! // of our dependencies. //! // of our dependencies.
//! aerosol::define_context!( //! aerosol::define_context!(
@ -85,26 +85,25 @@
//! logger: Arc<Logger> [StdoutLoggerFactory], //! logger: Arc<Logger> [StdoutLoggerFactory],
//! } //! }
//! ); //! );
//! //!
//! let context = AppContext::new().unwrap(); //! let context = AppContext::new().unwrap();
//! //!
//! run_app(context, 4); //! run_app(context, 4);
//! ``` //! ```
//! //!
//! See the individual macro documentation for more details. //! See the individual macro documentation for more details.
#[doc(hidden)] #[doc(hidden)]
pub extern crate tt_call; pub extern crate tt_call;
mod context;
mod interface;
mod join; mod join;
mod parse; mod parse;
mod interface;
mod context;
/// The building block for this crate. Automatically implemented /// The building block for this crate. Automatically implemented
/// for contexts providing a dependency of type `T`. /// for contexts providing a dependency of type `T`.
/// ///
/// Super-trait of all interfaces requiring a dependency of type /// Super-trait of all interfaces requiring a dependency of type
/// `T`. /// `T`.
pub trait Provide<T> { pub trait Provide<T> {
@ -113,7 +112,7 @@ pub trait Provide<T> {
/// Implement this trait to provide a convenient syntax for /// Implement this trait to provide a convenient syntax for
/// constructing implementations of dependencies. /// constructing implementations of dependencies.
pub trait Factory<Args=()> { pub trait Factory<Args = ()> {
type Object; type Object;
fn build(args: Args) -> Result<Self::Object, anyhow::Error>; fn build(args: Args) -> Result<Self::Object, anyhow::Error>;
} }

View file

@ -1,4 +1,5 @@
#![recursion_limit="512"] #![recursion_limit = "512"]
#![allow(clippy::blacklisted_name)]
extern crate aerosol; extern crate aerosol;
#[macro_use] #[macro_use]
@ -39,7 +40,9 @@ struct Bar;
impl aerosol::Factory<(Bar,)> for FooFactory { impl aerosol::Factory<(Bar,)> for FooFactory {
type Object = Foo; type Object = Foo;
fn build(_: (Bar,)) -> Result<Foo, anyhow::Error> { Ok(Foo) } fn build(_: (Bar,)) -> Result<Foo, anyhow::Error> {
Ok(Foo)
}
} }
aerosol::define_context!( aerosol::define_context!(
@ -50,7 +53,6 @@ aerosol::define_context!(
); );
fn main() { fn main() {
//trace_macros!(true); //trace_macros!(true);
//aerosol::test_macro!(); //aerosol::test_macro!();
tt_call! { tt_call! {