Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Property wrappers for dependency container #39

Open
stefanomondino opened this issue Dec 29, 2021 · 0 comments
Open

Property wrappers for dependency container #39

stefanomondino opened this issue Dec 29, 2021 · 0 comments

Comments

@stefanomondino
Copy link
Collaborator

It would be nice (?) to create a @propertyWrapper around dependencies when using a dependency container.

Something like:

class Something: Boomerang.DependencyContainer {
let container = ObjectContainer()

@Dependency(closure: { MyThingImplementation() }
var myThing: MyThing

init() {
}

}

As of today the main issues are:

  1. there is no official way to access the "enclosing" object from withing a property wrapper. Some workaround is possible with undocumented api (see below)
  2. when actually using the propertyWrapper (@Dependency in my example above), you cannot reference self, as it's not yet available. Therefore, all closures used for registration cannot use variables that may have been stored in self, and self should be passed to the closure itself
  3. To pass self to the closure, we should define the enclosing type upon PW creation itself, which sounds awful and superfluous.

A possible implementation (for future reference) is:

@propertyWrapper struct Dependency<Value, Container: Boomerang.DependencyContainer> where Container.DependencyKey == ObjectIdentifier {
    private let closure: (Container) -> Value
    private let scope: Boomerang.Container<ObjectIdentifier>.Scope
    init(_ containerType: Container.Type = Container.self,
         scope: Boomerang.Container<ObjectIdentifier>.Scope = .singleton,
         closure: @escaping (Container) -> Value) {
        self.scope = scope
        self.closure = closure
    }
    
    @available(*, unavailable,
       message: "This property wrapper can only be applied to classes"
   )
    public var wrappedValue: Value {
            get { fatalError() }
            // swiftlint:disable unused_setter_value
            set { fatalError() }
        }
        
    public static subscript(
            _enclosingInstance instance: Container,
            wrapped wrappedKeyPath: ReferenceWritableKeyPath<Container, Value>,
            storage storageKeyPath: ReferenceWritableKeyPath<Container, Self>
        ) -> Value {
                get { 
                   guard let value = instance.resolve(Value.self) else {
                    instance.register(for: Value.self,
                                         scope: instance[keyPath: storageKeyPath].scope,
                                         handler: { instance[keyPath: storageKeyPath].closure(instance) })
                    return instance.unsafeResolve()
                }
                return value
             }
              set {}
        }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant