froodi 1.0.0-beta.18

An ergonomic Rust IoC container
Documentation
use crate::{any::TypeInfo, macros_utils::types::RegistryOrEntry, registry::InstantiatorData, utils::hlist, Registry};

pub trait Merge<T> {
    type Output;

    #[must_use]
    fn merge(self, other: T) -> Self::Output;
}

impl Merge<Registry> for Registry {
    type Output = Registry;

    #[inline]
    fn merge(mut self, other: Registry) -> Self::Output {
        self.entries.extend(other.entries);
        self
    }
}

impl Merge<(TypeInfo, InstantiatorData)> for Registry {
    type Output = Registry;

    #[inline]
    fn merge(mut self, (key, value): (TypeInfo, InstantiatorData)) -> Self::Output {
        self.entries.insert(key, value);
        self
    }
}

impl Merge<RegistryOrEntry> for Registry {
    type Output = Self;

    #[inline]
    fn merge(self, registry_or_entry: RegistryOrEntry) -> Self::Output {
        match registry_or_entry {
            RegistryOrEntry::Registry(registry) => self.merge(registry),
            RegistryOrEntry::Entry(entry) => self.merge(entry),
        }
    }
}

impl<H> Merge<H> for Registry
where
    H: hlist::IntoIterator<RegistryOrEntry>,
{
    type Output = Self;

    #[inline]
    fn merge(self, other: H) -> Self::Output {
        other.into_iter().fold(self, Merge::merge)
    }
}

#[cfg(feature = "async")]
mod async_impl {
    use super::{hlist, Merge, Registry, TypeInfo};
    use crate::{
        async_impl::{self, RegistryWithSync},
        macros_utils::types::{
            RegistryKind::{self, Async, AsyncWithSync, Sync},
            RegistryKindOrEntry::{self, Entry, Kind},
        },
    };

    impl Merge<async_impl::Registry> for async_impl::Registry {
        type Output = Self;

        #[inline]
        fn merge(mut self, registry: Self) -> Self::Output {
            self.entries.extend(registry.entries);
            self
        }
    }

    impl Merge<Registry> for async_impl::Registry {
        type Output = RegistryWithSync;

        #[inline]
        fn merge(self, sync: Registry) -> Self::Output {
            Self::Output { registry: self, sync }
        }
    }

    impl Merge<async_impl::Registry> for Registry {
        type Output = RegistryWithSync;

        #[inline]
        fn merge(self, registry: async_impl::Registry) -> Self::Output {
            Self::Output { registry, sync: self }
        }
    }

    impl Merge<RegistryWithSync> for RegistryWithSync {
        type Output = Self;

        #[inline]
        fn merge(mut self, registry: RegistryWithSync) -> Self::Output {
            self.sync.entries.extend(registry.sync.entries);
            self.registry.entries.extend(registry.registry.entries);
            self
        }
    }

    impl Merge<Registry> for RegistryWithSync {
        type Output = Self;

        #[inline]
        fn merge(mut self, registry: Registry) -> Self::Output {
            self.sync.entries.extend(registry.entries);
            self
        }
    }

    impl Merge<async_impl::Registry> for RegistryWithSync {
        type Output = Self;

        #[inline]
        fn merge(mut self, registry: async_impl::Registry) -> Self::Output {
            self.registry.entries.extend(registry.entries);
            self
        }
    }

    impl Merge<(TypeInfo, async_impl::InstantiatorData)> for Registry {
        type Output = RegistryWithSync;

        #[inline]
        fn merge(self, (key, value): (TypeInfo, async_impl::InstantiatorData)) -> Self::Output {
            let mut registry = async_impl::Registry::default();
            registry.entries.insert(key, value);
            Self::Output { registry, sync: self }
        }
    }

    impl Merge<(TypeInfo, async_impl::InstantiatorData)> for async_impl::Registry {
        type Output = Self;

        #[inline]
        fn merge(mut self, (key, value): (TypeInfo, async_impl::InstantiatorData)) -> Self::Output {
            self.entries.insert(key, value);
            self
        }
    }

    impl Merge<(TypeInfo, async_impl::InstantiatorData)> for RegistryWithSync {
        type Output = Self;

