use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::Arc;
use crate::ctx::Ctx;
use crate::error::{CordisError, ServiceReadError, ServiceReadFailure};
use crate::key::{InstanceId, Key, TypeKey};
use crate::plugin::{Plugin, PluginFactory};
use crate::{BoxFuture, Effect};
pub trait Deps: Sized + Send + 'static {
type Keys: Clone + Send + Sync + 'static;
fn injects(keys: &Self::Keys, out: &mut Vec<TypeKey>);
fn resolve(keys: &Self::Keys, ctx: &Ctx) -> Result<Self, CordisError>;
}
pub struct DepKey<T: ?Sized + 'static> {
key: TypeKey,
_marker: PhantomData<fn() -> T>,
}
impl<T: ?Sized + 'static> DepKey<T> {
pub fn of() -> Self {
Self::wrap(TypeKey::of::<T>())
}
pub fn named(name: &'static str) -> Self {
Self::wrap(TypeKey::keyed::<T>(name))
}
pub fn dynamic(name: impl Into<Arc<str>>) -> Self {
Self::wrap(TypeKey::keyed_dynamic::<T>(name))
}
pub fn instance(self, id: InstanceId) -> Self {
Self::wrap(self.key.with_instance(id))
}
pub fn key(&self) -> &TypeKey {
&self.key
}
fn wrap(key: TypeKey) -> Self {
Self {
key,
_marker: PhantomData,
}
}
}
impl<T: ?Sized + 'static> From<Key<T>> for DepKey<T> {
fn from(key: Key<T>) -> Self {
Self::wrap(key.into())
}
}
impl<T: ?Sized + 'static> Default for DepKey<T> {
fn default() -> Self {
Self::of()
}
}
impl<T: ?Sized + 'static> Clone for DepKey<T> {
fn clone(&self) -> Self {
Self::wrap(self.key.clone())
}
}
impl<T: ?Sized + 'static> std::fmt::Debug for DepKey<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.key.fmt(f)
}
}
pub struct Keyed<T: ?Sized>(pub Arc<T>);
impl<T: ?Sized> Deref for Keyed<T> {
type Target = Arc<T>;
fn deref(&self) -> &Arc<T> {
&self.0
}
}
pub struct Gate<T: ?Sized>(PhantomData<fn() -> T>);
pub struct KeyedGate<T: ?Sized>(PhantomData<fn() -> T>);
fn require<T: ?Sized + Send + Sync + 'static>(
ctx: &Ctx,
key: &TypeKey,
) -> Result<Arc<T>, CordisError> {
ctx.require_as::<T>(key.clone())
.map_err(|error: ServiceReadError| match error.reason {
ServiceReadFailure::Unavailable(_) => {
CordisError::InjectUnsatisfied(vec![error.key.describe()])
}
_ => error.into(),
})
}
impl<T: ?Sized + Send + Sync + 'static> Deps for Arc<T> {
type Keys = ();
fn injects(_: &(), out: &mut Vec<TypeKey>) {
out.push(TypeKey::of::<T>());
}
fn resolve(_: &(), ctx: &Ctx) -> Result<Self, CordisError> {
require(ctx, &TypeKey::of::<T>())
}
}
impl<T: ?Sized + Send + Sync + 'static> Deps for Option<Arc<T>> {
type Keys = ();
fn injects(_: &(), _: &mut Vec<TypeKey>) {}
fn resolve(_: &(), ctx: &Ctx) -> Result<Self, CordisError> {
Ok(ctx.get_as::<T>(TypeKey::of::<T>()))
}
}
impl<T: ?Sized + Send + Sync + 'static> Deps for Keyed<T> {
type Keys = DepKey<T>;
fn injects(keys: &DepKey<T>, out: &mut Vec<TypeKey>) {
out.push(keys.key.clone());
}
fn resolve(keys: &DepKey<T>, ctx: &Ctx) -> Result<Self, CordisError> {
require(ctx, &keys.key).map(Keyed)
}
}
impl<T: ?Sized + Send + Sync + 'static> Deps for Option<Keyed<T>> {
type Keys = DepKey<T>;
fn injects(_: &DepKey<T>, _: &mut Vec<TypeKey>) {}
fn resolve(keys: &DepKey<T>, ctx: &Ctx) -> Result<Self, CordisError> {
Ok(ctx.get_as::<T>(keys.key.clone()).map(Keyed))
}
}
impl<T: ?Sized + 'static> Deps for Gate<T> {
type Keys = ();
fn injects(_: &(), out: &mut Vec<TypeKey>) {
out.push(TypeKey::of::<T>());
}
fn resolve(_: &(), _: &Ctx) -> Result<Self, CordisError> {
Ok(Gate(PhantomData))
}
}
impl<T: ?Sized + 'static> Deps for KeyedGate<T> {
type Keys = DepKey<T>;
fn injects(keys: &DepKey<T>, out: &mut Vec<TypeKey>) {
out.push(keys.key.clone());
}
fn resolve(_: &DepKey<T>, _: &Ctx) -> Result<Self, CordisError> {
Ok(KeyedGate(PhantomData))
}
}
impl Deps for () {
type Keys = ();
fn injects(_: &(), _: &mut Vec<TypeKey>) {}
fn resolve(_: &(), _: &Ctx) -> Result<Self, CordisError> {
Ok(())
}
}
macro_rules! tuple_deps {
($($name:ident $index:tt),+) => {
impl<$($name: Deps),+> Deps for ($($name,)+) {
type Keys = ($($name::Keys,)+);
fn injects(keys: &Self::Keys, out: &mut Vec<TypeKey>) {
$($name::injects(&keys.$index, out);)+
}
fn resolve(keys: &Self::Keys, ctx: &Ctx) -> Result<Self, CordisError> {
Ok(($($name::resolve(&keys.$index, ctx)?,)+))
}
}
};
}
tuple_deps!(A 0);
tuple_deps!(A 0, B 1);
tuple_deps!(A 0, B 1, C 2);
tuple_deps!(A 0, B 1, C 2, D 3);
tuple_deps!(A 0, B 1, C 2, D 3, E 4);
tuple_deps!(A 0, B 1, C 2, D 3, E 4, F 5);
tuple_deps!(A 0, B 1, C 2, D 3, E 4, F 5, G 6);
tuple_deps!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7);
fn declaration<D: Deps>(keys: &D::Keys) -> Vec<TypeKey> {
let mut all = Vec::new();
D::injects(keys, &mut all);
let mut injects = Vec::with_capacity(all.len());
for key in all {
if !injects.contains(&key) {
injects.push(key);
}
}
injects
}
pub trait TypedPlugin: Send + Sync + 'static {
type Deps: Deps;
fn name(&self) -> &str;
fn validate(&self) -> Result<(), CordisError> {
Ok(())
}
fn apply<'a>(
&'a self,
ctx: &'a Ctx,
deps: Self::Deps,
) -> BoxFuture<'a, Result<Effect, CordisError>>;
}
type KeysOf<P> = <<P as TypedPlugin>::Deps as Deps>::Keys;
pub struct Typed<P: TypedPlugin> {
plugin: P,
keys: KeysOf<P>,
injects: Vec<TypeKey>,
}
impl<P: TypedPlugin> Typed<P> {
pub fn new(plugin: P) -> Self
where
KeysOf<P>: Default,
{
Self::with_keys(plugin, Default::default())
}
pub fn with_keys(plugin: P, keys: KeysOf<P>) -> Self {
let injects = declaration::<P::Deps>(&keys);
Self {
plugin,
keys,
injects,
}
}
pub fn inner(&self) -> &P {
&self.plugin
}
}
impl<P: TypedPlugin> Plugin for Typed<P> {
fn name(&self) -> &str {
self.plugin.name()
}
fn injects(&self) -> &[TypeKey] {
&self.injects
}
fn validate(&self) -> Result<(), CordisError> {
self.plugin.validate()
}
fn apply<'a>(&'a self, ctx: &'a Ctx) -> BoxFuture<'a, Result<Effect, CordisError>> {
match P::Deps::resolve(&self.keys, ctx) {
Ok(deps) => self.plugin.apply(ctx, deps),
Err(error) => Box::pin(async move { Err(error) }),
}
}
}
pub trait TypedPluginFactory<C: Send + Sync + 'static>: Send + Sync + 'static {
type Plugin: TypedPlugin;
fn name(&self) -> &str {
std::any::type_name::<Self>()
}
fn validate_config(&self, _config: &C) -> Result<(), CordisError> {
Ok(())
}
fn build(&self, config: &C) -> Result<Self::Plugin, CordisError>;
}
pub struct TypedFactory<F, C>
where
F: TypedPluginFactory<C>,
C: Send + Sync + 'static,
{
factory: F,
keys: KeysOf<F::Plugin>,
injects: Vec<TypeKey>,
_config: PhantomData<fn() -> C>,
}
impl<F, C> TypedFactory<F, C>
where
F: TypedPluginFactory<C>,
C: Send + Sync + 'static,
{
pub fn new(factory: F) -> Self
where
KeysOf<F::Plugin>: Default,
{
Self::with_keys(factory, Default::default())
}
pub fn with_keys(factory: F, keys: KeysOf<F::Plugin>) -> Self {
let injects = declaration::<<F::Plugin as TypedPlugin>::Deps>(&keys);
Self {
factory,
keys,
injects,
_config: PhantomData,
}
}
}
impl<F, C> PluginFactory<C> for TypedFactory<F, C>
where
F: TypedPluginFactory<C>,
C: Send + Sync + 'static,
{
fn name(&self) -> &str {
self.factory.name()
}
fn injects(&self) -> &[TypeKey] {
&self.injects
}
fn validate_config(&self, config: &C) -> Result<(), CordisError> {
self.factory.validate_config(config)
}
fn build(&self, config: &C) -> Result<Box<dyn Plugin>, CordisError> {
let plugin = self.factory.build(config)?;
Ok(Box::new(Typed::with_keys(plugin, self.keys.clone())))
}
}