feat: load FederationConfig with custom dependency injector utility
This commit is contained in:
parent
1b557e045d
commit
2fb54938f6
7 changed files with 420 additions and 65 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1235,6 +1235,7 @@ dependencies = [
|
||||||
"derive-getters",
|
"derive-getters",
|
||||||
"derive_builder",
|
"derive_builder",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
|
"enum_delegate",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"mockall",
|
"mockall",
|
||||||
|
|
|
@ -35,6 +35,7 @@ actix-identity = "0.7.1"
|
||||||
derive_builder = "0.20.0"
|
derive_builder = "0.20.0"
|
||||||
derive-getters = "0.4.0"
|
derive-getters = "0.4.0"
|
||||||
activitypub_federation = "0.5.6"
|
activitypub_federation = "0.5.6"
|
||||||
|
enum_delegate = "0.2.0"
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -8,7 +8,9 @@ use actix_web::web::Data;
|
||||||
use super::RoutesRepository;
|
use super::RoutesRepository;
|
||||||
use crate::federation::adapter::out::forge::forge_factory::FederationForgeAdapterFactoryInterface;
|
use crate::federation::adapter::out::forge::forge_factory::FederationForgeAdapterFactoryInterface;
|
||||||
use crate::federation::application::port::out::db::{get_person::*, save_person::*};
|
use crate::federation::application::port::out::db::{get_person::*, save_person::*};
|
||||||
|
use crate::utils::data::Dependencies;
|
||||||
pub(super) use crate::utils::forges::forge_repository::ForgeRepositoryInterface;
|
pub(super) use crate::utils::forges::forge_repository::ForgeRepositoryInterface;
|
||||||
|
use activitypub_federation::config::FederationConfig;
|
||||||
|
|
||||||
pub type WebFederationOutDBGetPersonObj = Data<FederationOutDBGetPersonObj>;
|
pub type WebFederationOutDBGetPersonObj = Data<FederationOutDBGetPersonObj>;
|
||||||
pub type WebFederationOutDBSavePersonObj = Data<FederationOutDBSavePersonObj>;
|
pub type WebFederationOutDBSavePersonObj = Data<FederationOutDBSavePersonObj>;
|
||||||
|
@ -16,3 +18,15 @@ pub type WebFederationOutDBSavePersonObj = Data<FederationOutDBSavePersonObj>;
|
||||||
pub type WebFederationForgeRepositoryInterface =
|
pub type WebFederationForgeRepositoryInterface =
|
||||||
Data<Arc<dyn ForgeRepositoryInterface<Arc<dyn FederationForgeAdapterFactoryInterface>>>>;
|
Data<Arc<dyn ForgeRepositoryInterface<Arc<dyn FederationForgeAdapterFactoryInterface>>>>;
|
||||||
pub type WebFederationRouteRepository = Data<Arc<RoutesRepository>>;
|
pub type WebFederationRouteRepository = Data<Arc<RoutesRepository>>;
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct FData(pub Arc<Dependencies>);
|
||||||
|
|
||||||
|
impl std::ops::Deref for FData {
|
||||||
|
type Target = Dependencies;
|
||||||
|
fn deref<'a>(&'a self) -> &'a Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type WebFederationConfig = Data<Arc<FederationConfig<FData>>>;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use activitypub_federation::config::FederationConfig;
|
||||||
use actix_web::web;
|
use actix_web::web;
|
||||||
use sqlx::postgres::PgPool;
|
use sqlx::postgres::PgPool;
|
||||||
|
|
||||||
|
@ -11,86 +12,115 @@ pub mod input;
|
||||||
pub mod out;
|
pub mod out;
|
||||||
|
|
||||||
use crate::settings;
|
use crate::settings;
|
||||||
|
use crate::utils::data::Dependencies;
|
||||||
|
use crate::utils::forges::*;
|
||||||
use input::web::types::*;
|
use input::web::types::*;
|
||||||
use out::db::postgres::DBOutPostgresAdapter;
|
use out::db::postgres::DBOutPostgresAdapter;
|
||||||
|
|
||||||
use self::out::forge::forge_factory::*;
|
use self::out::forge::forge_factory::*;
|
||||||
use self::out::forge::forgejo::ForgejoBuilder;
|
use self::out::forge::forgejo::ForgejoBuilder;
|
||||||
use self::out::forge::github::GitHubBuilder;
|
use self::out::forge::github::GitHubBuilder;
|
||||||
use crate::utils::forges::*;
|
|
||||||
//use out::forge::{forge_repository::ForgeRepository, forgejo::Forgejo, github::Github};
|
//use out::forge::{forge_repository::ForgeRepository, forgejo::Forgejo, github::Github};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Adapters {
|
||||||
|
out_db_get_person_adapter: WebFederationOutDBGetPersonObj,
|
||||||
|
out_db_save_person_adapter: WebFederationOutDBSavePersonObj,
|
||||||
|
forge_repository_interface: WebFederationForgeRepositoryInterface,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Adapters {
|
||||||
|
fn new(pool: PgPool, settings: &settings::Settings) -> Self {
|
||||||
|
let db = DBOutPostgresAdapter::new(pool);
|
||||||
|
let out_db_get_person_adapter = WebFederationOutDBGetPersonObj::new(Arc::new(db.clone()));
|
||||||
|
let out_db_save_person_adapter = WebFederationOutDBSavePersonObj::new(Arc::new(db.clone()));
|
||||||
|
|
||||||
|
let forgejo: Arc<dyn FederationForgeAdapterFactoryInterface> =
|
||||||
|
Arc::new(ForgejoAdapterFactory::new(
|
||||||
|
ForgejoBuilder::default()
|
||||||
|
.url(settings.forges.forgejo.url.clone())
|
||||||
|
.client_id(settings.forges.forgejo.client_id.clone())
|
||||||
|
.client_secret(settings.forges.forgejo.client_secret.clone())
|
||||||
|
.settings(settings.clone())
|
||||||
|
.routes(input::web::RoutesRepository::default())
|
||||||
|
.username(settings.forges.forgejo.user.username.clone())
|
||||||
|
.api_token(settings.forges.forgejo.user.api_token.clone())
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
|
));
|
||||||
|
|
||||||
|
let github: Arc<dyn FederationForgeAdapterFactoryInterface> =
|
||||||
|
Arc::new(GitHubAdapterFactory::new(
|
||||||
|
GitHubBuilder::default()
|
||||||
|
.url(settings.forges.github.url.clone())
|
||||||
|
.api_url(settings.forges.github.api_url.clone())
|
||||||
|
.client_id(settings.forges.github.client_id.clone())
|
||||||
|
.settings(settings.clone())
|
||||||
|
.routes(input::web::RoutesRepository::default())
|
||||||
|
.client_secret(settings.forges.github.client_secret.clone())
|
||||||
|
.username(settings.forges.github.user.username.clone())
|
||||||
|
.personal_access_token(
|
||||||
|
settings.forges.github.user.personal_access_token.clone(),
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
|
));
|
||||||
|
|
||||||
|
let forge_repository_interface = {
|
||||||
|
let mut f = ForgeRepository::new();
|
||||||
|
f.add_forge(SupportedForges::Forgejo, forgejo);
|
||||||
|
f.add_forge(SupportedForges::Github, github);
|
||||||
|
let f: Arc<
|
||||||
|
dyn ForgeRepositoryInterface<Arc<dyn FederationForgeAdapterFactoryInterface>>,
|
||||||
|
> = Arc::new(f);
|
||||||
|
WebFederationForgeRepositoryInterface::new(f)
|
||||||
|
};
|
||||||
|
|
||||||
|
Self {
|
||||||
|
out_db_get_person_adapter,
|
||||||
|
out_db_save_person_adapter,
|
||||||
|
forge_repository_interface,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn federation_config(pool: PgPool, settings: &settings::Settings) -> WebFederationConfig {
|
||||||
|
let adapters = Adapters::new(pool, &settings);
|
||||||
|
|
||||||
|
//let mut data = FData::default();
|
||||||
|
let mut data = Dependencies::default();
|
||||||
|
data.insert(adapters.out_db_get_person_adapter.clone());
|
||||||
|
data.insert(adapters.out_db_save_person_adapter.clone());
|
||||||
|
data.insert(adapters.forge_repository_interface.clone());
|
||||||
|
data.insert(settings.clone());
|
||||||
|
data.insert(input::web::RoutesRepository::default());
|
||||||
|
data.insert(WebFederationRouteRepository::new(Arc::new(
|
||||||
|
input::web::RoutesRepository::default(),
|
||||||
|
)));
|
||||||
|
|
||||||
|
let data = FData(Arc::new(data));
|
||||||
|
|
||||||
|
actix_web::web::Data::new(Arc::new(
|
||||||
|
activitypub_federation::config::FederationConfig::builder()
|
||||||
|
.domain(settings.server.domain.clone())
|
||||||
|
.app_data(data.clone())
|
||||||
|
.build()
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_adapters(
|
pub fn load_adapters(
|
||||||
pool: PgPool,
|
pool: PgPool,
|
||||||
settings: &settings::Settings,
|
settings: &settings::Settings,
|
||||||
) -> impl FnOnce(&mut web::ServiceConfig) {
|
) -> impl FnOnce(&mut web::ServiceConfig) {
|
||||||
let db = DBOutPostgresAdapter::new(pool);
|
let adapters = Adapters::new(pool, settings);
|
||||||
let out_db_get_person_adapter = WebFederationOutDBGetPersonObj::new(Arc::new(db.clone()));
|
|
||||||
let out_db_save_person_adapter = WebFederationOutDBSavePersonObj::new(Arc::new(db.clone()));
|
|
||||||
|
|
||||||
let forgejo: Arc<dyn FederationForgeAdapterFactoryInterface> =
|
|
||||||
Arc::new(ForgejoAdapterFactory::new(
|
|
||||||
ForgejoBuilder::default()
|
|
||||||
.url(settings.forges.forgejo.url.clone())
|
|
||||||
.client_id(settings.forges.forgejo.client_id.clone())
|
|
||||||
.client_secret(settings.forges.forgejo.client_secret.clone())
|
|
||||||
.username(settings.forges.forgejo.user.username.clone())
|
|
||||||
.api_token(settings.forges.forgejo.user.api_token.clone())
|
|
||||||
.build()
|
|
||||||
.unwrap(),
|
|
||||||
));
|
|
||||||
|
|
||||||
let github: Arc<dyn FederationForgeAdapterFactoryInterface> =
|
|
||||||
Arc::new(GitHubAdapterFactory::new(
|
|
||||||
GitHubBuilder::default()
|
|
||||||
.url(settings.forges.github.url.clone())
|
|
||||||
.api_url(settings.forges.github.api_url.clone())
|
|
||||||
.client_id(settings.forges.github.client_id.clone())
|
|
||||||
.client_secret(settings.forges.github.client_secret.clone())
|
|
||||||
.username(settings.forges.github.user.username.clone())
|
|
||||||
.personal_access_token(settings.forges.github.user.personal_access_token.clone())
|
|
||||||
.build()
|
|
||||||
.unwrap(),
|
|
||||||
));
|
|
||||||
|
|
||||||
// let forgejo = Forgejo::new(
|
|
||||||
// settings.forges.forgejo.url.clone(),
|
|
||||||
// settings.forges.forgejo.client_id.clone(),
|
|
||||||
// settings.forges.forgejo.client_secret.clone(),
|
|
||||||
// refresh_access_token_input_adapter.clone(),
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// let github = Github::new(
|
|
||||||
// settings.forges.github.url.clone(),
|
|
||||||
// settings.forges.github.api_url.clone(),
|
|
||||||
// settings.forges.github.client_id.clone(),
|
|
||||||
// settings.forges.github.client_secret.clone(),
|
|
||||||
// refresh_access_token_input_adapter.clone(),
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
|
|
||||||
let forge_repository_interface = {
|
|
||||||
let mut f = ForgeRepository::new();
|
|
||||||
f.add_forge(SupportedForges::Forgejo, forgejo);
|
|
||||||
f.add_forge(SupportedForges::Github, github);
|
|
||||||
// f.add_forge(SupportedForges::Github, github);
|
|
||||||
let f: Arc<dyn ForgeRepositoryInterface<Arc<dyn FederationForgeAdapterFactoryInterface>>> =
|
|
||||||
Arc::new(f);
|
|
||||||
WebFederationForgeRepositoryInterface::new(f)
|
|
||||||
};
|
|
||||||
|
|
||||||
let f = move |cfg: &mut web::ServiceConfig| {
|
let f = move |cfg: &mut web::ServiceConfig| {
|
||||||
cfg.configure(input::web::load_ctx());
|
cfg.configure(input::web::load_ctx());
|
||||||
cfg.app_data(out_db_get_person_adapter);
|
cfg.app_data(adapters.out_db_get_person_adapter);
|
||||||
cfg.app_data(out_db_save_person_adapter);
|
cfg.app_data(adapters.out_db_save_person_adapter);
|
||||||
cfg.app_data(forge_repository_interface);
|
cfg.app_data(adapters.forge_repository_interface);
|
||||||
|
|
||||||
// cfg.app_data(forge_repository_interface);
|
|
||||||
//
|
|
||||||
// cfg.app_data(web::Data::new(refresh_access_token_input_adapter));
|
|
||||||
//
|
|
||||||
// cfg.app_data(s);
|
|
||||||
//
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Box::new(f)
|
Box::new(f)
|
||||||
|
|
|
@ -44,6 +44,9 @@ async fn main() {
|
||||||
socket_addr,
|
socket_addr,
|
||||||
settings.server.domain
|
settings.server.domain
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let s = settings.clone();
|
||||||
|
let federation_config = federation::adapter::federation_config(db.pool.clone(), &s).await;
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
.wrap(IdentityMiddleware::default())
|
.wrap(IdentityMiddleware::default())
|
||||||
|
@ -62,6 +65,8 @@ async fn main() {
|
||||||
db.pool.clone(),
|
db.pool.clone(),
|
||||||
&settings,
|
&settings,
|
||||||
))
|
))
|
||||||
|
// .app_data(utils::data::Extensions::default())
|
||||||
|
.app_data(federation_config.clone())
|
||||||
.configure(utils::random_string::GenerateRandomString::inject())
|
.configure(utils::random_string::GenerateRandomString::inject())
|
||||||
})
|
})
|
||||||
.bind(&socket_addr)
|
.bind(&socket_addr)
|
||||||
|
|
303
src/utils/data.rs
Normal file
303
src/utils/data.rs
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
any::{Any, TypeId},
|
||||||
|
collections::HashMap,
|
||||||
|
fmt,
|
||||||
|
hash::{BuildHasherDefault, Hasher},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A hasher for `TypeId`s that takes advantage of its known characteristics.
|
||||||
|
///
|
||||||
|
/// Author of `anymap` crate has done research on the topic:
|
||||||
|
/// https://github.com/chris-morgan/anymap/blob/2e9a5704/src/lib.rs#L599
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct NoOpHasher(u64);
|
||||||
|
|
||||||
|
impl Hasher for NoOpHasher {
|
||||||
|
fn write(&mut self, _bytes: &[u8]) {
|
||||||
|
unimplemented!("This NoOpHasher can only handle u64s")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_u64(&mut self, i: u64) {
|
||||||
|
self.0 = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finish(&self) -> u64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A type map for request depedencies.
|
||||||
|
///
|
||||||
|
/// All entries into this map must be owned types (or static references).
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Dependencies {
|
||||||
|
/// Use AHasher with a std HashMap with for faster lookups on the small `TypeId` keys.
|
||||||
|
map: HashMap<TypeId, Box<dyn Any + Send + Sync>, BuildHasherDefault<NoOpHasher>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dependencies {
|
||||||
|
/// Creates an empty `Dependencies`.
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> Dependencies {
|
||||||
|
Dependencies {
|
||||||
|
map: HashMap::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Insert an item into the map.
|
||||||
|
///
|
||||||
|
/// If an item of this type was already stored, it will be replaced and returned.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use actix_http::Dependencies;
|
||||||
|
/// let mut map = Dependencies::new();
|
||||||
|
/// assert_eq!(map.insert(""), None);
|
||||||
|
/// assert_eq!(map.insert(1u32), None);
|
||||||
|
/// assert_eq!(map.insert(2u32), Some(1u32));
|
||||||
|
/// assert_eq!(*map.get::<u32>().unwrap(), 2u32);
|
||||||
|
/// ```
|
||||||
|
pub fn insert<T: 'static + Send + Sync>(&mut self, val: T) -> Option<T> {
|
||||||
|
self.map
|
||||||
|
.insert(TypeId::of::<T>(), Box::new(val))
|
||||||
|
.and_then(downcast_owned)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if map contains an item of a given type.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use actix_http::Dependencies;
|
||||||
|
/// let mut map = Dependencies::new();
|
||||||
|
/// assert!(!map.contains::<u32>());
|
||||||
|
///
|
||||||
|
/// assert_eq!(map.insert(1u32), None);
|
||||||
|
/// assert!(map.contains::<u32>());
|
||||||
|
/// ```
|
||||||
|
pub fn contains<T: 'static>(&self) -> bool {
|
||||||
|
self.map.contains_key(&TypeId::of::<T>())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a reference to an item of a given type.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use actix_http::Dependencies;
|
||||||
|
/// let mut map = Dependencies::new();
|
||||||
|
/// map.insert(1u32);
|
||||||
|
/// assert_eq!(map.get::<u32>(), Some(&1u32));
|
||||||
|
/// ```
|
||||||
|
pub fn get<T: 'static>(&self) -> Option<&T> {
|
||||||
|
self.map
|
||||||
|
.get(&TypeId::of::<T>())
|
||||||
|
.and_then(|boxed| boxed.downcast_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a mutable reference to an item of a given type.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use actix_http::Dependencies;
|
||||||
|
/// let mut map = Dependencies::new();
|
||||||
|
/// map.insert(1u32);
|
||||||
|
/// assert_eq!(map.get_mut::<u32>(), Some(&mut 1u32));
|
||||||
|
/// ```
|
||||||
|
pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
||||||
|
self.map
|
||||||
|
.get_mut(&TypeId::of::<T>())
|
||||||
|
.and_then(|boxed| boxed.downcast_mut())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove an item from the map of a given type.
|
||||||
|
///
|
||||||
|
/// If an item of this type was already stored, it will be returned.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use actix_http::Dependencies;
|
||||||
|
/// let mut map = Dependencies::new();
|
||||||
|
///
|
||||||
|
/// map.insert(1u32);
|
||||||
|
/// assert_eq!(map.get::<u32>(), Some(&1u32));
|
||||||
|
///
|
||||||
|
/// assert_eq!(map.remove::<u32>(), Some(1u32));
|
||||||
|
/// assert!(!map.contains::<u32>());
|
||||||
|
/// ```
|
||||||
|
pub fn remove<T: 'static>(&mut self) -> Option<T> {
|
||||||
|
self.map.remove(&TypeId::of::<T>()).and_then(downcast_owned)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear the `Dependencies` of all inserted depedencies.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use actix_http::Dependencies;
|
||||||
|
/// let mut map = Dependencies::new();
|
||||||
|
///
|
||||||
|
/// map.insert(1u32);
|
||||||
|
/// assert!(map.contains::<u32>());
|
||||||
|
///
|
||||||
|
/// map.clear();
|
||||||
|
/// assert!(!map.contains::<u32>());
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extends self with the items from another `Dependencies`.
|
||||||
|
pub fn extend(&mut self, other: Dependencies) {
|
||||||
|
self.map.extend(other.map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Dependencies {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("Dependencies").finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn downcast_owned<T: 'static>(boxed: Box<dyn Any + Send + Sync>) -> Option<T> {
|
||||||
|
boxed.downcast().ok().map(|boxed| *boxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_remove() {
|
||||||
|
let mut map = Dependencies::new();
|
||||||
|
|
||||||
|
map.insert::<i8>(123);
|
||||||
|
assert!(map.get::<i8>().is_some());
|
||||||
|
|
||||||
|
map.remove::<i8>();
|
||||||
|
assert!(map.get::<i8>().is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_clear() {
|
||||||
|
let mut map = Dependencies::new();
|
||||||
|
|
||||||
|
map.insert::<i8>(8);
|
||||||
|
map.insert::<i16>(16);
|
||||||
|
map.insert::<i32>(32);
|
||||||
|
|
||||||
|
assert!(map.contains::<i8>());
|
||||||
|
assert!(map.contains::<i16>());
|
||||||
|
assert!(map.contains::<i32>());
|
||||||
|
|
||||||
|
map.clear();
|
||||||
|
|
||||||
|
assert!(!map.contains::<i8>());
|
||||||
|
assert!(!map.contains::<i16>());
|
||||||
|
assert!(!map.contains::<i32>());
|
||||||
|
|
||||||
|
map.insert::<i8>(10);
|
||||||
|
assert_eq!(*map.get::<i8>().unwrap(), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_integers() {
|
||||||
|
static A: u32 = 8;
|
||||||
|
|
||||||
|
let mut map = Dependencies::new();
|
||||||
|
|
||||||
|
map.insert::<i8>(8);
|
||||||
|
map.insert::<i16>(16);
|
||||||
|
map.insert::<i32>(32);
|
||||||
|
map.insert::<i64>(64);
|
||||||
|
map.insert::<i128>(128);
|
||||||
|
map.insert::<u8>(8);
|
||||||
|
map.insert::<u16>(16);
|
||||||
|
map.insert::<u32>(32);
|
||||||
|
map.insert::<u64>(64);
|
||||||
|
map.insert::<u128>(128);
|
||||||
|
map.insert::<&'static u32>(&A);
|
||||||
|
assert!(map.get::<i8>().is_some());
|
||||||
|
assert!(map.get::<i16>().is_some());
|
||||||
|
assert!(map.get::<i32>().is_some());
|
||||||
|
assert!(map.get::<i64>().is_some());
|
||||||
|
assert!(map.get::<i128>().is_some());
|
||||||
|
assert!(map.get::<u8>().is_some());
|
||||||
|
assert!(map.get::<u16>().is_some());
|
||||||
|
assert!(map.get::<u32>().is_some());
|
||||||
|
assert!(map.get::<u64>().is_some());
|
||||||
|
assert!(map.get::<u128>().is_some());
|
||||||
|
assert!(map.get::<&'static u32>().is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_composition() {
|
||||||
|
struct Magi<T>(pub T);
|
||||||
|
|
||||||
|
struct Madoka {
|
||||||
|
pub god: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Homura {
|
||||||
|
pub attempts: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Mami {
|
||||||
|
pub guns: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut map = Dependencies::new();
|
||||||
|
|
||||||
|
map.insert(Magi(Madoka { god: false }));
|
||||||
|
map.insert(Magi(Homura { attempts: 0 }));
|
||||||
|
map.insert(Magi(Mami { guns: 999 }));
|
||||||
|
|
||||||
|
assert!(!map.get::<Magi<Madoka>>().unwrap().0.god);
|
||||||
|
assert_eq!(0, map.get::<Magi<Homura>>().unwrap().0.attempts);
|
||||||
|
assert_eq!(999, map.get::<Magi<Mami>>().unwrap().0.guns);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_depedencies() {
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct MyType(i32);
|
||||||
|
|
||||||
|
let mut depedencies = Dependencies::new();
|
||||||
|
|
||||||
|
depedencies.insert(5i32);
|
||||||
|
depedencies.insert(MyType(10));
|
||||||
|
|
||||||
|
assert_eq!(depedencies.get(), Some(&5i32));
|
||||||
|
assert_eq!(depedencies.get_mut(), Some(&mut 5i32));
|
||||||
|
|
||||||
|
assert_eq!(depedencies.remove::<i32>(), Some(5i32));
|
||||||
|
assert!(depedencies.get::<i32>().is_none());
|
||||||
|
|
||||||
|
assert_eq!(depedencies.get::<bool>(), None);
|
||||||
|
assert_eq!(depedencies.get(), Some(&MyType(10)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_extend() {
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct MyType(i32);
|
||||||
|
|
||||||
|
let mut depedencies = Dependencies::new();
|
||||||
|
|
||||||
|
depedencies.insert(5i32);
|
||||||
|
depedencies.insert(MyType(10));
|
||||||
|
|
||||||
|
let mut other = Dependencies::new();
|
||||||
|
|
||||||
|
other.insert(15i32);
|
||||||
|
other.insert(20u8);
|
||||||
|
|
||||||
|
depedencies.extend(other);
|
||||||
|
|
||||||
|
assert_eq!(depedencies.get(), Some(&15i32));
|
||||||
|
assert_eq!(depedencies.get_mut(), Some(&mut 15i32));
|
||||||
|
|
||||||
|
assert_eq!(depedencies.remove::<i32>(), Some(15i32));
|
||||||
|
assert!(depedencies.get::<i32>().is_none());
|
||||||
|
|
||||||
|
assert_eq!(depedencies.get::<bool>(), None);
|
||||||
|
assert_eq!(depedencies.get(), Some(&MyType(10)));
|
||||||
|
|
||||||
|
assert_eq!(depedencies.get(), Some(&20u8));
|
||||||
|
assert_eq!(depedencies.get_mut(), Some(&mut 20u8));
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,5 +3,6 @@
|
||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
pub mod absolute_url;
|
pub mod absolute_url;
|
||||||
|
pub mod data;
|
||||||
pub mod forges;
|
pub mod forges;
|
||||||
pub mod random_string;
|
pub mod random_string;
|
||||||
|
|
Loading…
Add table
Reference in a new issue