        #[inline]
        fn merge(mut self, (key, value): (TypeInfo, async_impl::InstantiatorData)) -> Self::Output {
            self.registry.entries.insert(key, value);
            self
        }
    }

    impl Merge<Registry> for RegistryKind {
        type Output = Self;

        #[inline]
        fn merge(self, registry: Registry) -> Self::Output {
            match self {
                Sync(other) => Sync(registry.merge(other)),
                Async(other) => AsyncWithSync(registry.merge(other)),
                AsyncWithSync(other) => AsyncWithSync(other.merge(registry)),
            }
        }
    }

    impl Merge<async_impl::Registry> for RegistryKind {
        type Output = Self;

        #[inline]
        fn merge(self, registry: async_impl::Registry) -> Self::Output {
            match self {
                Sync(other) => AsyncWithSync(other.merge(registry)),
                Async(other) => Async(registry.merge(other)),
                AsyncWithSync(other) => AsyncWithSync(other.merge(registry)),
            }
        }
    }

    impl Merge<RegistryWithSync> for RegistryKind {
        type Output = Self;

        #[inline]
        fn merge(self, registry: RegistryWithSync) -> Self::Output {
            match self {
                Sync(other) => AsyncWithSync(registry.merge(other)),
                Async(other) => AsyncWithSync(registry.merge(other)),
                AsyncWithSync(other) => AsyncWithSync(registry.merge(other)),
            }
        }
    }

    impl Merge<RegistryKindOrEntry> for RegistryWithSync {
        type Output = Self;

        #[inline]
        fn merge(self, registry_kind_or_entry: RegistryKindOrEntry) -> Self::Output {
            match registry_kind_or_entry {
                Kind(Sync(registry)) => self.merge(registry),
                Kind(Async(registry)) => self.merge(registry),
                Kind(AsyncWithSync(registry)) => self.merge(registry),
                Entry(entry) => self.merge(entry),
            }
        }
    }

    impl Merge<RegistryKindOrEntry> for async_impl::Registry {
        type Output = RegistryWithSync;

        #[inline]
        fn merge(self, registry_kind_or_entry: RegistryKindOrEntry) -> Self::Output {
            match registry_kind_or_entry {
                Kind(Sync(registry)) => self.merge(registry),
                Kind(Async(registry)) => self.merge(registry).into(),
                Kind(AsyncWithSync(registry)) => registry.merge(self),
                Entry(entry) => self.merge(entry).into(),
            }
        }
    }

    impl Merge<RegistryKindOrEntry> for RegistryKind {
        type Output = Self;

        #[inline]
        fn merge(self, registry_kind_or_entry: RegistryKindOrEntry) -> Self::Output {
            match (self, registry_kind_or_entry) {
                (Sync(registry), Kind(Sync(other))) => Sync(registry.merge(other)),
                (Async(registry), Kind(Async(other))) => Async(registry.merge(other)),
                (AsyncWithSync(registry), Kind(AsyncWithSync(other))) => AsyncWithSync(registry.merge(other)),
                (Sync(registry), Entry(entry)) => AsyncWithSync(registry.merge(entry)),
                (Async(registry), Entry(entry)) => Async(registry.merge(entry)),
                (AsyncWithSync(registry), Entry(entry)) => AsyncWithSync(registry.merge(entry)),
                (Sync(registry), Kind(AsyncWithSync(other))) => AsyncWithSync(other.merge(registry)),
                (Async(registry), Kind(Sync(other))) => AsyncWithSync(other.merge(registry)),
                (AsyncWithSync(registry), Kind(Sync(other))) => AsyncWithSync(registry.merge(other)),
                (Sync(registry), Kind(Async(other))) => AsyncWithSync(registry.merge(other)),
                (Async(registry), Kind(AsyncWithSync(other))) => AsyncWithSync(other.merge(registry)),
                (AsyncWithSync(registry), Kind(Async(other))) => AsyncWithSync(registry.merge(other)),
            }
        }
    }

    impl<H> Merge<H> for RegistryWithSync
    where
        H: hlist::IntoIterator<RegistryKindOrEntry>,
    {
        type Output = Self;

        fn merge(self, other: H) -> Self::Output {
            other.into_iter().fold(self, Merge::merge)
        }
    }
}