diff --git a/.swiftlint.yml b/.swiftlint.yml index 62e07e7..12cefdc 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,3 +1,5 @@ excluded: - DIDemoApp - Package.swift + +line_length: 140 \ No newline at end of file diff --git a/Sources/SwinjectLight/Container.swift b/Sources/SwinjectLight/Container.swift index 3ad7eff..2a595a9 100644 --- a/Sources/SwinjectLight/Container.swift +++ b/Sources/SwinjectLight/Container.swift @@ -1,10 +1,13 @@ import Foundation +#if canImport(Darwin) +@MainActor +#endif public protocol Resolver: AnyObject { func resolve(_ type: Service.Type) -> Service } -public final class Container: @unchecked Sendable { +public final class Container { private var storage: [String: Any] = [:] public init() { } @@ -13,8 +16,19 @@ public final class Container: @unchecked Sendable { let key = "\(type)" storage[key] = factory } + + public func register(_ type: Service.Type, + parametersType: Parameters.Type, + factory: @escaping (Resolver, Parameters) -> Service) { + let key = "\(type)" + storage[key] = factory + } } +#if !canImport(Darwin) +extension Container: @unchecked Sendable { } +#endif + extension Container: Resolver { public func resolve(_ type: Service.Type) -> Service { let key = "\(type)" @@ -27,4 +41,16 @@ extension Container: Resolver { let service = typedFactory?(self) return service! } + + public func resolve(_ type: Service.Type, parameters: Parameters) -> Service { + let key = "\(type)" + guard let factory = storage[key] else { + fatalError("Dependency \(key) has not been registered") + } + guard let typedFactory = factory as? (((Resolver, Parameters) -> Service)?) else { + fatalError("Dependency \(key) did not provide factory closure") + } + let service = typedFactory?(self, parameters) + return service! + } } diff --git a/Tests/SwinjectLightTests/SwinjectLightTests.swift b/Tests/SwinjectLightTests/SwinjectLightTests.swift index 6a0e9f4..25fd0c6 100644 --- a/Tests/SwinjectLightTests/SwinjectLightTests.swift +++ b/Tests/SwinjectLightTests/SwinjectLightTests.swift @@ -2,8 +2,25 @@ import XCTest @testable import SwinjectLight private protocol MockDependency: AnyObject { } +private protocol MockParametersDependency: AnyObject { } private class MockClass: MockDependency { } +private class MockClassWithParameters: MockParametersDependency { + struct Parameters: Equatable { + let foo: String + } + + let parameters: Parameters + let dependency: MockDependency + + init(dependency: MockDependency, parameters: Parameters) { + self.dependency = dependency + self.parameters = parameters + } +} +#if canImport(Darwin) +@MainActor +#endif final class SwinjectLightTests: XCTestCase { func testRegisterAndResolve() { let container = Container() @@ -26,4 +43,18 @@ final class SwinjectLightTests: XCTestCase { XCTAssertTrue(resolvedDependency is MockClass) XCTAssertTrue(localVariable === resolvedDependency) } + + func testRegisterAndResolveWithParameters() { + let container = Container() + let parameters = MockClassWithParameters.Parameters(foo: "foo") + container.register(MockDependency.self) { _ in MockClass() } + container.register(MockParametersDependency.self, parametersType: MockClassWithParameters.Parameters.self) { resolver, parameters in + MockClassWithParameters(dependency: resolver.resolve(MockDependency.self), parameters: parameters) + } + + let resolvedDependency = container.resolve(MockParametersDependency.self, parameters: parameters) + XCTAssertTrue(resolvedDependency is MockClassWithParameters) + XCTAssertTrue((resolvedDependency as? MockClassWithParameters)?.dependency is MockDependency) + XCTAssertEqual((resolvedDependency as? MockClassWithParameters)?.parameters, parameters) + } }