#[cfg(feature = "async")]
use std::future::Future;
#[cfg(feature = "async")]
use std::pin::Pin;
pub trait ModuleMeta: 'static {
const NAME: &'static str;
fn dependencies() -> &'static [(&'static str, std::any::TypeId)];
}
pub trait AutoBuilder: ModuleMeta {
type Capability: Clone + 'static;
type Error: std::error::Error + Send + 'static;
fn build(kit: &crate::kit::Kit) -> Result<Self::Capability, Self::Error>;
}
#[cfg(feature = "async")]
pub trait AsyncAutoBuilder: ModuleMeta {
type Capability: Clone + Send + Sync + 'static;
type Error: std::error::Error + Send + 'static;
#[allow(
clippy::type_complexity,
reason = "Pin<Box<dyn Future + Send>> is the canonical dyn-compatible async trait dispatch type"
)]
fn build<'a>(
kit: &'a crate::kit::AsyncKit,
) -> Pin<Box<dyn Future<Output = Result<Self::Capability, Self::Error>> + Send + 'a>>;
}
pub(crate) type BuildFn = Box<
dyn FnOnce(
&crate::kit::Kit,
) -> Result<Box<dyn std::any::Any>, Box<dyn std::error::Error + Send + 'static>>,
>;
#[cfg(all(test, feature = "async"))]
mod async_tests {
use super::*;
use crate::kit::async_kit::AsyncKit;
use crate::test_helpers::{block_on, MockError};
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
#[derive(Debug, Clone, PartialEq)]
struct LoggerCapability {
name: String,
}
struct MockLoggerModule;
impl ModuleMeta for MockLoggerModule {
const NAME: &'static str = "mock-logger";
fn dependencies() -> &'static [(&'static str, std::any::TypeId)] {
&[]
}
}
impl AsyncAutoBuilder for MockLoggerModule {
type Capability = Arc<LoggerCapability>;
type Error = MockError;
fn build<'a>(
kit: &'a AsyncKit,
) -> Pin<Box<dyn Future<Output = Result<Self::Capability, Self::Error>> + Send + 'a>>
{
let _ = kit;
Box::pin(async move {
Ok(Arc::new(LoggerCapability {
name: "mock".to_string(),
}))
})
}
}
#[test]
fn async_auto_builder_returns_pin_box_future() {
let kit = AsyncKit::new();
let fut = MockLoggerModule::build(&kit);
let result = block_on(fut);
assert!(result.is_ok());
let cap = result.expect("build future returned Ok");
assert_eq!(cap.name, "mock");
}
#[test]
fn async_auto_builder_capability_is_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<LoggerCapability>();
assert_send_sync::<Arc<LoggerCapability>>();
}
#[test]
fn async_auto_builder_error_is_send_static() {
fn assert_send_static<T: Send + 'static>() {}
assert_send_static::<MockError>();
}
}