use crate::prelude::*;
pub trait Resolve<X: Resolvable> {
fn resolve(self) -> X;
}
pub trait ResolveFrom<X>: Resolvable {
fn resolve_from(value: X) -> Self;
}
impl<X, Y: ResolveFrom<X>> Resolve<Y> for X {
fn resolve(self) -> Y {
Y::resolve_from(self)
}
}
pub trait Resolvable {}
#[macro_export]
macro_rules! resolvable_with_identity_impl {
($ty:ty$(,)?) => {
impl Resolvable for $ty {}
impl ResolveFrom<$ty> for $ty {
fn resolve_from(value: $ty) -> $ty {
value
}
}
};
}
#[macro_export]
macro_rules! resolvable_with_try_into_impls {
($ty:ty$(,)?) => {
impl Resolvable for $ty {}
impl<T: TryInto<$ty, Error = E>, E: Debug> ResolveFrom<T> for $ty {
fn resolve_from(value: T) -> $ty {
value.try_into().unwrap_or_else(|err| {
panic!(
"The provided argument could not be resolved into a {}: {err:?}",
core::any::type_name::<$ty>()
)
})
}
}
};
}
impl<'a, X: ResolveFrom<X> + Clone> ResolveFrom<&'a X> for X {
fn resolve_from(value: &'a X) -> X {
value.clone()
}
}
pub trait LabelledResolve<Y: LabelledResolvable> {
fn labelled_resolve(self, resolver: &impl LabelResolver<Y::ResolverOutput>) -> Y;
}
pub trait LabelledResolveFrom<X>: LabelledResolvable {
fn labelled_resolve_from(value: X, resolver: &impl LabelResolver<Self::ResolverOutput>)
-> Self;
}
impl<X, Y: LabelledResolveFrom<X>> LabelledResolve<Y> for X {
fn labelled_resolve(
self,
resolver: &impl LabelResolver<<Y as LabelledResolvable>::ResolverOutput>,
) -> Y {
Y::labelled_resolve_from(self, resolver)
}
}
pub trait LabelledResolvable {
type ResolverOutput;
}
pub trait LabelResolver<X> {
fn resolve_label_into(&self, label: &str) -> X;
}
#[macro_export]
macro_rules! labelled_resolvable_with_identity_impl {
($ty:ty, resolver_output: $resolver_output:ty$(,)?) => {
impl LabelledResolvable for $ty {
type ResolverOutput = $resolver_output;
}
impl LabelledResolveFrom<$ty> for $ty {
fn labelled_resolve_from(
value: Self,
_resolver: &impl LabelResolver<$resolver_output>,
) -> Self {
value
}
}
};
}
#[macro_export]
macro_rules! labelled_resolvable_using_resolvable_impl {
($ty:ty, resolver_output: $resolver_output:ty$(,)?) => {
impl LabelledResolvable for $ty {
type ResolverOutput = $resolver_output;
}
impl<T: Resolve<Self>> LabelledResolveFrom<T> for $ty {
fn labelled_resolve_from(
value: T,
_resolver: &impl LabelResolver<$resolver_output>,
) -> Self {
value.resolve()
}
}
};
}
impl<'a, X: LabelledResolvable<ResolverOutput = X>> LabelledResolveFrom<&'a str> for X {
fn labelled_resolve_from(value: &'a str, resolver: &impl LabelResolver<X>) -> X {
resolver.resolve_label_into(value)
}
}
impl<'a, X: LabelledResolvable<ResolverOutput = X>> LabelledResolveFrom<&'a String> for X {
fn labelled_resolve_from(value: &'a String, resolver: &impl LabelResolver<X>) -> X {
resolver.resolve_label_into(value.as_str())
}
}
impl<X: LabelledResolvable<ResolverOutput = X>> LabelledResolveFrom<String> for X {
fn labelled_resolve_from(value: String, resolver: &impl LabelResolver<X>) -> X {
resolver.resolve_label_into(value.as_str())
}
}
impl<X: LabelledResolvable> LabelledResolvable for Option<X> {
type ResolverOutput = X;
}
impl<X: LabelledResolvable> LabelledResolveFrom<Option<X>> for Option<X> {
fn labelled_resolve_from(value: Option<X>, _resolver: &impl LabelResolver<X>) -> Option<X> {
value
}
}
impl<X: LabelledResolvable> LabelledResolveFrom<X> for Option<X> {
fn labelled_resolve_from(value: X, _resolver: &impl LabelResolver<X>) -> Option<X> {
Some(value)
}
}
impl<'a, X: LabelledResolvable + Clone> LabelledResolveFrom<&'a X> for Option<X> {
fn labelled_resolve_from(value: &'a X, _resolver: &impl LabelResolver<X>) -> Option<X> {
Some(value.clone())
}
}
impl<'a, X: LabelledResolvable + Clone> LabelledResolveFrom<&'a Option<X>> for Option<X> {
fn labelled_resolve_from(value: &'a Option<X>, _resolver: &impl LabelResolver<X>) -> Option<X> {
value.clone()
}
}
impl<'a, X: LabelledResolvable> LabelledResolveFrom<&'a str> for Option<X> {
fn labelled_resolve_from(value: &'a str, resolver: &impl LabelResolver<X>) -> Option<X> {
Some(resolver.resolve_label_into(value))
}
}
impl<'a, X: LabelledResolvable> LabelledResolveFrom<&'a String> for Option<X> {
fn labelled_resolve_from(value: &'a String, resolver: &impl LabelResolver<X>) -> Option<X> {
Some(resolver.resolve_label_into(value.as_str()))
}
}
impl<X: LabelledResolvable> LabelledResolveFrom<String> for Option<X> {
fn labelled_resolve_from(value: String, resolver: &impl LabelResolver<X>) -> Option<X> {
Some(resolver.resolve_label_into(value.as_str()))
}
}
impl<X: LabelledResolvable> LabelledResolvable for Vec<X> {
type ResolverOutput = X;
}
impl<T, X> LabelledResolveFrom<T> for Vec<X>
where
T: IntoIterator,
T::Item: LabelledResolve<X>,
X: LabelledResolvable<ResolverOutput = X>,
{
fn labelled_resolve_from(value: T, resolver: &impl LabelResolver<X>) -> Vec<X> {
value
.into_iter()
.map(|item| LabelledResolve::<X>::labelled_resolve(item, resolver))
.collect()
}
}
impl<X: LabelledResolvable> LabelledResolvable for IndexSet<X> {
type ResolverOutput = X;
}
impl<T, X> LabelledResolveFrom<T> for IndexSet<X>
where
T: IntoIterator,
T::Item: LabelledResolve<X>,
X: LabelledResolvable<ResolverOutput = X> + core::hash::Hash + core::cmp::Eq,
{
fn labelled_resolve_from(value: T, resolver: &impl LabelResolver<X>) -> IndexSet<X> {
value
.into_iter()
.map(|item| LabelledResolve::<X>::labelled_resolve(item, resolver))
.collect()
}
}