Skip to content
12 changes: 12 additions & 0 deletions Cargo.toml
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
[workspace]
resolver = "2"
members = ["examples/*", "features/*", "strategies/*", "wrapp"]

[workspace.dependencies]

# Project Modules
wrapp-di = { path = "./features/wrapp-di" }

# External Crates
futures = "0.3"
futures-channel = "0.3"
tracing = "0.1"
pin-project-lite = "0.2"
thiserror = "2.0"
4 changes: 4 additions & 0 deletions features/wrapp-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
wrapp-di.workspace = true

thiserror.workspace = true
tracing.workspace = true
37 changes: 37 additions & 0 deletions features/wrapp-config/examples/using-config-provider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use wrapp_config::provider::ConfigProvider;
Comment thread
Dimi-Provatas marked this conversation as resolved.

#[derive(Clone)]
struct AppConfig {
host: String,
port: u16,
app_name: String,
}

fn main() {
let app_config = AppConfig {
host: "localhost".to_string(),
port: 8080_u16,
app_name: "My Awesome App".to_string(),
};

let mut config_provider = ConfigProvider::new();
let config_provider = match config_provider.add_config(app_config.clone()) {
Ok(p) => p,
Err(e) => {
eprintln!("{e:?}");
return;
}
};

let retrieved_config = match config_provider.config::<AppConfig>() {
Some(c) => c,
None => {
eprintln!("Could not find config type");
return;
}
};

assert_eq!(app_config.host, retrieved_config.host);
assert_eq!(app_config.port, retrieved_config.port);
assert_eq!(app_config.app_name, retrieved_config.app_name);
}
12 changes: 12 additions & 0 deletions features/wrapp-config/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//! Config Errors

use wrapp_di::types::TypeInfo;


/// Errors when trying to register a config
#[derive(thiserror::Error, Debug, Clone)]
pub enum RegisterConfigError {
/// The required Config is already registered
#[error("The required Config type is already registered")]
AlreadyRegistered(TypeInfo),
}
28 changes: 15 additions & 13 deletions features/wrapp-config/src/lib.rs
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
pub fn add(left: usize, right: usize) -> usize {
left + right
}
//! Wrapp Config provides a simple config injection mechanism for Wrapp DI.
//!
//! ### Overview
//!
//! - [`ConfigProvider`](crate::provider::ConfigProvider) - Registry of configs which can be injected into modules.
//! - [`Config<ConfigType>`](crate::resolver::Config) - [`Resolver`](wrapp_di::resolver::Resolver) type which allows for config injections in factories.
//!
//!
//! # Examples
//! ```rust
#![doc = include_str!("../examples/using-config-provider.rs")]
//! ```

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
pub mod resolver;
pub mod errors;
pub mod provider;
61 changes: 61 additions & 0 deletions features/wrapp-config/src/provider.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//! Config provider to register and retrieve configs based on type.

use std::{
any::{Any, TypeId},
collections::HashMap,
sync::Arc,
};

use wrapp_di::types::TypeInfo;

use crate::errors::{RegisterConfigError};

/// A provider to register all configs.
///
/// Configs can be registered and retrieved based on type.
#[derive(Default)]
pub struct ConfigProvider {
configs: HashMap<TypeId, Arc<dyn Any + Send + Sync + 'static>>,
}

impl ConfigProvider {
/// Initializes an empty Config Provider
pub fn new() -> Self {
Self {
configs: HashMap::new(),
}
}

/// Retrieve a config with specified type.
pub fn config<T: Send + Sync + 'static>(&self) -> Option<Arc<T>> {
let type_id = TypeId::of::<T>();

let config = self.configs
.get(&type_id)?;

match config.clone().downcast::<T>() {
Ok(config) => Some(config),
Err(_) => {
debug_assert!(false, "Config Provider contained invalid type in slot for type: {:?}", TypeInfo::of::<T>());
tracing::error!("Config Provider contained invalid type in slot for type: {:?}", TypeInfo::of::<T>());
None
},
}

}

/// Add a config to the registry.
pub fn add_config<T: Send + Sync + 'static>(
&mut self,
config: T,
) -> Result<&mut Self, RegisterConfigError> {
let type_id = TypeId::of::<T>();

if self.configs.contains_key(&type_id) {
return Err(RegisterConfigError::AlreadyRegistered(TypeInfo::of::<T>()));
}

self.configs.insert(type_id, Arc::new(config));
Ok(self)
}
}
92 changes: 92 additions & 0 deletions features/wrapp-config/src/resolver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//! Config resolver for Wrapp DI

use std::{any::type_name, ops::Deref, sync::Arc};

use wrapp_di::{
errors::{InjectError, RequireError},
initiator::DiHandle,
resolver::Resolver,
types::{DependencyInfo, TypeInfo},
};

use crate::provider::ConfigProvider;

/// A wrapper type to allow for config injections
///
/// This provides a simple way to retrieve configs from the config registry,
/// and inject them on a factory as a dependency
///
/// # Example
/// ```ignore
/// # use wrapp_config::provider::ConfigProvider;
/// # use wrapp_config::resolver::Config;
/// #[derive(Clone)]
/// pub struct MyModuleConfig {
/// enabled: bool,
/// //...
/// }
///
/// fn register_config() {
/// let config_provider = ConfigProvider::new();
/// let my_module_config = MyModuleConfig {
/// enabled: true,
/// //...
/// };
///
/// config_provider.add_config(my_module_config).unwrap();
/// }
///
///
/// #[wrapp::module]
/// pub struct MyModule;
/// impl MyModule {
/// #[wrapp::module(condition)]
/// pub fn enable(config: Config<MyModuleConfig>) -> bool {
/// config.enabled
/// }
/// }
///
/// ```
pub struct Config<T> {
Comment thread
Dimi-Provatas marked this conversation as resolved.
inner: Arc<T>,
}
impl<T> Deref for Config<T> {
type Target = T;

fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> Config<T> {
pub fn inner(&self) -> Arc<T> {
self.inner.clone()
}

pub fn into_inner(self) -> Arc<T> {
self.inner
}
}

impl<T: Send + Sync + 'static> Resolver for Config<T> {
async fn resolve(handle: &mut DiHandle) -> Result<Self, InjectError>
where
Self: Sized,
{
let config_name = type_name::<T>();
let config_provider = handle.resolve::<Arc<ConfigProvider>>().await?;

let config: Arc<T> = config_provider
.config()
.ok_or_else(|| InjectError::RequireError(RequireError::TypeMissing(config_name)))?;

Ok(Config { inner: config })
}

fn dependency_info() -> DependencyInfo {
DependencyInfo {
type_info: TypeInfo::of::<Config<T>>(),
optional: false,
lazy: false,
}
}
}
10 changes: 5 additions & 5 deletions features/wrapp-di/Cargo.toml
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
futures = "0.3"
futures-channel = "0.3"
thiserror = "2"
tracing = "0.1"
pin-project-lite = "0.2"
futures.workspace = true
futures-channel.workspace = true
tracing.workspace = true
pin-project-lite.workspace = true
thiserror.workspace = true