You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
3.8 KiB

2 years ago
  1. //
  2. // Copyright © 2019 Swinject Contributors. All rights reserved.
  3. //
  4. /// Storage provided by `ObjectScope`. It is used by `Container` to persist resolved instances.
  5. public protocol InstanceStorage: AnyObject {
  6. var instance: Any? { get set }
  7. func graphResolutionCompleted()
  8. func instance(inGraph graph: GraphIdentifier) -> Any?
  9. func setInstance(_ instance: Any?, inGraph graph: GraphIdentifier)
  10. }
  11. extension InstanceStorage {
  12. public func graphResolutionCompleted() {}
  13. public func instance(inGraph _: GraphIdentifier) -> Any? { return instance }
  14. public func setInstance(_ instance: Any?, inGraph _: GraphIdentifier) { self.instance = instance }
  15. }
  16. /// Persists storage during the resolution of the object graph
  17. public final class GraphStorage: InstanceStorage {
  18. private var instances = [GraphIdentifier: Weak<Any>]()
  19. public var instance: Any?
  20. public init() {}
  21. public func graphResolutionCompleted() {
  22. instance = nil
  23. }
  24. public func instance(inGraph graph: GraphIdentifier) -> Any? {
  25. return instances[graph]?.value
  26. }
  27. public func setInstance(_ instance: Any?, inGraph graph: GraphIdentifier) {
  28. self.instance = instance
  29. if instances[graph] == nil { instances[graph] = Weak() }
  30. instances[graph]?.value = instance
  31. }
  32. }
  33. /// Persists stored instance until it is explicitly discarded.
  34. public final class PermanentStorage: InstanceStorage {
  35. public var instance: Any?
  36. public init() {}
  37. }
  38. /// Does not persist stored instance.
  39. public final class TransientStorage: InstanceStorage {
  40. public var instance: Any? {
  41. get { return nil }
  42. set {} // swiftlint:disable:this unused_setter_value
  43. }
  44. public init() {}
  45. }
  46. /// Does not persist value types.
  47. /// Persists reference types as long as there are strong references to given instance.
  48. public final class WeakStorage: InstanceStorage {
  49. private var _instance = Weak<Any>()
  50. public var instance: Any? {
  51. get { return _instance.value }
  52. set { _instance.value = newValue }
  53. }
  54. public init() {}
  55. }
  56. /// Combines the behavior of multiple instance storages.
  57. /// Instance is persisted as long as at least one of the underlying storages is persisting it.
  58. public final class CompositeStorage: InstanceStorage {
  59. private let components: [InstanceStorage]
  60. public var instance: Any? {
  61. get {
  62. #if swift(>=4.1)
  63. return components.compactMap { $0.instance }.first
  64. #else
  65. return components.flatMap { $0.instance }.first
  66. #endif
  67. }
  68. set { components.forEach { $0.instance = newValue } }
  69. }
  70. public init(_ components: [InstanceStorage]) {
  71. self.components = components
  72. }
  73. public func graphResolutionCompleted() {
  74. components.forEach { $0.graphResolutionCompleted() }
  75. }
  76. public func setInstance(_ instance: Any?, inGraph graph: GraphIdentifier) {
  77. components.forEach { $0.setInstance(instance, inGraph: graph) }
  78. }
  79. public func instance(inGraph graph: GraphIdentifier) -> Any? {
  80. #if swift(>=4.1)
  81. return components.compactMap { $0.instance(inGraph: graph) }.first
  82. #else
  83. return components.flatMap { $0.instance(inGraph: graph) }.first
  84. #endif
  85. }
  86. }
  87. private class Weak<Wrapped> {
  88. private weak var object: AnyObject?
  89. #if os(Linux)
  90. var value: Wrapped? {
  91. get {
  92. guard let object = object else { return nil }
  93. return object as? Wrapped
  94. }
  95. set { object = newValue.flatMap { $0 as? AnyObject } }
  96. }
  97. #else
  98. var value: Wrapped? {
  99. get {
  100. guard let object = object else { return nil }
  101. return object as? Wrapped
  102. }
  103. set { object = newValue as AnyObject? }
  104. }
  105. #endif
  106. }