diff --git a/Example/KnitExample/KnitExampleAssembly.swift b/Example/KnitExample/KnitExampleAssembly.swift index 5285b00..a9debe6 100644 --- a/Example/KnitExample/KnitExampleAssembly.swift +++ b/Example/KnitExample/KnitExampleAssembly.swift @@ -43,12 +43,7 @@ final class KnitExampleAssembly: ModuleAssembly { } ) - container.registerIntoCollection( - ExampleService.self, - factory: { _ in - ExampleService() - } - ) + container.autoregisterIntoCollection(ExampleService.self, initializer: ExampleService.init) container.registerIntoCollection( MainActorService.self, diff --git a/Package.swift b/Package.swift index cb49d10..625da83 100644 --- a/Package.swift +++ b/Package.swift @@ -24,7 +24,8 @@ let package = Package( dependencies: [ .product(name: "Swinject", package: "Swinject"), .product(name: "SwinjectAutoregistration", package: "SwinjectAutoregistration"), - ] + ], + exclude: ["ServiceCollection/Container+ServiceCollection.erb"] ), .testTarget( name: "KnitTests", diff --git a/Sources/Knit/ServiceCollection/Container+ServiceCollection.erb b/Sources/Knit/ServiceCollection/Container+ServiceCollection.erb new file mode 100644 index 0000000..3537cb6 --- /dev/null +++ b/Sources/Knit/ServiceCollection/Container+ServiceCollection.erb @@ -0,0 +1,158 @@ +// +// NOTICE: +// +// This file is generated from Container+ServiceCollection.erb by ERB. +// Do NOT modify it directly. +// Instead, modify Container+ServiceCollection.erb and run `Scripts/gencode`. +// +<% type_count = 20 %> + +import Foundation + +extension Container { + + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.registerIntoCollection(Animal.self) { _ in Cat(...) } + /// container.registerIntoCollection(Animal.self) { _ in Dog(...) } + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: The service type to register. + /// - factory: The closure to specify how the service type is resolved with the dependencies of the type. + /// It is invoked when the ``Container`` needs to instantiate the instance. + /// It takes a ``Resolver`` to inject dependencies to the instance, + /// and returns the instance of the component type for the service. + /// - Returns: The registered service entry. + @discardableResult + public func registerIntoCollection( + _ service: Service.Type, + factory: @escaping @MainActor (Resolver) -> Service + ) -> ServiceEntry { + self.register( + service, + name: makeUniqueCollectionRegistrationName(), + factory: { resolver in + MainActor.assumeIsolated { + return factory(resolver) + } + } + ) + } + + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: The service type to register. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor (()) -> Service + ) -> ServiceEntry { + let initClosure = { + MainActor.assumeIsolated { + initializer(()) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1)) -> Service + ) -> ServiceEntry { + let initClosure = { (arg: (T1)) in + MainActor.assumeIsolated { + initializer((arg)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + +<% (2..type_count).each do |i| %> +<% types = (1..i).map { |n| "T#{n}" }.join(", ") %> +<% args = (0..i-1).map { |n| "args.#{n}" }.join(", ") %> + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection>( + _ service: Service.Type, + initializer: @escaping @MainActor ((<%= types %>)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (<%= types %>)) in + MainActor.assumeIsolated { + initializer((<%= args %>)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } +<% end %> + + // MARK: - Private Methods + + private func makeUniqueCollectionRegistrationName() -> String { + "\(collectionRegistrationPrefix)-\(UUID().uuidString)" + } + +} diff --git a/Sources/Knit/ServiceCollection/Container+ServiceCollection.swift b/Sources/Knit/ServiceCollection/Container+ServiceCollection.swift index c1267d1..7a1302f 100644 --- a/Sources/Knit/ServiceCollection/Container+ServiceCollection.swift +++ b/Sources/Knit/ServiceCollection/Container+ServiceCollection.swift @@ -1,5 +1,9 @@ // -// Copyright © Block, Inc. All rights reserved. +// NOTICE: +// +// This file is generated from Container+ServiceCollection.erb by ERB. +// Do NOT modify it directly. +// Instead, modify Container+ServiceCollection.erb and run `Scripts/gencode`. // import Foundation @@ -41,6 +45,681 @@ extension Container { ) } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: The service type to register. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor (()) -> Service + ) -> ServiceEntry { + let initClosure = { + MainActor.assumeIsolated { + initializer(()) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1)) -> Service + ) -> ServiceEntry { + let initClosure = { (arg: (T1)) in + MainActor.assumeIsolated { + initializer((arg)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2)) in + MainActor.assumeIsolated { + initializer((args.0, args.1)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5, T6)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5, T6)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4, args.5)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5, T6, T7)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5, T6, T7)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4, args.5, args.6)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5, T6, T7, T8)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5, T6, T7, T8)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4, args.5, args.6, args.7)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5, T6, T7, T8, T9)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5, T6, T7, T8, T9)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4, args.5, args.6, args.7, args.8)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4, args.5, args.6, args.7, args.8, args.9)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4, args.5, args.6, args.7, args.8, args.9, args.10)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4, args.5, args.6, args.7, args.8, args.9, args.10, args.11)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4, args.5, args.6, args.7, args.8, args.9, args.10, args.11, args.12)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4, args.5, args.6, args.7, args.8, args.9, args.10, args.11, args.12, args.13)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4, args.5, args.6, args.7, args.8, args.9, args.10, args.11, args.12, args.13, args.14)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4, args.5, args.6, args.7, args.8, args.9, args.10, args.11, args.12, args.13, args.14, args.15)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4, args.5, args.6, args.7, args.8, args.9, args.10, args.11, args.12, args.13, args.14, args.15, args.16)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4, args.5, args.6, args.7, args.8, args.9, args.10, args.11, args.12, args.13, args.14, args.15, args.16, args.17)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4, args.5, args.6, args.7, args.8, args.9, args.10, args.11, args.12, args.13, args.14, args.15, args.16, args.17, args.18)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + /// Registers a service factory into a collection. + /// + /// Usage: + /// ``` + /// let container = Container() + /// container.addBehavior(ServiceCollector()) + /// container.autoregisterIntoCollection(Animal.self, initializer: Cat.init) + /// container.autoregisterIntoCollection(Animal.self, initializer: Dog.init) + /// + /// let animals = resolver.resolveCollection(Animal.self) + /// print(animals.entries) // [Cat, Dog] + /// ``` + /// - Parameters: + /// - service: Registered service type. + /// - initializer: Initializer of the registered service. + /// - Returns: The registered service entry. + @discardableResult + public func autoregisterIntoCollection( + _ service: Service.Type, + initializer: @escaping @MainActor ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20)) -> Service + ) -> ServiceEntry { + let initClosure = { (args: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20)) in + MainActor.assumeIsolated { + initializer((args.0, args.1, args.2, args.3, args.4, args.5, args.6, args.7, args.8, args.9, args.10, args.11, args.12, args.13, args.14, args.15, args.16, args.17, args.18, args.19)) + } + } + return self.autoregister( + service, + name: makeUniqueCollectionRegistrationName(), + initializer: initClosure + ) + } + // MARK: - Private Methods private func makeUniqueCollectionRegistrationName() -> String { diff --git a/Tests/KnitTests/ServiceCollectorTests.swift b/Tests/KnitTests/ServiceCollectorTests.swift index 5437400..900bd3e 100644 --- a/Tests/KnitTests/ServiceCollectorTests.swift +++ b/Tests/KnitTests/ServiceCollectorTests.swift @@ -160,6 +160,47 @@ final class ServiceCollectorTests: XCTestCase { ) } + // MARK: - Tests - autoregisterIntoCollection + + @MainActor + func test_autoregisterIntoCollection() { + let container = Container() + container.addBehavior(ServiceCollector()) + + // Register some services into a collection + container.autoregisterIntoCollection(ServiceProtocol.self, initializer: ServiceA.init) + container.autoregisterIntoCollection(ServiceProtocol.self, initializer: ServiceB.init) + + // Resolving the collection should produce the services + let collection = container.resolveCollection(ServiceProtocol.self) + XCTAssertEqual(collection.entries.count, 2) + XCTAssert(collection.entries.first is ServiceA) + XCTAssert(collection.entries.last is ServiceB) + } + + // High-arity overloads are generated by a script. Ensure they work as expected. + @MainActor + func test_autoregisterIntoCollection_highArityOverloads() { + let container = Container() + container.addBehavior(ServiceCollector()) + + // Register dependencies for autoregistration + container.register(String.self) { _ in "string" } + container.register(UInt.self) { _ in 1 } + container.register(Int.self) { _ in 2 } + + // Register a high-arity service into a collection + container.autoregisterIntoCollection(ServiceProtocol.self, initializer: HighArityService.init) + + // Resolving the collection should produce the service + let collection = container.resolveCollection(ServiceProtocol.self) + XCTAssertEqual(collection.entries.count, 1) + XCTAssertEqual( + collection.entries.first as? HighArityService, + HighArityService(string: "string", uint: 1, int: 2) + ) + } + // MARK: - Tests - Object Scopes @MainActor