Skip to content

Commit

Permalink
Merge pull request #201 from cashapp/bradfol/autoregistercollection-m…
Browse files Browse the repository at this point in the history
…ainactor

Reimplement `autoregisterIntoCollection()` methods with `@MainActor`
  • Loading branch information
bradfol authored Sep 25, 2024
2 parents bcf65b7 + e9c60f1 commit 4bc513c
Show file tree
Hide file tree
Showing 5 changed files with 882 additions and 8 deletions.
7 changes: 1 addition & 6 deletions Example/KnitExample/KnitExampleAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
158 changes: 158 additions & 0 deletions Sources/Knit/ServiceCollection/Container+ServiceCollection.erb
Original file line number Diff line number Diff line change
@@ -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: Service.Type,
factory: @escaping @MainActor (Resolver) -> Service
) -> ServiceEntry<Service> {
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: Service.Type,
initializer: @escaping @MainActor (()) -> Service
) -> ServiceEntry<Service> {
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, T1>(
_ service: Service.Type,
initializer: @escaping @MainActor ((T1)) -> Service
) -> ServiceEntry<Service> {
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, <%= types %>>(
_ service: Service.Type,
initializer: @escaping @MainActor ((<%= types %>)) -> Service
) -> ServiceEntry<Service> {
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)"
}

}
Loading

0 comments on commit 4bc513c

Please sign in to comment.