├── Emaject
├── tests
│ ├── tests.cpp
│ ├── unused.cpp
│ ├── lambda_install.cpp
│ ├── helloworld.cpp
│ ├── from_resolve.cpp
│ ├── with_arg.cpp
│ ├── from_instance.cpp
│ ├── transient.cpp
│ ├── ctor_inject.cpp
│ ├── field_inject.cpp
│ ├── from_factory.cpp
│ ├── inject_taits.cpp
│ ├── method_inject.cpp
│ ├── use_id.cpp
│ ├── single.cpp
│ └── cached.cpp
├── .runsettings
├── Emaject.vcxproj.filters
├── Emaject.vcxproj
└── include
│ └── Emaject.hpp
├── LICENSE
├── Emaject.sln
├── .gitignore
└── README.md
/Emaject/tests/tests.cpp:
--------------------------------------------------------------------------------
1 | #define CATCH_CONFIG_MAIN
2 | #include "catch.hpp"
--------------------------------------------------------------------------------
/Emaject/.runsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | tests
5 | .*
6 |
7 |
--------------------------------------------------------------------------------
/Emaject/tests/unused.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "catch.hpp"
4 |
5 | namespace
6 | {
7 | using emaject::Container;
8 | using emaject::IInstaller;
9 | using emaject::Injector;
10 |
11 | class ICounter
12 | {
13 | public:
14 | virtual ~ICounter() = default;
15 | virtual int countUp() = 0;
16 | };
17 |
18 | struct CounterInstaller : IInstaller
19 | {
20 | void onBinding(Container* c) const
21 | {
22 | // Unused
23 | c->bind()
24 | .unused()
25 | .asTransient();
26 | }
27 | };
28 |
29 | TEST_CASE("unuused")
30 | {
31 | Injector injector;
32 | injector.install();
33 |
34 | {
35 | auto counter = injector.resolve();
36 | REQUIRE(counter == nullptr);
37 | }
38 | {
39 | auto counter = injector.resolve();
40 | REQUIRE(counter == nullptr);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Emaject/tests/lambda_install.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include "catch.hpp"
6 |
7 | namespace
8 | {
9 | using emaject::Container;
10 | using emaject::IInstaller;
11 | using emaject::Injector;
12 |
13 | class IPrinter
14 | {
15 | public:
16 | virtual ~IPrinter() = default;
17 | virtual void println(std::string_view str) const = 0;
18 | };
19 |
20 | class CoutPrinter : public IPrinter
21 | {
22 | public:
23 | void println(std::string_view str) const override
24 | {
25 | std::cout << "[lambda_install]" << str << std::endl;
26 | }
27 | };
28 |
29 | TEST_CASE("lambda_install")
30 | {
31 | Injector injector;
32 | injector.install([](Container* c) {
33 | c->bind()
34 | .to()
35 | .asCached();
36 | });
37 |
38 | auto printer = injector.resolve();
39 | printer->println("Hello World");
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Tyanmahou
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Emaject/tests/helloworld.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include "catch.hpp"
6 |
7 | namespace
8 | {
9 | using emaject::Container;
10 | using emaject::IInstaller;
11 | using emaject::Injector;
12 |
13 | class IPrinter
14 | {
15 | public:
16 | virtual ~IPrinter() = default;
17 | virtual void println(std::string_view str) const = 0;
18 | };
19 |
20 | class CoutPrinter : public IPrinter
21 | {
22 | public:
23 | void println(std::string_view str) const override
24 | {
25 | std::cout << "[hello world]" << str << std::endl;
26 | }
27 | };
28 |
29 | struct CoutInstaller : IInstaller
30 | {
31 | void onBinding(Container* c) const
32 | {
33 | c->bind()
34 | .to()
35 | .asCached();
36 | }
37 | };
38 |
39 | TEST_CASE("hello world")
40 | {
41 | Injector injector;
42 | injector.install();
43 |
44 | auto printer = injector.resolve();
45 | printer->println("Hello World");
46 | }
47 | }
--------------------------------------------------------------------------------
/Emaject/tests/from_resolve.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include "catch.hpp"
5 |
6 | namespace
7 | {
8 | using emaject::Container;
9 | using emaject::IInstaller;
10 | using emaject::Injector;
11 |
12 |
13 | class IFoo
14 | {
15 | public:
16 | virtual ~IFoo() = default;
17 | };
18 | class IFooFoo : public IFoo
19 | {
20 | };
21 | class FooFoo : public IFooFoo
22 | {
23 | };
24 | struct FooInstaller : IInstaller
25 | {
26 | void onBinding(Container* c) const
27 | {
28 | c->bind()
29 | .to()
30 | .asCached();
31 |
32 | c->bind()
33 | .to()
34 | .fromResolve()
35 | .asCached();
36 | }
37 | };
38 | TEST_CASE("from_resolve")
39 | {
40 | Injector injector;
41 | injector.install();
42 |
43 | {
44 | auto foo = injector.resolve();
45 | auto foofoo = injector.resolve();
46 |
47 | REQUIRE(foo != nullptr);
48 | REQUIRE(foo == foofoo);
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/Emaject/tests/with_arg.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include "catch.hpp"
4 |
5 | namespace
6 | {
7 | using emaject::Container;
8 | using emaject::IInstaller;
9 | using emaject::Injector;
10 |
11 | class ICounter
12 | {
13 | public:
14 | virtual ~ICounter() = default;
15 | virtual int countUp() = 0;
16 | };
17 |
18 | class Counter : public ICounter
19 | {
20 | int m_count;
21 | public:
22 | Counter(int count = 0):
23 | m_count(count)
24 | {}
25 |
26 | int countUp() override
27 | {
28 | return ++m_count;
29 | }
30 | };
31 |
32 | struct CounterInstaller : IInstaller
33 | {
34 | void onBinding(Container* c) const
35 | {
36 | c->bind()
37 | .to()
38 | .withArgs(100)
39 | .asTransient();
40 | }
41 | };
42 |
43 | TEST_CASE("with_arg")
44 | {
45 | Injector injector;
46 | injector.install();
47 |
48 | {
49 | auto counter = injector.resolve();
50 | REQUIRE(counter->countUp() == 101);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Emaject/tests/from_instance.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "catch.hpp"
3 |
4 | namespace
5 | {
6 | using emaject::Container;
7 | using emaject::IInstaller;
8 | using emaject::Injector;
9 |
10 |
11 | class Singleton
12 | {
13 | public:
14 | static std::shared_ptr Instance()
15 | {
16 | static auto instance = std::shared_ptr(new Singleton());
17 | return instance;
18 | }
19 | private:
20 | Singleton() = default;
21 | Singleton(const Singleton& other) = delete;
22 | Singleton& operator=(const Singleton& other) = delete;
23 | };
24 | struct SingletonInstaller : IInstaller
25 | {
26 | void onBinding(Container* c) const
27 | {
28 | c->bind()
29 | .toSelf()
30 | .fromInstance(Singleton::Instance())
31 | .asSingle();
32 | }
33 | };
34 | TEST_CASE("from_instance")
35 | {
36 | Injector injector;
37 | injector.install();
38 | {
39 | auto singleton = injector.resolve();
40 | REQUIRE(Singleton::Instance().get() == singleton.get());
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/Emaject/tests/transient.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include "catch.hpp"
5 |
6 | namespace
7 | {
8 | using emaject::Container;
9 | using emaject::IInstaller;
10 | using emaject::Injector;
11 |
12 | class ICounter
13 | {
14 | public:
15 | virtual ~ICounter() = default;
16 | virtual int countUp() = 0;
17 | };
18 |
19 | class Counter : public ICounter
20 | {
21 | int m_count = 0;
22 | public:
23 | int countUp() override
24 | {
25 | return ++m_count;
26 | }
27 | };
28 |
29 | struct CounterInstaller : IInstaller
30 | {
31 | void onBinding(Container* c) const
32 | {
33 | c->bind()
34 | .to()
35 | .asTransient();
36 | }
37 | };
38 |
39 | TEST_CASE("transient")
40 | {
41 | Injector injector;
42 | injector.install();
43 |
44 | {
45 | auto counter = injector.resolve(); // new instance
46 | REQUIRE(counter->countUp() == 1);
47 | }
48 | {
49 | auto counter = injector.resolve(); // new instance
50 | REQUIRE(counter->countUp() == 1);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Emaject/tests/ctor_inject.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include "catch.hpp"
6 |
7 | namespace
8 | {
9 | using emaject::Container;
10 | using emaject::IInstaller;
11 | using emaject::Injector;
12 |
13 | class IPrinter
14 | {
15 | public:
16 | virtual ~IPrinter() = default;
17 | virtual void println(std::string_view str) const = 0;
18 | };
19 |
20 | class CoutPrinter : public IPrinter
21 | {
22 | public:
23 | void println(std::string_view str) const override
24 | {
25 | }
26 | };
27 |
28 | struct CoutInstaller : IInstaller
29 | {
30 | void onBinding(Container* c) const
31 | {
32 | c->bind()
33 | .to()
34 | .asCached();
35 | }
36 | };
37 |
38 | class HelloWorld
39 | {
40 | public:
41 | INJECT_CTOR(HelloWorld(std::shared_ptr printer)) :
42 | m_printer(printer)
43 | {}
44 |
45 | void greet() const
46 | {
47 | m_printer->println("[ctor_inject] Hello World");
48 | }
49 | private:
50 | std::shared_ptr m_printer;
51 | };
52 |
53 | TEST_CASE("ctor_inject")
54 | {
55 | Injector injector;
56 | injector.install();
57 |
58 | auto helloWorld = injector.instantiate();
59 | helloWorld->greet();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Emaject.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30717.126
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Emaject", "Emaject\Emaject.vcxproj", "{7026BEA5-2773-4939-988B-B380A50E16ED}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {7026BEA5-2773-4939-988B-B380A50E16ED}.Debug|x64.ActiveCfg = Debug|x64
17 | {7026BEA5-2773-4939-988B-B380A50E16ED}.Debug|x64.Build.0 = Debug|x64
18 | {7026BEA5-2773-4939-988B-B380A50E16ED}.Debug|x86.ActiveCfg = Debug|Win32
19 | {7026BEA5-2773-4939-988B-B380A50E16ED}.Debug|x86.Build.0 = Debug|Win32
20 | {7026BEA5-2773-4939-988B-B380A50E16ED}.Release|x64.ActiveCfg = Release|x64
21 | {7026BEA5-2773-4939-988B-B380A50E16ED}.Release|x64.Build.0 = Release|x64
22 | {7026BEA5-2773-4939-988B-B380A50E16ED}.Release|x86.ActiveCfg = Release|Win32
23 | {7026BEA5-2773-4939-988B-B380A50E16ED}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {81DCED82-43B2-4970-B8B6-0D3298C48A5F}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/Emaject/tests/field_inject.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include "catch.hpp"
6 | namespace
7 | {
8 | using emaject::Container;
9 | using emaject::IInstaller;
10 | using emaject::Injector;
11 |
12 | class IPrinter
13 | {
14 | public:
15 | virtual ~IPrinter() = default;
16 | virtual void println(std::string_view str) const = 0;
17 | };
18 |
19 | class CoutPrinter : public IPrinter
20 | {
21 | public:
22 | void println(std::string_view str) const override
23 | {
24 | std::cout << str << std::endl;
25 | }
26 | };
27 |
28 | struct CoutInstaller : IInstaller
29 | {
30 | void onBinding(Container* c) const
31 | {
32 | c->bind()
33 | .to()
34 | .asCached();
35 | }
36 | };
37 |
38 | class HelloWorld
39 | {
40 | public:
41 | HelloWorld() = default;
42 |
43 | void greet() const
44 | {
45 | m_printer->println("[field_inject] Hello World");
46 | }
47 | private:
48 | [[INJECT(m_printer)]]
49 | std::shared_ptr m_printer;
50 | };
51 |
52 | TEST_CASE("field_inject")
53 | {
54 | static_assert(emaject::detail::IsAutoInjectable);
55 | Injector injector;
56 | injector.install();
57 |
58 | auto helloWorld = injector.instantiate();
59 | helloWorld->greet();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Emaject/tests/from_factory.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include "catch.hpp"
5 |
6 | namespace
7 | {
8 | using emaject::Container;
9 | using emaject::IInstaller;
10 | using emaject::Injector;
11 |
12 | class IFoo
13 | {
14 | public:
15 | virtual ~IFoo() = default;
16 | virtual int value() const = 0;
17 | };
18 | class Foo : public IFoo
19 | {
20 | public:
21 | Foo(int value) :
22 | m_value(value)
23 | {
24 | }
25 | int value() const override
26 | {
27 | return m_value;
28 | }
29 | private:
30 | int m_value;
31 | };
32 |
33 | struct FooInstaller : IInstaller
34 | {
35 | void onBinding(Container* c) const
36 | {
37 | // No arg Factory
38 | c->bind()
39 | .toSelf()
40 | .fromFactory([] {
41 | return std::make_shared(1);
42 | })
43 | .asCached();
44 |
45 | // Container arg Factory
46 | c->bind()
47 | .toSelf()
48 | .fromFactory([](Container* c) {
49 | return std::make_shared(c->resolve()->value() + 1);
50 | })
51 | .asCached();
52 | }
53 | };
54 | TEST_CASE("from_factory")
55 | {
56 | Injector injector;
57 | injector.install();
58 |
59 | {
60 | auto foo0 = injector.resolve();
61 | auto foo1 = injector.resolve();
62 | REQUIRE(foo0->value() == 1);
63 | REQUIRE(foo1->value() == 2);
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/Emaject/tests/inject_taits.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include "catch.hpp"
6 |
7 | namespace
8 | {
9 | using emaject::Container;
10 | using emaject::IInstaller;
11 | using emaject::Injector;
12 |
13 | class IPrinter
14 | {
15 | public:
16 | virtual ~IPrinter() = default;
17 | virtual void println(std::string_view str) const = 0;
18 | };
19 |
20 | class CoutPrinter : public IPrinter
21 | {
22 | public:
23 | void println(std::string_view str) const override
24 | {
25 | std::cout << str << std::endl;
26 | }
27 | };
28 |
29 | struct CoutInstaller : IInstaller
30 | {
31 | void onBinding(Container* c) const
32 | {
33 | c->bind()
34 | .to()
35 | .asCached();
36 | }
37 | };
38 |
39 | class HelloWorld
40 | {
41 | public:
42 | HelloWorld()
43 | {}
44 |
45 | void greet() const
46 | {
47 | m_printer->println("[inject trairs] Hello World");
48 | }
49 |
50 | void setPrinter(std::shared_ptr printer)
51 | {
52 | m_printer = printer;
53 | }
54 | private:
55 | std::shared_ptr m_printer;
56 | };
57 | }
58 |
59 | namespace emaject
60 | {
61 | template<>
62 | struct InjectTraits
63 | {
64 | void onInject(HelloWorld* value, Container* c)
65 | {
66 | value->setPrinter(c->resolve());
67 | }
68 | };
69 | }
70 |
71 | namespace
72 | {
73 | TEST_CASE("inject trairs")
74 | {
75 | Injector injector;
76 | injector.install();
77 |
78 | auto helloWorld = injector.instantiate();
79 | helloWorld->greet();
80 | }
81 | }
--------------------------------------------------------------------------------
/Emaject/tests/method_inject.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include "catch.hpp"
6 |
7 | namespace
8 | {
9 | using emaject::Container;
10 | using emaject::IInstaller;
11 | using emaject::Injector;
12 |
13 | class Hoge
14 | {
15 | public:
16 | Hoge(int v):
17 | value(v)
18 | {}
19 | int value;
20 | };
21 |
22 | class Foo
23 | {
24 | public:
25 | Foo(int v) :
26 | value(v)
27 | {}
28 | int value;
29 | };
30 |
31 | class HogeFoo
32 | {
33 | public:
34 | int value() const
35 | {
36 | return m_hoge->value + m_foo->value;
37 | }
38 | int value2() const
39 | {
40 | return m_hoge2->value + m_foo2->value;
41 | }
42 | private:
43 | [[INJECT(setHogeAndFoo)]]
44 | void setHogeAndFoo(
45 | const std::shared_ptr& hoge,
46 | const std::shared_ptr& foo
47 | ) {
48 | m_hoge = hoge;
49 | m_foo = foo;
50 | }
51 | [[INJECT(setHogeAndFoo2, 1, 2)]]
52 | void setHogeAndFoo2(
53 | const std::shared_ptr& hoge,
54 | const std::shared_ptr& foo
55 | ) {
56 | m_hoge2 = hoge;
57 | m_foo2 = foo;
58 | }
59 | private:
60 | std::shared_ptr m_hoge;
61 | std::shared_ptr m_foo;
62 |
63 | std::shared_ptr m_hoge2;
64 | std::shared_ptr m_foo2;
65 | };
66 | struct HogeFooInstaller : IInstaller
67 | {
68 | void onBinding(Container* c) const
69 | {
70 | c->bind().withArgs(20).asTransient();
71 | c->bind().withArgs(100).asTransient();
72 |
73 | c->bind().withArgs(10).asTransient();
74 | c->bind().withArgs(200).asTransient();
75 | }
76 | };
77 |
78 | TEST_CASE("method_inject")
79 | {
80 | Injector injector;
81 | injector.install();
82 |
83 | auto hogeFoo = injector.instantiate();
84 | REQUIRE(hogeFoo->value() == 120);
85 | REQUIRE(hogeFoo->value2() == 210);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Emaject/tests/use_id.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include
6 | #include "catch.hpp"
7 |
8 | namespace
9 | {
10 | using emaject::Container;
11 | using emaject::IInstaller;
12 | using emaject::Injector;
13 |
14 | class IPrinter
15 | {
16 | public:
17 | virtual ~IPrinter() = default;
18 | virtual void println(std::string_view str) const = 0;
19 | };
20 |
21 | class CoutPrinter : public IPrinter
22 | {
23 | public:
24 | void println(std::string_view str) const override
25 | {
26 | std::cout << str << " for cout" << std::endl;
27 | }
28 | };
29 |
30 | class PrintfPrinter : public IPrinter
31 | {
32 | public:
33 | void println(std::string_view str) const override
34 | {
35 | std::printf("%s for printf\n", str.data());
36 | }
37 | };
38 |
39 | struct CoutInstaller : IInstaller
40 | {
41 | void onBinding(Container* c) const
42 | {
43 | // ID = 0 -> CoutPrinter
44 | c->bind()
45 | .to()
46 | .asCached();
47 | }
48 | };
49 | struct PrintfInstaller : IInstaller
50 | {
51 | void onBinding(Container* c) const
52 | {
53 | // ID = 1 -> PrintfPrinter
54 | c->bind()
55 | .to()
56 | .asCached();
57 | }
58 | };
59 | class HelloWorld
60 | {
61 | public:
62 | HelloWorld() = default;
63 |
64 | void greet() const
65 | {
66 | m_printer0->println("Hello World");
67 | m_printer1->println("Hello World");
68 | }
69 | private:
70 | [[INJECT(m_printer0)]] // ID = 0
71 | std::shared_ptr m_printer0;
72 |
73 | [[INJECT(m_printer1, 1)]]
74 | std::shared_ptr m_printer1;
75 | };
76 |
77 | TEST_CASE("use_id")
78 | {
79 | Injector injector;
80 | injector
81 | .install()
82 | .install();
83 |
84 | auto helloWorld = injector.instantiate();
85 | helloWorld->greet();
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Emaject/tests/single.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "catch.hpp"
4 |
5 | namespace
6 | {
7 | using emaject::Container;
8 | using emaject::IInstaller;
9 | using emaject::Injector;
10 |
11 | class ICounter
12 | {
13 | public:
14 | virtual ~ICounter() = default;
15 | virtual int countUp() = 0;
16 | };
17 | class IPrinter
18 | {
19 | public:
20 | virtual ~IPrinter() = default;
21 | virtual void println(std::string_view str) const = 0;
22 | };
23 | class PrintCounter : public ICounter, public IPrinter
24 | {
25 | int m_count = 0;
26 | public:
27 | int countUp() override
28 | {
29 | return ++m_count;
30 | }
31 | void println(std::string_view str) const override
32 | {
33 | std::cout << "[single]" << str << " " << m_count << std::endl;
34 | }
35 | };
36 |
37 | struct CounterInstaller : IInstaller
38 | {
39 | void onBinding(Container* c) const
40 | {
41 | c->bind()
42 | .to()
43 | .asSingle();
44 |
45 | // failed
46 | c->bind()
47 | .to()
48 | .asCached();
49 |
50 | // failed
51 | c->bind()
52 | .to()
53 | .asTransient();
54 | }
55 | };
56 |
57 | TEST_CASE("single")
58 | {
59 | Injector injector;
60 | injector.install();
61 |
62 | {
63 | auto counter = injector.resolve(); // new instance(single)
64 | REQUIRE(counter != nullptr);
65 | REQUIRE(counter->countUp() == 1);
66 | }
67 | {
68 | auto counter1 = injector.resolve(); // cached
69 | auto counter2 = injector.resolve(); // cached
70 | REQUIRE(counter1 == counter2);
71 | }
72 | {
73 | auto counter = injector.resolve(); // failed
74 | REQUIRE(counter == nullptr);
75 | }
76 | {
77 | auto printer = injector.resolve(); // failed
78 | REQUIRE(printer == nullptr);
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Emaject/tests/cached.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include "catch.hpp"
5 |
6 | namespace
7 | {
8 | using emaject::Container;
9 | using emaject::IInstaller;
10 | using emaject::Injector;
11 |
12 | class ICounter
13 | {
14 | public:
15 | virtual ~ICounter() = default;
16 | virtual int countUp() = 0;
17 | };
18 |
19 | class Counter : public ICounter
20 | {
21 | int m_count = 0;
22 | public:
23 | int countUp() override
24 | {
25 | return ++m_count;
26 | }
27 | };
28 |
29 | struct Test
30 | {
31 | [[INJECT(c1)]]
32 | std::shared_ptr c1;
33 | [[INJECT(c1_2)]]
34 | std::shared_ptr c1_2;
35 | [[INJECT(c2, 2)]]
36 | std::shared_ptr c2;
37 | [[INJECT(c2_2, 2)]]
38 | std::shared_ptr c2_2;
39 |
40 | [[INJECT(c3)]]
41 | std::shared_ptr c3;
42 | };
43 | struct CounterInstaller : IInstaller
44 | {
45 | void onBinding(Container* c) const
46 | {
47 | c->bind()
48 | .to()
49 | .asCached();
50 |
51 | c->bind()
52 | .to()
53 | .asCached();
54 |
55 | c->bind()
56 | .asCached();
57 | }
58 | };
59 | TEST_CASE("cached")
60 | {
61 | Injector injector;
62 | injector.install();
63 |
64 | {
65 | auto counter = injector.resolve(); // new instance
66 | REQUIRE(counter->countUp() == 1);
67 | }
68 | {
69 | auto counter = injector.resolve(); // used cache
70 | REQUIRE(counter->countUp() == 2);
71 | }
72 | {
73 | auto test = injector.instantiate();
74 | REQUIRE(test->c1 != nullptr);
75 | REQUIRE(test->c2 != nullptr);
76 | REQUIRE(test->c3 != nullptr);
77 |
78 | REQUIRE(test->c1 == test->c1_2);
79 | REQUIRE(test->c1 != test->c2);
80 | REQUIRE(test->c1 != test->c2_2);
81 | REQUIRE(test->c1 != test->c3);
82 |
83 | REQUIRE(test->c2 == test->c2_2);
84 | REQUIRE(test->c3 == test->c3);
85 | }
86 | }
87 | }
--------------------------------------------------------------------------------
/Emaject/Emaject.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | ヘッダー ファイル
20 |
21 |
22 | ヘッダー ファイル
23 |
24 |
25 |
26 |
27 | ソース ファイル
28 |
29 |
30 | ソース ファイル
31 |
32 |
33 | ソース ファイル
34 |
35 |
36 | ソース ファイル
37 |
38 |
39 | ソース ファイル
40 |
41 |
42 | ソース ファイル
43 |
44 |
45 | ソース ファイル
46 |
47 |
48 | ソース ファイル
49 |
50 |
51 | ソース ファイル
52 |
53 |
54 | ソース ファイル
55 |
56 |
57 | ソース ファイル
58 |
59 |
60 | ソース ファイル
61 |
62 |
63 | ソース ファイル
64 |
65 |
66 | ソース ファイル
67 |
68 |
69 | ソース ファイル
70 |
71 |
72 | ソース ファイル
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Skip to content
2 | Search or jump to…
3 |
4 | Pull requests
5 | Issues
6 | Marketplace
7 | Explore
8 |
9 | @tyanmahou
10 | tyanmahou
11 | /
12 | Magico
13 | 1
14 | 6
15 | 0
16 | Code
17 | Issues
18 | Pull requests
19 | Actions
20 | Projects
21 | Wiki
22 | Security
23 | Insights
24 | Settings
25 | Magico/.gitignore
26 |
27 | mahou gitignore add
28 | Latest commit 1cc0884 on 5 Sep 2017
29 | History
30 | 0 contributors
31 | 299 lines (242 sloc) 5.16 KB
32 |
33 | ## Ignore Visual Studio temporary files, build results, and
34 | ## files generated by popular Visual Studio add-ons.
35 | ##
36 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
37 |
38 | # User-specific files
39 | *.suo
40 | *.user
41 | *.userosscache
42 | *.sln.docstates
43 |
44 | # User-specific files (MonoDevelop/Xamarin Studio)
45 | *.userprefs
46 |
47 | # Build results
48 | [Dd]ebug/
49 | [Dd]ebugPublic/
50 | [Rr]elease/
51 | [Rr]eleases/
52 | x64/
53 | x86/
54 | bld/
55 | [Bb]in/
56 | [Oo]bj/
57 | [Ll]og/
58 |
59 | # Visual Studio 2015 cache/options directory
60 | .vs/
61 | # Uncomment if you have tasks that create the project's static files in wwwroot
62 | #wwwroot/
63 |
64 | # MSTest test Results
65 | [Tt]est[Rr]esult*/
66 | [Bb]uild[Ll]og.*
67 |
68 | # NUNIT
69 | *.VisualState.xml
70 | TestResult.xml
71 |
72 | # Build Results of an ATL Project
73 | [Dd]ebugPS/
74 | [Rr]eleasePS/
75 | dlldata.c
76 |
77 | # Benchmark Results
78 | BenchmarkDotNet.Artifacts/
79 |
80 | # .NET Core
81 | project.lock.json
82 | project.fragment.lock.json
83 | artifacts/
84 | **/Properties/launchSettings.json
85 |
86 | *_i.c
87 | *_p.c
88 | *_i.h
89 | *.ilk
90 | *.meta
91 | *.obj
92 | *.pch
93 | *.pdb
94 | *.pgc
95 | *.pgd
96 | *.rsp
97 | *.sbr
98 | *.tlb
99 | *.tli
100 | *.tlh
101 | *.tmp
102 | *.tmp_proj
103 | *.log
104 | *.vspscc
105 | *.vssscc
106 | .builds
107 | *.pidb
108 | *.svclog
109 | *.scc
110 |
111 | # Chutzpah Test files
112 | _Chutzpah*
113 |
114 | # Visual C++ cache files
115 | ipch/
116 | *.aps
117 | *.ncb
118 | *.opendb
119 | *.opensdf
120 | *.sdf
121 | *.cachefile
122 | *.VC.db
123 | *.VC.VC.opendb
124 |
125 | # Visual Studio profiler
126 | *.psess
127 | *.vsp
128 | *.vspx
129 | *.sap
130 |
131 | # TFS 2012 Local Workspace
132 | $tf/
133 |
134 | # Guidance Automation Toolkit
135 | *.gpState
136 |
137 | # ReSharper is a .NET coding add-in
138 | _ReSharper*/
139 | *.[Rr]e[Ss]harper
140 | *.DotSettings.user
141 |
142 | # JustCode is a .NET coding add-in
143 | .JustCode
144 |
145 | # TeamCity is a build add-in
146 | _TeamCity*
147 |
148 | # DotCover is a Code Coverage Tool
149 | *.dotCover
150 |
151 | # AxoCover is a Code Coverage Tool
152 | .axoCover/*
153 | !.axoCover/settings.json
154 |
155 | # Visual Studio code coverage results
156 | *.coverage
157 | *.coveragexml
158 |
159 | # NCrunch
160 | _NCrunch_*
161 | .*crunch*.local.xml
162 | nCrunchTemp_*
163 |
164 | # MightyMoose
165 | *.mm.*
166 | AutoTest.Net/
167 |
168 | # Web workbench (sass)
169 | .sass-cache/
170 |
171 | # Installshield output folder
172 | [Ee]xpress/
173 |
174 | # DocProject is a documentation generator add-in
175 | DocProject/buildhelp/
176 | DocProject/Help/*.HxT
177 | DocProject/Help/*.HxC
178 | DocProject/Help/*.hhc
179 | DocProject/Help/*.hhk
180 | DocProject/Help/*.hhp
181 | DocProject/Help/Html2
182 | DocProject/Help/html
183 |
184 | # Click-Once directory
185 | publish/
186 |
187 | # Publish Web Output
188 | *.[Pp]ublish.xml
189 | *.azurePubxml
190 | # Note: Comment the next line if you want to checkin your web deploy settings,
191 | # but database connection strings (with potential passwords) will be unencrypted
192 | *.pubxml
193 | *.publishproj
194 |
195 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
196 | # checkin your Azure Web App publish settings, but sensitive information contained
197 | # in these scripts will be unencrypted
198 | PublishScripts/
199 |
200 | # NuGet Packages
201 | *.nupkg
202 | # The packages folder can be ignored because of Package Restore
203 | **/packages/*
204 | # except build/, which is used as an MSBuild target.
205 | !**/packages/build/
206 | # Uncomment if necessary however generally it will be regenerated when needed
207 | #!**/packages/repositories.config
208 | # NuGet v3's project.json files produces more ignorable files
209 | *.nuget.props
210 | *.nuget.targets
211 |
212 | # Microsoft Azure Build Output
213 | csx/
214 | *.build.csdef
215 |
216 | # Microsoft Azure Emulator
217 | ecf/
218 | rcf/
219 |
220 | # Windows Store app package directories and files
221 | AppPackages/
222 | BundleArtifacts/
223 | Package.StoreAssociation.xml
224 | _pkginfo.txt
225 | *.appx
226 |
227 | # Visual Studio cache files
228 | # files ending in .cache can be ignored
229 | *.[Cc]ache
230 | # but keep track of directories ending in .cache
231 | !*.[Cc]ache/
232 |
233 | # Others
234 | ClientBin/
235 | ~$*
236 | *~
237 | *.dbmdl
238 | *.dbproj.schemaview
239 | *.jfm
240 | *.pfx
241 | *.publishsettings
242 | orleans.codegen.cs
243 |
244 | # Since there are multiple workflows, uncomment next line to ignore bower_components
245 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
246 | #bower_components/
247 |
248 | # RIA/Silverlight projects
249 | Generated_Code/
250 |
251 | # Backup & report files from converting an old project file
252 | # to a newer Visual Studio version. Backup files are not needed,
253 | # because we have git ;-)
254 | _UpgradeReport_Files/
255 | Backup*/
256 | UpgradeLog*.XML
257 | UpgradeLog*.htm
258 |
259 | # SQL Server files
260 | *.mdf
261 | *.ldf
262 | *.ndf
263 |
264 | # Business Intelligence projects
265 | *.rdl.data
266 | *.bim.layout
267 | *.bim_*.settings
268 |
269 | # Microsoft Fakes
270 | FakesAssemblies/
271 |
272 | # GhostDoc plugin setting file
273 | *.GhostDoc.xml
274 |
275 | # Node.js Tools for Visual Studio
276 | .ntvs_analysis.dat
277 | node_modules/
278 |
279 | # Typescript v1 declaration files
280 | typings/
281 |
282 | # Visual Studio 6 build log
283 | *.plg
284 |
285 | # Visual Studio 6 workspace options file
286 | *.opt
287 |
288 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
289 | *.vbw
290 |
291 | # Visual Studio LightSwitch build output
292 | **/*.HTMLClient/GeneratedArtifacts
293 | **/*.DesktopClient/GeneratedArtifacts
294 | **/*.DesktopClient/ModelManifest.xml
295 | **/*.Server/GeneratedArtifacts
296 | **/*.Server/ModelManifest.xml
297 | _Pvt_Extensions
298 |
299 | # Paket dependency manager
300 | .paket/paket.exe
301 | paket-files/
302 |
303 | # FAKE - F# Make
304 | .fake/
305 |
306 | # JetBrains Rider
307 | .idea/
308 | *.sln.iml
309 |
310 | # CodeRush
311 | .cr/
312 |
313 | # Python Tools for Visual Studio (PTVS)
314 | __pycache__/
315 | *.pyc
316 |
317 | # Cake - Uncomment if you are using it
318 | # tools/**
319 | # !tools/packages.config
320 |
321 | # Tabs Studio
322 | *.tss
323 |
324 | # Telerik's JustMock configuration file
325 | *.jmconfig
326 |
327 | # BizTalk build output
328 | *.btp.cs
329 | *.btm.cs
330 | *.odx.cs
331 | *.xsd.cs
332 | © 2020 GitHub, Inc.
333 | Terms
334 | Privacy
335 | Security
336 | Status
337 | Help
338 | Contact GitHub
339 | Pricing
340 | API
341 | Training
342 | Blog
343 | About
344 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Emaject
2 | C++20 DI Library
3 |
4 | ## About
5 |
6 | "Emaject" is a `Dependency Injection` library for C++20 only with a header;
7 |
8 | ## How to
9 |
10 | Header Include Only `Emaject.hpp`
11 |
12 | ## Example
13 |
14 | ```cpp
15 | class IPrinter
16 | {
17 | public:
18 | virtual ~IPrinter() = default;
19 | virtual void println(std::string_view str) const = 0;
20 | };
21 |
22 | class CoutPrinter : public IPrinter
23 | {
24 | public:
25 | void println(std::string_view str) const override
26 | {
27 | std::cout << str << std::endl;
28 | }
29 | };
30 |
31 | struct CoutInstaller : IInstaller
32 | {
33 | void onBinding(Container* c) const
34 | {
35 | c->bind()
36 | .to()
37 | .asCached();
38 | }
39 | };
40 |
41 | int main()
42 | {
43 | Injector injector;
44 | injector.install();
45 |
46 | auto printer = injector.resolve();
47 | printer->println("Hello World");
48 | }
49 | ```
50 | ### Field Inject
51 |
52 | This is executed after the constructor.
53 |
54 | ```cpp
55 | class HelloWorld
56 | {
57 | public:
58 | HelloWorld() = default;
59 |
60 | void greet() const
61 | {
62 | m_printer->println("Hello World");
63 | }
64 | private:
65 | [[INJECT(m_printer)]]
66 | std::shared_ptr m_printer;
67 | };
68 |
69 | int main()
70 | {
71 | Injector injector;
72 | injector.install();
73 |
74 | auto helloWorld = injector.instantiate();
75 | helloWorld->greet();
76 | }
77 | ```
78 | ### Method Inject
79 |
80 | This is executed at the same timing as Field Inject.
81 |
82 | ```cpp
83 | class HelloWorld
84 | {
85 | public:
86 | HelloWorld() = default;
87 |
88 | void greet() const
89 | {
90 | m_printer->println("Hello World");
91 | }
92 | private:
93 | [[INJECT(setPrinter)]]
94 | void setPrinter(std::shared_ptr printer)
95 | {
96 | m_printer = printer;
97 | }
98 | std::shared_ptr m_printer;
99 | };
100 | ```
101 |
102 | ### Constructor Inject
103 |
104 | ```cpp
105 | class HelloWorld
106 | {
107 | public:
108 | INJECT_CTOR(HelloWorld(std::shared_ptr printer)):
109 | m_printer(printer)
110 | {}
111 |
112 | void greet() const
113 | {
114 | m_printer->println("Hello World");
115 | }
116 | private:
117 | std::shared_ptr m_printer;
118 | };
119 | ```
120 | ### Traits Inject
121 |
122 | You can also inject using `InjectTraits`.
123 | This is executed after the constructor and Field Inject.
124 |
125 |
126 | ```cpp
127 | namespace emaject
128 | {
129 | template<>
130 | struct InjectTraits
131 | {
132 | void onInject(HelloWorld* value, Container* c)
133 | {
134 | value->setPrinter(c->resolve());
135 | }
136 | };
137 | }
138 | ```
139 |
140 | ### ID
141 |
142 | You can use an ID for binding. If not specified, it will be `0`.
143 |
144 | ```cpp
145 | class PrintfPrinter : public IPrinter
146 | {
147 | public:
148 | void println(std::string_view str) const override
149 | {
150 | std::printf("%s for printf", str.data());
151 | }
152 | };
153 |
154 | struct PrintfInstaller : IInstaller
155 | {
156 | void onBinding(Container* c) const
157 | {
158 | // ID = 1 -> PrintfPrinter
159 | c->bind()
160 | .to()
161 | .asCached();
162 | }
163 | };
164 | ```
165 | You can specify the ID with field inject.
166 |
167 | ```cpp
168 | class HelloWorld
169 | {
170 | public:
171 | HelloWorld() = default;
172 |
173 | void greet() const
174 | {
175 | m_printer0->println("Hello World");
176 | m_printer1->println("Hello World");
177 | }
178 | private:
179 | [[INJECT(m_printer0)]] // default ID = 0
180 | std::shared_ptr m_printer0;
181 |
182 | [[INJECT(m_printer1, 1)]] // ID = 1
183 | std::shared_ptr m_printer1;
184 | };
185 | ```
186 |
187 | and method inject.
188 |
189 | ```cpp
190 | class HelloWorld
191 | {
192 | public:
193 | HelloWorld() = default;
194 |
195 | void greet() const
196 | {
197 | m_printer0->println("Hello World");
198 | m_printer1->println("Hello World");
199 | }
200 | private:
201 | [[INJECT(setPrinter, 0, 1)]]
202 | void setPrinter(std::shared_ptr printer0, std::shared_ptr printer1)
203 | {
204 | m_printer0 = printer0;
205 | m_printer1 = printer1;
206 | }
207 | std::shared_ptr m_printer0;
208 | std::shared_ptr m_printer1;
209 | };
210 | ```
211 | or resolve
212 |
213 | ```cpp
214 | container->resolve();
215 | ```
216 |
217 | ### Scope
218 |
219 | #### Transient
220 |
221 | If you use `asTransient()`, an instance will be created for each injection.
222 |
223 | ```cpp
224 | struct CounterInstaller : IInstaller
225 | {
226 | void onBinding(Container* c) const
227 | {
228 | c->bind()
229 | .to()
230 | .asTransient();
231 | }
232 | };
233 |
234 | int main()
235 | {
236 | Injector injector;
237 | injector.install();
238 |
239 | {
240 | auto counter = injector.resolve(); // new instance
241 | std::cout << counter->countUp() << std::endl; // 1
242 | }
243 | {
244 | auto counter = injector.resolve(); // new instance
245 | std::cout << counter->countUp() << std::endl; // 1
246 | }
247 | }
248 | ```
249 |
250 | #### Cached
251 |
252 | If you use `asCached`, the one cached by the ID will be reused.
253 |
254 | ```cpp
255 | struct CounterInstaller : IInstaller
256 | {
257 | void onBinding(Container* c) const
258 | {
259 | container->bind()
260 | .to()
261 | .asCached();
262 | }
263 | };
264 |
265 | int main()
266 | {
267 | Injector injector;
268 | injector.install();
269 |
270 | {
271 | auto counter = injector.resolve(); // new instance
272 | std::cout << counter->countUp() << std::endl; // 1
273 | }
274 | {
275 | auto counter = injector.resolve(); // use cache
276 | std::cout << counter->countUp() << std::endl; // 2
277 | }
278 | }
279 | ```
280 |
281 | #### Single
282 |
283 | If you use `asSingle`, the cached one will be reused and you can't bind to same type.
284 |
285 | ```cpp
286 | struct CounterInstaller : IInstaller
287 | {
288 | void onBinding(Container* c) const
289 | {
290 | c->bind()
291 | .to()
292 | .asSingle();
293 |
294 | // failed Counter is Already bind to
295 | c->bind()
296 | .to()
297 | .asSingle();
298 | }
299 | };
300 |
301 | int main()
302 | {
303 | Injector injector;
304 | injector.install();
305 |
306 | {
307 | auto counter = injector.resolve(); // new instance
308 | std::cout << counter->countUp() << std::endl; // 1
309 | }
310 | {
311 | auto counter = injector.resolve(); // used cache
312 | std::cout << counter->countUp() << std::endl; // 2
313 | }
314 | {
315 | auto counter = injector.resolve(); // nullptr
316 | }
317 | }
318 | ```
--------------------------------------------------------------------------------
/Emaject/Emaject.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 16.0
23 | Win32Proj
24 | {7026bea5-2773-4939-988b-b380a50e16ed}
25 | Emaject
26 | 10.0
27 |
28 |
29 |
30 | Application
31 | true
32 | v143
33 | Unicode
34 |
35 |
36 | Application
37 | false
38 | v143
39 | true
40 | Unicode
41 |
42 |
43 | Application
44 | true
45 | v143
46 | Unicode
47 |
48 |
49 | Application
50 | false
51 | v143
52 | true
53 | Unicode
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | true
75 | $(ProjectDir)\include;$(IncludePath)
76 |
77 |
78 | false
79 |
80 |
81 | true
82 |
83 |
84 | false
85 |
86 |
87 |
88 | Level3
89 | true
90 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
91 | true
92 | stdcpplatest
93 |
94 |
95 | Console
96 | true
97 |
98 |
99 |
100 |
101 | Level3
102 | true
103 | true
104 | true
105 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
106 | true
107 | stdcpplatest
108 |
109 |
110 | Console
111 | true
112 | true
113 | true
114 |
115 |
116 |
117 |
118 | Level3
119 | true
120 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
121 | true
122 |
123 |
124 | Console
125 | true
126 |
127 |
128 |
129 |
130 | Level3
131 | true
132 | true
133 | true
134 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
135 | true
136 |
137 |
138 | Console
139 | true
140 | true
141 | true
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/Emaject/include/Emaject.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | namespace emaject
11 | {
12 | class Container;
13 |
14 | template
15 | struct InjectTraits
16 | {
17 | //void onInject(Type* value, Container* c)
18 | };
19 |
20 | namespace detail
21 | {
22 | template
23 | struct AutoInjector;
24 |
25 | template
26 | struct MethodInjector;
27 |
28 | template
29 | concept TraitsInjectable = requires(Type * t, Container * c)
30 | {
31 | InjectTraits{}.onInject(t, c);
32 | };
33 |
34 | template
35 | concept AutoInjectable = requires(Type * t, Container * c)
36 | {
37 | AutoInjector{}.onInject(t, c);
38 | };
39 |
40 | template
41 | concept MethodInjectable = requires(Type * t, Container * c)
42 | {
43 | requires std::is_member_function_pointer_v;
44 | typename MethodInjector::Type;
45 | MethodInjector{}.onInject(t, c);
46 | };
47 |
48 | template
49 | concept CtorInjectable = requires()
50 | {
51 | typename Type::CtorInject;
52 | };
53 |
54 | template
55 | concept DefaultInstantiatable = (sizeof...(Args) == 0 && detail::CtorInjectable) || std::constructible_from;
56 | }
57 |
58 | ///
59 | /// Container
60 | ///
61 | class Container
62 | {
63 | public:
64 | template
65 | [[nodiscard]] auto bind()
66 | {
67 | return Binder(this);
68 | }
69 |
70 | template
71 | [[nodiscard]] std::shared_ptr instantiate(Args&&... args)
72 | {
73 | auto ret = this->makeInstance(std::forward(args)...);
74 | this->inject(ret.get());
75 | return ret;
76 | }
77 | template
78 | [[nodiscard]] std::shared_ptr resolve()
79 | {
80 | auto itr = m_bindInfos.find(typeid(Tag));
81 | if (itr == m_bindInfos.end()) {
82 | return nullptr;
83 | }
84 | auto&& [factory, createKind, cache] = std::any_cast&>(itr->second);
85 | if (createKind != ScopeKind::Transient) {
86 | if (!cache) {
87 | cache = factory(this);
88 | }
89 | return std::static_pointer_cast(cache);
90 | }
91 | return std::static_pointer_cast(factory(this));
92 | }
93 |
94 | template
95 | void inject(Type* value)
96 | {
97 | if constexpr (detail::AutoInjectable) {
98 | if (value) {
99 | detail::AutoInjector{}.onInject(value, this);
100 | }
101 | }
102 | if constexpr (detail::TraitsInjectable) {
103 | if (value) {
104 | InjectTraits{}.onInject(value, this);
105 | }
106 | }
107 | }
108 | private:
109 | enum class ScopeKind
110 | {
111 | Transient,
112 | Cached,
113 | Single
114 | };
115 | template
116 | struct Tag {};
117 |
118 | template
119 | using Factory = std::function(Container*)>;
120 |
121 | template
122 | struct BindInfo
123 | {
124 | Factory factory;
125 | ScopeKind kind;
126 | std::shared_ptr cache;
127 | };
128 | struct DerefInfo
129 | {
130 | bool isSingle = false;
131 | std::vector bindIds;
132 | };
133 | template
134 | class Binder
135 | {
136 | public:
137 | Binder(Container* c) :
138 | m_container(c)
139 | {}
140 | public:
141 | template
142 | [[nodiscard]] auto to() const
143 | {
144 | return FromDescriptor(m_container);
145 | }
146 | [[nodiscard]] auto toSelf() const
147 | {
148 | return FromDescriptor(m_container);
149 | }
150 | public:
151 | [[nodiscard]] auto fromNew() const requires detail::DefaultInstantiatable
152 | {
153 | return toSelf().fromNew();
154 | }
155 | template
156 | [[nodiscard]] auto withArgs(Args&&... args) const requires std::constructible_from
157 | {
158 | return toSelf().withArgs(std::forward(args)...);
159 | }
160 | [[nodiscard]] auto fromInstance(const std::shared_ptr& instance) const
161 | {
162 | return toSelf().fromInstance(instance);
163 | }
164 | [[nodiscard]] auto fromFactory(const Factory& factory) const
165 | {
166 | return toSelf().fromFactory(factory);
167 | }
168 | [[nodiscard]] auto fromFactory(const std::function()>& factory) const
169 | {
170 | return toSelf().fromFactory(factory);
171 | }
172 | [[nodiscard]] auto unused() const
173 | {
174 | return toSelf().unused();
175 | }
176 | public:
177 | bool asTransient() const requires detail::DefaultInstantiatable
178 | {
179 | return fromNew().asTransient();
180 | }
181 | bool asCached() const requires detail::DefaultInstantiatable
182 | {
183 | return fromNew().asCached();
184 | }
185 | bool asSingle() const requires detail::DefaultInstantiatable
186 | {
187 | return fromNew().asSingle();
188 | }
189 | private:
190 | Container* m_container;
191 | };
192 |
193 | template
194 | class FromDescriptor
195 | {
196 | public:
197 | FromDescriptor(Container* c) :
198 | m_container(c)
199 | {}
200 | public:
201 | [[nodiscard]] auto fromNew() const requires detail::DefaultInstantiatable
202 | {
203 | return fromFactory([] (Container* c){
204 | return c->instantiate();
205 | });
206 | }
207 | template
208 | [[nodiscard]] auto withArgs(Args&&... args) const requires std::constructible_from
209 | {
210 | return fromFactory([...args = std::forward(args)](Container* c){
211 | // not allow move becouse transient
212 | auto ret = std::make_shared(args...);
213 | c->inject(ret.get());
214 | return ret;
215 | });
216 | }
217 | [[nodiscard]] auto fromInstance(const std::shared_ptr& instance) const
218 | {
219 | return fromFactory([i = instance] {
220 | return i;
221 | });
222 | }
223 | [[nodiscard]] auto fromFactory(const Factory& factory) const
224 | {
225 | return ScopeDescriptor(m_container, factory);
226 | }
227 | [[nodiscard]] auto fromFactory(const std::function()>& factory) const
228 | {
229 | return fromFactory([factory]([[maybe_unused]] Container* container) {
230 | return factory();
231 | });
232 | }
233 | template