Skip to content

Instantly share code, notes, and snippets.

@sssbohdan
Last active August 5, 2022 13:41
Show Gist options
  • Save sssbohdan/d817e268a2015280b7b5f3b9e02933e5 to your computer and use it in GitHub Desktop.
Save sssbohdan/d817e268a2015280b7b5f3b9e02933e5 to your computer and use it in GitHub Desktop.
Resolver
//
// DI.swift
// MobiusNotes
//
// Created by bsavych on 05/08/2022.
//
import Foundation
enum DIScope {
case singleton
case new
}
protocol DIRegistration {
func register<Element>(object: @escaping (DIResolver) -> Element, in scope: DIScope)
func register<Element, Param1>(object: @escaping (DIResolver, Param1) -> Element, in scope: DIScope)
func register<Element, Param1, Param2>(object: @escaping (DIResolver, Param1, Param2) -> Element, in scope: DIScope)
func register<Element, Param1, Param2, Param3>(object: @escaping (DIResolver, Param1, Param2, Param3) -> Element, in scope: DIScope)
}
protocol DIResolver {
func resolve<Element>(type: Element.Type) -> Element
func resolve<Element, Param1>(type: Element.Type, param: Param1) -> Element
func resolve<Element, Param1, Param2>(type: Element.Type, params: (Param1, Param2)) -> Element
func resolve<Element, Param1, Param2, Param3>(type: Element.Type, params: (Param1, Param2, Param3)) -> Element
}
typealias DIProtocol = DIRegistration & DIResolver
final class DI: DIProtocol {
private lazy var singletons = [String: Any]()
private lazy var functions = [String: Any]()
private lazy var scopes = [String: DIScope]()
// MARK: - Register
func register<Element>(object: @escaping (DIResolver) -> Element, in scope: DIScope) {
let string = String(reflecting: Element.self)
self.register(object, id: string, scope: scope)
}
func register<Element, Param1>(object: @escaping (DIResolver, Param1) -> Element, in scope: DIScope) {
let string = String(reflecting: Element.self)
self.register(object, id: string, scope: scope)
}
func register<Element, Param1, Param2>(object: @escaping (DIResolver, Param1, Param2) -> Element, in scope: DIScope) {
let string = String(reflecting: Element.self)
self.register(object, id: string, scope: scope)
}
func register<Element, Param1, Param2, Param3>(object: @escaping (DIResolver, Param1, Param2, Param3) -> Element, in scope: DIScope) {
let string = String(reflecting: Element.self)
self.register(object, id: string, scope: scope)
}
private func register(_ obj: Any, id: String, scope: DIScope) {
self.scopes[id] = scope
self.functions[id] = obj
}
// MARK: - Resolve
func resolve<Element>(type: Element.Type) -> Element {
let string = String(reflecting: Element.self)
guard let scope = self.scopes[string] else {
fatalError("The object of type \(string) is not registered")
}
switch scope {
case .new:
let f = self.functions[string] as! (DIResolver) -> Element
return f(self)
case .singleton:
if let obj = singletons[string] as? Element {
return obj
} else {
let f = self.functions[string] as! (DIResolver) -> Element
let obj = f(self)
singletons[string] = obj
return obj
}
}
}
func resolve<Element, Param1>(type: Element.Type, param: Param1) -> Element {
let string = String(reflecting: Element.self)
guard let scope = self.scopes[string] else {
fatalError("The object of type \(string) is not registered")
}
switch scope {
case .new:
let f = self.functions[string] as! (DIResolver, Param1) -> Element
return f(self, param)
case .singleton:
if let obj = singletons[string] as? Element {
return obj
} else {
let f = self.functions[string] as! (DIResolver, Param1) -> Element
let obj = f(self, param)
singletons[string] = obj
return obj
}
}
}
func resolve<Element, Param1, Param2>(type: Element.Type, params: (Param1, Param2)) -> Element {
let string = String(reflecting: Element.self)
guard let scope = self.scopes[string] else {
fatalError("The object of type \(string) is not registered")
}
switch scope {
case .new:
let f = self.functions[string] as! (DIResolver, Param1, Param2) -> Element
return f(self, params.0, params.1)
case .singleton:
if let obj = singletons[string] as? Element {
return obj
} else {
let f = self.functions[string] as! (DIResolver, Param1, Param2) -> Element
let obj = f(self, params.0, params.1)
singletons[string] = obj
return obj
}
}
}
func resolve<Element, Param1, Param2, Param3>(type: Element.Type, params: (Param1, Param2, Param3)) -> Element {
let string = String(reflecting: Element.self)
guard let scope = self.scopes[string] else {
fatalError("The object of type \(string) is not registered")
}
switch scope {
case .new:
let f = self.functions[string] as! (DIResolver, Param1, Param2, Param3) -> Element
return f(self, params.0, params.1, params.2)
case .singleton:
if let obj = singletons[string] as? Element {
return obj
} else {
let f = self.functions[string] as! (DIResolver, Param1, Param2, Param3) -> Element
let obj = f(self, params.0, params.1, params.2)
singletons[string] = obj
return obj
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment