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

Use of Annotations with Factories #124

Open
Gavvers opened this issue Aug 16, 2020 · 3 comments
Open

Use of Annotations with Factories #124

Gavvers opened this issue Aug 16, 2020 · 3 comments

Comments

@Gavvers
Copy link

Gavvers commented Aug 16, 2020

I have been reading and re-reading the wiki as well as the code comments, but I am still very unclear on how Annotations can be used with factory injection (std::function<std::unique_ptr<T>>), if that it even supported. The comment on bind() in component.h says,

* All these cases support annotated injection, just wrap I and/or C in fruit::Annotated<> if desired. For example:

The example only shows the simple case. How does it work with factories?

@poletti-marco
Copy link
Contributor

Hi, yes, annotated factories are supported, in bind() too.
Some example code:

#include <fruit/fruit.h>
#include <iostream>

using fruit::Component;
using fruit::Injector;

struct X {
    virtual void f() = 0;
    virtual ~X() = default;
};

struct Y {
    INJECT(Y()) = default;
};

struct XImpl : public X {
    Y* y;
    int n;
    INJECT(XImpl(Y* y, ASSISTED(int) n)) : y(y), n(n) {}
    void f() override {}
    virtual ~XImpl() = default;
};

using XFactory = std::function<std::unique_ptr<X>(int)>;

Component<XFactory> getXFactoryComponent1() {
    return fruit::createComponent()
        // std::function<std::unique_ptr<X>(int)> from std::function<std::unique_ptr<XImpl>(int)>
        // std::function<std::unique_ptr<XImpl>(int)> using XImpl's constructor
        .bind<X, XImpl>();
}

// Equivalent to getXFactoryComponent1
Component<XFactory> getXFactoryComponent2() {
    return fruit::createComponent()
        .registerProvider([](std::function<std::unique_ptr<XImpl>(int)>* implFactory) {
            return XFactory([=](int n) {
                XImpl* p = (*implFactory)(n).release();
                return std::unique_ptr<X>(p);
            });
        });
}

struct MyAnnotation {};

Component<fruit::Annotated<MyAnnotation, XFactory>> getXFactoryComponent3() {
    return fruit::createComponent()
        // fruit::Annotated<MyAnnotation, std::function<std::unique_ptr<X>(int)>> from std::function<std::unique_ptr<XImpl>(int)>
        // std::function<std::unique_ptr<XImpl>(int)> using XImpl's constructor
        .bind<fruit::Annotated<MyAnnotation, X>, XImpl>();
}

// Equivalent to getXFactoryComponent3
Component<fruit::Annotated<MyAnnotation, XFactory>> getXFactoryComponent4() {
    return fruit::createComponent()
        .registerProvider<fruit::Annotated<MyAnnotation, XFactory>(std::function<std::unique_ptr<XImpl>(int)>*)>([](std::function<std::unique_ptr<XImpl>(int)>* implFactory) {
            return XFactory([=](int n) {
                XImpl* p = (*implFactory)(n).release();
                return std::unique_ptr<X>(p);
            });
        });
}

int main() {
    {
        Injector<XFactory> injector(getXFactoryComponent1);
        XFactory factory = injector.get<XFactory>();
        std::unique_ptr<X> x = factory(42);
        (void) x;
    }
    {
        Injector<XFactory> injector(getXFactoryComponent2);
        XFactory factory = injector.get<XFactory>();
        std::unique_ptr<X> x = factory(42);
        (void) x;
    }
    {
        Injector<fruit::Annotated<MyAnnotation, XFactory>> injector(getXFactoryComponent3);
        XFactory factory = injector.get<fruit::Annotated<MyAnnotation, XFactory>>();
        std::unique_ptr<X> x = factory(42);
        (void) x;
    }
    {
        Injector<fruit::Annotated<MyAnnotation, XFactory>> injector(getXFactoryComponent4);
        XFactory factory = injector.get<fruit::Annotated<MyAnnotation, XFactory>>();
        std::unique_ptr<X> x = factory(42);
        (void) x;
    }
}

I hope that it clarifies things.
If not, please let me know what's your use case and we can discuss that specifically.

@Gavvers
Copy link
Author

Gavvers commented Aug 18, 2020

It helps, thanks.

The implFactory in components 3 and 4 is created by fruit?

@poletti-marco
Copy link
Contributor

poletti-marco commented Aug 19, 2020

Hi, yes, from the INJECT/ASSISTED markers on the constructor.
Alternatively, (e.g. if you don't own that code or if for some other reason you don't want to modify it) you could use registerFactory() to bind the impl factory.
https://github.com/google/fruit/wiki/quick-reference#factories-and-assisted-injection

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants