macro_rules! impl_provider_utils {
() => {
pub trait TryInto {
type Provider: Provider;
type Error: 'static + core::fmt::Display + Send + Sync;
fn try_into(self) -> Result<Self::Provider, Self::Error>;
}
#[doc(hidden)]
pub trait With<T: Provider> {
type Output;
fn with(self, provider: T) -> Self::Output;
}
impl<T: Provider> TryInto for T {
type Error = core::convert::Infallible;
type Provider = T;
fn try_into(self) -> Result<Self::Provider, Self::Error> {
Ok(self)
}
}
};
}
macro_rules! impl_providers_state {
(
$(#[$($attr:tt)*])* struct Providers {
$(
$(
#[doc = $($doc:tt)*]
)*
$field:ident: $field_ty:ident
),* $(,)?
}
$(
#[doc = $($trait_doc:tt)*]
)*
trait $trait:ident {
}
) => {
#[doc(hidden)]
$(
#[$($attr)*]
)*
pub struct Providers<$($field_ty,)*> {
$(
$(
#[doc = $($doc)*]
)*
$field: $field_ty,
)*
}
$(
#[doc = $($trait_doc)*]
)*
pub trait $trait {
$(
#[doc(hidden)]
type $field_ty: $field::Provider;
)*
#[doc(hidden)]
fn build(self) -> Providers<$(Self::$field_ty,)*>;
#[doc(hidden)]
fn as_ref(&self) -> Providers<$(&Self::$field_ty,)*>;
#[doc(hidden)]
fn as_mut(&mut self) -> Providers<$(&mut Self::$field_ty,)*>;
}
#[doc(hidden)]
impl<$($field_ty: $field::Provider,)*> $trait for Providers<$($field_ty,)*> {
$(
type $field_ty = $field_ty;
)*
fn build(self) -> Providers<$(Self::$field_ty,)*> {
self
}
fn as_ref(&self) -> Providers<$(&Self::$field_ty,)*> {
Providers {
$(
$field: &self.$field,
)*
}
}
fn as_mut(&mut self) -> Providers<$(&mut Self::$field_ty,)*> {
Providers {
$(
$field: &mut self.$field,
)*
}
}
}
#[derive(Debug, Default)]
pub struct DefaultProviders {
providers: Providers<$($field::Default,)*>
}
#[doc(hidden)]
impl $trait for DefaultProviders {
$(
type $field_ty = $field::Default;
)*
fn build(self) -> Providers<$(Self::$field_ty,)*> {
self.providers
}
fn as_ref(&self) -> Providers<$(&Self::$field_ty,)*> {
Providers {
$(
$field: &self.providers.$field,
)*
}
}
fn as_mut(&mut self) -> Providers<$(&mut Self::$field_ty,)*> {
Providers {
$(
$field: &mut self.providers.$field,
)*
}
}
}
impl_providers_state!(@with, $trait, {}, {$($field: $field_ty),*});
};
(@with, $trait:ident, { $($field:ident: $field_ty:ident),* }, {}) => {
};
(@with, $trait:ident, { $($prev:ident: $prev_ty:ident),* }, { $field:ident: $field_ty:ident $(, $rest:ident: $rest_ty:ident)* }) => {
impl<Provider: $trait, New: $field::Provider> $field::With<New> for Builder<Provider> {
type Output = Builder<Providers<$(Provider::$prev_ty, )* New $(, Provider::$rest_ty)*>>;
fn with(self, $field: New) -> Self::Output {
let providers = self.0.build();
Builder(Providers {
$field,
$(
$prev: providers.$prev,
)*
$(
$rest: providers.$rest,
)*
})
}
}
impl_providers_state!(@with, $trait, { $($prev: $prev_ty, )* $field: $field_ty }, {$($rest: $rest_ty),*});
}
}
macro_rules! impl_provider_method {
($(#[$($attr:tt)*])* $name:ident, $field:ident, $trait:ident) => {
$(
#[$($attr)*]
)*
pub fn $name<T, U>(self, $field: T) -> Result<Builder<U>, T::Error>
where
T: $field::TryInto,
U: $trait,
Self: $field::With<T::Provider, Output = Builder<U>>,
{
let $field = $field.try_into()?;
let builder = $field::With::with(self, $field);
Ok(builder)
}
};
}