Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Sources/SCInject/Assembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,21 @@

import Foundation

/// A class responsible for assembling dependencies and providing a `Resolver` to resolve them.
///
/// The `Assembler` class serves as a coordinator for assembling an array of `Assembly` instances, which configure and
/// register dependencies within a `Container`.
/// Once the dependencies are assembled, the `Assembler` can return a `Resolver` for resolving the dependencies.
public final class Assembler {
private let container: Container

/// Initializes a new Assembler with the provided Container.
public init(container: Container) {
self.container = container
}

/// Assembles the provided list of Assembly instances, each of which is responsible for registering its dependencies
/// within the container.
@discardableResult
public func assemble(_ assemblies: [Assembly]) -> Assembler {
for assembly in assemblies {
Expand All @@ -31,6 +39,7 @@ public final class Assembler {
return self
}

/// Provides the `Resolver` associated with the `Container` that was assembled.
public func resolver() -> Resolver {
container
}
Expand Down
9 changes: 9 additions & 0 deletions Sources/SCInject/Assembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@

import Foundation

/// A protocol that defines a blueprint for assembling dependencies into a registry.
///
/// Types conforming to the `Assembly` protocol are responsible for registering dependencies within a `Registry`
/// instance.
/// These dependencies can later be resolved by a `Resolver` provided by an `Assembler`.
///
/// This protocol is typically used in conjunction with the `Assembler` class, which coordinates the assembly process
/// across multiple `Assembly` instances.
public protocol Assembly {
/// Assembles and registers dependencies into the provided `Registry`.
func assemble(_ registry: Registry)
}
9 changes: 9 additions & 0 deletions Sources/SCInject/Container.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,17 @@

import Foundation

/// A protocol that combines `Registry` and `Resolver` functionality, representing a container that can both register
/// and resolve dependencies.
public protocol Container: Registry, Resolver {}

/// A final class that implements the `Container` protocol, providing a dependency injection container with support for
/// registering and resolving dependencies.
/// The `DefaultContainer` class allows for hierarchical dependency injection with support for different scopes
/// (`transient` and `container`).
/// Dependencies can be registered with or without names, and resolved accordingly. If a dependency is not found in the
/// current container, it will attempt to resolve it from a parent container if one exists.
/// This class is thread-safe.
public final class DefaultContainer: Container {
private let parent: DefaultContainer?
private let lock = NSRecursiveLock()
Expand Down
1 change: 1 addition & 0 deletions Sources/SCInject/RegisterName.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import Foundation

/// A structure that represents a name used for registering and resolving dependencies in a container.
public struct RegisterName: RawRepresentable, CustomStringConvertible, Hashable {
public let rawValue: String

Expand Down
34 changes: 34 additions & 0 deletions Sources/SCInject/Registry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,47 @@

import Foundation

/// A protocol that defines an interface for registering dependencies within a container.
/// The `Registry` protocol allows the registration of dependencies with different scopes and names.
/// Implementations of this protocol are responsible for storing the provided closures that create instances of the
/// registered types.
/// These registered dependencies can later be resolved by a `Resolver`.
/// This protocol is typically implemented by dependency injection containers, such as `DefaultContainer`.
public protocol Registry {
/// Registers a dependency with a transient scope.
/// - Parameter type: The type of the dependency to register.
/// - Parameter closure: A closure that provides the instance of the dependency.
func register<T>(_ type: T.Type, closure: @escaping (Resolver) -> T)

/// Registers a dependency with a specified scope.
/// - Parameter type: The type of the dependency to register.
/// - Parameter scope: The scope in which the dependency should be resolved.
/// - Parameter closure: A closure that provides the instance of the dependency.
func register<T>(_ type: T.Type, _ scope: Scope, closure: @escaping (Resolver) -> T)

/// Registers a named dependency with a transient scope.
/// - Parameter type: The type of the dependency to register.
/// - Parameter name: The name associated with the dependency.
/// - Parameter closure: A closure that provides the instance of the dependency.
func register<T>(_ type: T.Type, name: String, closure: @escaping (Resolver) -> T)

/// Registers a named dependency with a specified scope.
/// - Parameter type: The type of the dependency to register.
/// - Parameter name: The name associated with the dependency.
/// - Parameter scope: The scope in which the dependency should be resolved.
/// - Parameter closure: A closure that provides the instance of the dependency.
func register<T>(_ type: T.Type, name: String, _ scope: Scope, closure: @escaping (Resolver) -> T)

/// Registers a named dependency with a transient scope.
/// - Parameter type: The type of the dependency to register.
/// - Parameter name: The name associated with the dependency.
/// - Parameter closure: A closure that provides the instance of the dependency.
func register<T>(_ type: T.Type, name: RegisterName, closure: @escaping (Resolver) -> T)

/// Registers a named dependency with a specified scope.
/// - Parameter type: The type of the dependency to register.
/// - Parameter name: The name associated with the dependency.
/// - Parameter scope: The scope in which the dependency should be resolved.
/// - Parameter closure: A closure that provides the instance of the dependency.
func register<T>(_ type: T.Type, name: RegisterName, _ scope: Scope, closure: @escaping (Resolver) -> T)
}
21 changes: 21 additions & 0 deletions Sources/SCInject/Resolver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,29 @@

import Foundation

/// A protocol that defines an interface for resolving dependencies from a container.
/// The `Resolver` protocol allows the retrieval of dependencies that have been previously registered in a container.
/// Dependencies can be resolved by their type, and optionally by a name, if they were registered with one.
/// Implementations of this protocol are typically provided by dependency injection containers, such as
/// `DefaultContainer`.
public protocol Resolver: AnyObject {
/// Resolves a dependency by its type.
/// - Parameter type: The type of the dependency to resolve.
/// - Returns: An instance of the resolved dependency.
/// - Note: The application will crash if the dependency cannot be resolved.
func resolve<T>(_ type: T.Type) -> T

/// Resolves a named dependency by its type.
/// - Parameter type: The type of the dependency to resolve.
/// - Parameter name: The name associated with the dependency.
/// - Returns: An instance of the resolved dependency.
/// - Note: The application will crash if the dependency cannot be resolved.
func resolve<T>(_ type: T.Type, name: String) -> T

/// Resolves a named dependency by its type.
/// - Parameter type: The type of the dependency to resolve.
/// - Parameter name: The `RegisterName` associated with the dependency.
/// - Returns: An instance of the resolved dependency.
/// - Note: The application will crash if the dependency cannot be resolved.
func resolve<T>(_ type: T.Type, name: RegisterName) -> T
}
10 changes: 10 additions & 0 deletions Sources/SCInject/Scope.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,17 @@
// limitations under the License.
//

/// An enumeration that defines the scope of a dependency within a container.
/// The `Scope` enum specifies how instances of dependencies are managed within a dependency injection container.
/// It determines whether a new instance is created each time the dependency is resolved, or whether a single instance
/// is reused throughout the container's lifetime.
///
/// - `transient`: A new instance of the dependency is created every time it is resolved.
/// - `container`: A single instance of the dependency is created and reused throughout the container's lifetime.
public enum Scope {
/// A new instance of the dependency is created every time it is resolved.
case transient

/// A single instance of the dependency is created and reused throughout the container's lifetime.
case container
}