diff --git a/Sources/InfomaniakDI/DependencyInjectionService.swift b/Sources/InfomaniakDI/DependencyInjectionService.swift index b4bbf0e..dbe4ef9 100644 --- a/Sources/InfomaniakDI/DependencyInjectionService.swift +++ b/Sources/InfomaniakDI/DependencyInjectionService.swift @@ -18,16 +18,8 @@ import Foundation /// Allows to add and remove dynamically containers. /// Also provides a standard, shared, singleton style, container. public final class DependencyInjectionService { - /// Shared container of all singletons of an executable - var _sharedContainer: Container - - public var sharedContainer: Container { - _sharedContainer - } - - public init(sharedContainer: Container = Container()) { - self._sharedContainer = sharedContainer - } - + public static let sharedContainer = Container() + + public init() {} } diff --git a/Sources/InfomaniakDI/Inject.swift b/Sources/InfomaniakDI/PropertyWrappers/Inject.swift similarity index 100% rename from Sources/InfomaniakDI/Inject.swift rename to Sources/InfomaniakDI/PropertyWrappers/Inject.swift diff --git a/Sources/InfomaniakDI/PropertyWrappers/InjectService.swift b/Sources/InfomaniakDI/PropertyWrappers/InjectService.swift new file mode 100644 index 0000000..62bdec4 --- /dev/null +++ b/Sources/InfomaniakDI/PropertyWrappers/InjectService.swift @@ -0,0 +1,77 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import Foundation + +/// A property wrapper that resolves shared types when the host type is initialized. +@propertyWrapper public struct InjectService: CustomDebugStringConvertible, Equatable, Identifiable { + /// Identifiable + /// + /// Something to link the identity of this property wrapper to the underlying Service type. + public let id = ObjectIdentifier(Injected.self) + + /// Equatable + /// + /// Two `InjectService` that points to the same `Injected` Metatype are expected to be equal (for the sake of SwiftUI + /// correctness) + public static func == (lhs: InjectService, rhs: InjectService) -> Bool { + return lhs.id == rhs.id + } + + public var debugDescription: String { + """ + <\(type(of: self)) + wrapping type:'\(Injected.self)' + customTypeIdentifier:\(String(describing: customTypeIdentifier)) + factoryParameters:\(String(describing: factoryParameters)) + id:\(id)'> + """ + } + + /// Store the resolved service + var service: Injected! + + public var container: Resolvable + public var customTypeIdentifier: String? + public var factoryParameters: [String: Any]? + + public init(customTypeIdentifier: String? = nil, + factoryParameters: [String: Any]? = nil) { + self.customTypeIdentifier = customTypeIdentifier + self.factoryParameters = factoryParameters + container = DependencyInjectionService.sharedContainer + + do { + service = try container.resolve(type: Injected.self, + forCustomTypeIdentifier: customTypeIdentifier, + factoryParameters: factoryParameters, + resolver: container) + } catch { + fatalError("DI fatal error :\(error)") + } + } + + public var wrappedValue: Injected { + get { + service + } + set { + fatalError("You are not expected to substitute resolved objects") + } + } + + /// The property wrapper itself for debugging and testing + public var projectedValue: Self { + self + } +} diff --git a/Sources/InfomaniakDI/LazyInject.swift b/Sources/InfomaniakDI/PropertyWrappers/LazyInject.swift similarity index 87% rename from Sources/InfomaniakDI/LazyInject.swift rename to Sources/InfomaniakDI/PropertyWrappers/LazyInject.swift index e9b5200..7c5a9e7 100644 --- a/Sources/InfomaniakDI/LazyInject.swift +++ b/Sources/InfomaniakDI/PropertyWrappers/LazyInject.swift @@ -14,7 +14,7 @@ import Foundation /// Inject a type at the first use of the property -@propertyWrapper public final class LazyInject: Equatable, Identifiable { +@propertyWrapper public class LazyInject: Equatable, Identifiable { /// Identifiable /// /// Something to link the identity of this property wrapper to the underlying Service type. @@ -61,9 +61,9 @@ import Foundation do { resolvedInstance = try container.resolve(type: Injected.self, - forCustomTypeIdentifier: customTypeIdentifier, - factoryParameters: factoryParameters, - resolver: container) + forCustomTypeIdentifier: customTypeIdentifier, + factoryParameters: factoryParameters, + resolver: container) return resolvedInstance! } catch { fatalError("DI fatal error :\(error)") diff --git a/Sources/InfomaniakDI/PropertyWrappers/LazyInjectService.swift b/Sources/InfomaniakDI/PropertyWrappers/LazyInjectService.swift new file mode 100644 index 0000000..ea07aff --- /dev/null +++ b/Sources/InfomaniakDI/PropertyWrappers/LazyInjectService.swift @@ -0,0 +1,79 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import Foundation + +@propertyWrapper public class LazyInjectService: Equatable, Identifiable { + /// Identifiable + /// + /// Something to link the identity of this property wrapper to the underlying Service type. + public let id = ObjectIdentifier(Injected.self) + + /// Equatable + /// + /// Two `LazyInjectService` that points to the same `Service` Metatype are expected to be equal (for the sake of SwiftUI + /// correctness) + public static func == (lhs: LazyInjectService, rhs: LazyInjectService) -> Bool { + return lhs.id == rhs.id + } + + public var debugDescription: String { + """ + <\(type(of: self)) + wrapping type:'\(Injected.self)' + customTypeIdentifier:\(String(describing: customTypeIdentifier)) + factoryParameters:\(String(describing: factoryParameters)) + id:\(id)'> + """ + } + + /// Store the instance of the resolved type + var resolvedInstance: Injected? + + public var container: Resolvable + public var customTypeIdentifier: String? + public var factoryParameters: [String: Any]? + + public init(customTypeIdentifier: String? = nil, + factoryParameters: [String: Any]? = nil) { + self.customTypeIdentifier = customTypeIdentifier + self.factoryParameters = factoryParameters + container = DependencyInjectionService.sharedContainer + } + + public var wrappedValue: Injected { + get { + if let resolvedInstance { + return resolvedInstance + } + + do { + resolvedInstance = try container.resolve(type: Injected.self, + forCustomTypeIdentifier: customTypeIdentifier, + factoryParameters: factoryParameters, + resolver: container) + return resolvedInstance! + } catch { + fatalError("DI fatal error :\(error)") + } + } + set { + fatalError("You are not expected to substitute resolved objects") + } + } + + /// The property wrapper itself for debugging and testing + public var projectedValue: LazyInjectService { + self + } +}