Skip to content

Commit

Permalink
Builder -> LazyInstantiator and LazyForwardingInstantiator
Browse files Browse the repository at this point in the history
  • Loading branch information
dfed committed Dec 1, 2023
1 parent 08c5032 commit 6af069d
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 107 deletions.
46 changes: 46 additions & 0 deletions Sources/SafeDI/LazyForwardingInstantiator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Distributed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

/// A SafeDI dependency designed for the lazy instantiation of an `@Instantiable` type that contains
/// `@Forwarded` properties. This class enables instantiation with specific arguments, facilitating
/// the inheritance of these arguments by `@Instantiable` types that are `@Instantiated` within
/// the `InstantiableType`, as well as by all types `@Instantiated` downstream.
///
/// - SeeAlso: `LazyInstantiator`
/// - Note: This class is the sole means for instantiating an `@Instantiable` type with `@Forwarded`
/// properties within the SafeDI framework.
public final class LazyForwardingInstantiator<ArgumentsToForward, InstantiableType> {
/// Initializes a new lazy forwarding instantiator with the provided instantiation closure.
///
/// - Parameter instantiator: A closure that takes `ArgumentsToForward` and returns an instance of `InstantiableType`.
public init(_ instantiator: @escaping (ArgumentsToForward) -> InstantiableType) {
self.instantiator = instantiator
}

/// Instantiates and returns a new instance of the `@Instantiable` type, using the provided arguments.
///
/// - Parameter arguments: Arguments required for instantiation.
/// - Returns: An `InstantiableType` instance.
public func instantiate(_ arguments: ArgumentsToForward) -> InstantiableType {
instantiator(arguments)
}

private let instantiator: (ArgumentsToForward) -> InstantiableType
}
22 changes: 11 additions & 11 deletions Sources/SafeDI/LazyInstantiated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,34 +21,34 @@
import Foundation

/// Marks a SafeDI dependency that is instantiated on first access.
@propertyWrapper public final class LazyInstantiated<BuiltType> {
@propertyWrapper public final class LazyInstantiated<InstantiableType> {

// MARK: Initialization

public init(synchronization: SynchronizationBehavior = .main, _ builder: Builder<(), BuiltType>) {
self.builder = builder
public init(synchronization: SynchronizationBehavior = .main, _ builder: LazyInstantiator<InstantiableType>) {
self.lazyInstantiator = builder
self.synchronization = synchronization
}

// MARK: Public

public var wrappedValue: BuiltType {
public var wrappedValue: InstantiableType {
synchronization.sync {
if let builtValue = self._unsafeBuiltValue {
return builtValue
if let instantiated = self._unsafeInstantiated {
return instantiated
} else {
let builtValue = self.builder.build()
self._unsafeBuiltValue = builtValue
return builtValue
let instantiated = self.lazyInstantiator.instantiate()
self._unsafeInstantiated = instantiated
return instantiated
}
}
}

// MARK: Private

private let builder: Builder<(), BuiltType>
private let lazyInstantiator: LazyInstantiator<InstantiableType>
private let synchronization: SynchronizationBehavior
private var _unsafeBuiltValue: BuiltType?
private var _unsafeInstantiated: InstantiableType?

// MARK: - SynchronizationBehavior

Expand Down
40 changes: 40 additions & 0 deletions Sources/SafeDI/LazyInstantiator.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Distributed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

/// A SafeDI dependency responsible for the lazy instantiation of an `@Instantiable` type.
/// This class facilitates the delayed creation of an `@Instantiable` instance, making it particularly
/// useful in scenarios where immediate instantiation is not necessary or desirable. `LazyInstantiator`
/// facilitates control over memory usage and enables just-in-time instantiation.
///
/// - SeeAlso: `LazyForwardingInstantiator`
public final class LazyInstantiator<InstantiableType> {
/// - Parameter instantiator: A closure that returns an instance of `InstantiableType`.
public init(_ instantiator: @escaping () -> InstantiableType) {
self.instantiator = instantiator
}

/// Instantiates and returns a new instance of the `@Instantiable` type.
/// - Returns: An `InstantiableType` instance.
public func instantiate() -> InstantiableType {
instantiator()
}

private let instantiator: () -> InstantiableType
}
12 changes: 5 additions & 7 deletions Sources/SafeDICore/Models/Dependency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public struct Dependency: Codable, Hashable {
case .instantiated, .inherited, .singleton, .forwarded:
return property.label
case .lazyInstantiated:
return "\(property.label)\(Self.builderType)"
return "\(property.label)\(Self.lazyInstantiatorType)"
}
}

Expand All @@ -83,14 +83,12 @@ public struct Dependency: Codable, Hashable {
case .lazyInstantiated:
// TODO: fully qualify this type with `SafeDI.` member prefix
return .simple(
name: Self.builderType,
generics: [
.tuple([]),
property.typeDescription
]
name: Self.lazyInstantiatorType,
generics: [property.typeDescription]
)
}
}

static let builderType = "Builder"
static let lazyInstantiatorType = "LazyInstantiator"
static let lazyForwardingInstantiatorType = "LazyForwardingInstantiator"
}
42 changes: 21 additions & 21 deletions Tests/SafeDICoreTests/InitializerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -755,10 +755,10 @@ final class InitializerTests: XCTestCase {
hasGenericWhereClause: false,
arguments: [
.init(
innerLabel: "invariantBuilder",
innerLabel: "invariantLazyInstantiator",
typeDescription: .simple(
name: "Builder",
generics: [.tuple([]), .simple(name: "Invariant")]
name: "LazyInstantiator",
generics: [.simple(name: "Invariant")]
)
),
]
Expand All @@ -769,10 +769,10 @@ final class InitializerTests: XCTestCase {
fulfilling: [
.init(
property: .init(
label: "invariantBuilder",
label: "invariantLazyInstantiator",
typeDescription: .simple(
name: "Builder",
generics: [.tuple([]), .simple(name: "Invariant")]
name: "LazyInstantiator",
generics: [.simple(name: "Invariant")]
)
),
source: .instantiated
Expand All @@ -781,9 +781,9 @@ final class InitializerTests: XCTestCase {
typeIsClass: false,
trailingNewline: true).description,
"""
public init(buildSafeDIDependencies: () -> (Builder<(), Invariant>)) {
public init(buildSafeDIDependencies: () -> (LazyInstantiator<Invariant>)) {
let dependencies = buildSafeDIDependencies()
self.init(invariantBuilder: dependencies)
self.init(invariantLazyInstantiator: dependencies)
}
"""
)
Expand All @@ -798,10 +798,10 @@ final class InitializerTests: XCTestCase {
hasGenericWhereClause: false,
arguments: [
.init(
innerLabel: "invariantBuilder",
innerLabel: "invariantLazyInstantiator",
typeDescription: .simple(
name: "Builder",
generics: [.tuple([]), .simple(name: "Invariant")]
name: "LazyInstantiator",
generics: [.simple(name: "Invariant")]
)
),
]
Expand All @@ -821,9 +821,9 @@ final class InitializerTests: XCTestCase {
typeIsClass: false,
trailingNewline: true).description,
"""
public init(buildSafeDIDependencies: () -> (Builder<(), Invariant>)) {
public init(buildSafeDIDependencies: () -> (LazyInstantiator<Invariant>)) {
let dependencies = buildSafeDIDependencies()
self.init(invariantBuilder: dependencies)
self.init(invariantLazyInstantiator: dependencies)
}
"""
)
Expand All @@ -838,10 +838,10 @@ final class InitializerTests: XCTestCase {
hasGenericWhereClause: false,
arguments: [
.init(
innerLabel: "invariantBuilder",
innerLabel: "invariantLazyInstantiator",
typeDescription: .simple(
name: "Builder",
generics: [.tuple([]), .simple(name: "Invariant")]
name: "LazyInstantiator",
generics: [.simple(name: "Invariant")]
)
),
]
Expand All @@ -852,10 +852,10 @@ final class InitializerTests: XCTestCase {
fulfilling: [
.init(
property: .init(
label: "invariantBuilder",
label: "invariantLazyInstantiator",
typeDescription: .simple(
name: "Builder",
generics: [.tuple([]), .simple(name: "Invariant")]
name: "LazyInstantiator",
generics: [.simple(name: "Invariant")]
)
),
source: .instantiated
Expand All @@ -871,9 +871,9 @@ final class InitializerTests: XCTestCase {
typeIsClass: false,
trailingNewline: true).description,
"""
public init(buildSafeDIDependencies: () -> (Builder<(), Invariant>)) {
public init(buildSafeDIDependencies: () -> (LazyInstantiator<Invariant>)) {
let dependencies = buildSafeDIDependencies()
self.init(invariantBuilder: dependencies)
self.init(invariantLazyInstantiator: dependencies)
}
"""
)
Expand Down
Loading

0 comments on commit 6af069d

Please sign in to comment.