aboutsummaryrefslogtreecommitdiff
path: root/src/DI
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2022-02-27 12:54:10 +0100
committerHampusM <hampus@hampusmat.com>2022-06-13 17:56:53 +0200
commit5864e5abc43b201c3801fa39a2fcaf9e3a9e8914 (patch)
tree98e5e324066ef4d1cbd3cc4c792a258fbd86c12d /src/DI
parente233dc28491c33e8a7dc0a11576d3b8ce91cce2c (diff)
refactor: use dependency injection
Diffstat (limited to 'src/DI')
-rw-r--r--src/DI/auto_wirable.hpp28
-rw-r--r--src/DI/auto_wirable.tpp10
-rw-r--r--src/DI/container.hpp65
-rw-r--r--src/DI/container.tpp53
-rw-r--r--src/DI/function_wrapper.hpp20
-rw-r--r--src/DI/function_wrapper.tpp9
-rw-r--r--src/DI/interfaces/wrapper.hpp17
-rw-r--r--src/DI/object_type.cpp18
-rw-r--r--src/DI/object_type.hpp35
-rw-r--r--src/DI/object_wrapper.hpp20
-rw-r--r--src/DI/object_wrapper.tpp9
11 files changed, 284 insertions, 0 deletions
diff --git a/src/DI/auto_wirable.hpp b/src/DI/auto_wirable.hpp
new file mode 100644
index 0000000..13d252e
--- /dev/null
+++ b/src/DI/auto_wirable.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "DI/container.hpp"
+
+#include <memory>
+
+// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
+class IGenericAutoWirable
+{
+public:
+ virtual ~IGenericAutoWirable() = default;
+};
+
+template <class Interface>
+class IAutoWirable : public IGenericAutoWirable
+{
+public:
+ static Interface resolve();
+};
+
+template <class Interface, class ObjectImpl, class... Dependencies>
+class AutoWirable : public IAutoWirable<Interface>
+{
+public:
+ static std::shared_ptr<Interface> resolve(const Container &container);
+};
+
+#include "auto_wirable.tpp"
diff --git a/src/DI/auto_wirable.tpp b/src/DI/auto_wirable.tpp
new file mode 100644
index 0000000..6c0d111
--- /dev/null
+++ b/src/DI/auto_wirable.tpp
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "auto_wirable.hpp"
+
+template <class Interface, class ObjectImpl, class... Dependencies>
+std::shared_ptr<Interface>
+AutoWirable<Interface, ObjectImpl, Dependencies...>::resolve(const Container &container)
+{
+ return std::make_shared<ObjectImpl>(container.get<Dependencies>()...);
+}
diff --git a/src/DI/container.hpp b/src/DI/container.hpp
new file mode 100644
index 0000000..2402894
--- /dev/null
+++ b/src/DI/container.hpp
@@ -0,0 +1,65 @@
+#pragma once
+
+#include "DI/object_type.hpp"
+#include "interfaces/wrapper.hpp"
+
+#include <functional>
+#include <memory>
+#include <type_traits>
+#include <unordered_map>
+
+class Container;
+
+template <typename Interface>
+class BindingBuilder
+{
+public:
+ explicit BindingBuilder(Container *container);
+
+ template <class ObjectImpl,
+ class = std::enable_if_t<std::is_base_of_v<Interface, ObjectImpl>>>
+ void to();
+
+ void to_factory(Interface func);
+
+private:
+ Container *_container;
+};
+
+template <typename Satan>
+struct is_func : public std::false_type // NOLINT(readability-identifier-naming)
+{
+};
+
+template <typename Satan, typename... Args>
+struct is_func<std::function<Satan(Args...)>> : public std::true_type
+{
+};
+
+class Container
+{
+public:
+ Container() = default;
+
+ template <class Interface>
+ BindingBuilder<Interface> bind();
+
+ template <class Interface, class = std::enable_if_t<std::is_abstract_v<Interface>>>
+ std::shared_ptr<Interface> get() const;
+
+ /*
+ template <typename Interface,
+ typename = std::enable_if_t<
+ !std::is_abstract_v<Interface> &&
+ std::is_invocable_v<Interface, typename Interface::argument_type>>>
+ Interface get() const;
+ */
+
+ template <typename Interface, typename = std::enable_if_t<is_func<Interface>::value>>
+ Interface get() const;
+
+ std::unordered_map<BaseObjectType, std::shared_ptr<IGenericWrapper>, ObjectTypeHasher>
+ bindings;
+};
+
+#include "container.tpp"
diff --git a/src/DI/container.tpp b/src/DI/container.tpp
new file mode 100644
index 0000000..21bf81a
--- /dev/null
+++ b/src/DI/container.tpp
@@ -0,0 +1,53 @@
+#pragma once
+
+#include "container.hpp"
+
+#include "function_wrapper.hpp"
+#include "object_wrapper.hpp"
+
+template <class Interface>
+BindingBuilder<Interface>::BindingBuilder(Container *container) : _container(container)
+{
+}
+
+template <class Interface>
+template <class ObjectImpl, class>
+void BindingBuilder<Interface>::to()
+{
+ _container->bindings.emplace(
+ ObjectType<Interface>(),
+ std::dynamic_pointer_cast<IGenericWrapper>(
+ std::make_shared<ObjectWrapper<Interface, ObjectImpl>>(*_container)));
+}
+
+template <class Interface>
+void BindingBuilder<Interface>::to_factory(Interface func)
+{
+ _container->bindings.emplace(ObjectType<Interface>(),
+ std::dynamic_pointer_cast<IGenericWrapper>(
+ std::make_shared<FunctionWrapper<Interface>>(func)));
+}
+
+template <class Interface>
+BindingBuilder<Interface> Container::bind()
+{
+ return BindingBuilder<Interface>(this);
+}
+
+template <class Interface, class>
+std::shared_ptr<Interface> Container::get() const
+{
+ auto wrapper = std::dynamic_pointer_cast<IWrapper<std::shared_ptr<Interface>>>(
+ bindings.at(ObjectType<Interface>()));
+
+ return wrapper->get();
+}
+
+template <typename Interface, typename>
+Interface Container::get() const
+{
+ auto wrapper = std::dynamic_pointer_cast<IWrapper<Interface>>(
+ bindings.at(ObjectType<Interface>()));
+
+ return wrapper->get();
+}
diff --git a/src/DI/function_wrapper.hpp b/src/DI/function_wrapper.hpp
new file mode 100644
index 0000000..e4b6779
--- /dev/null
+++ b/src/DI/function_wrapper.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "DI/container.hpp"
+#include "DI/interfaces/wrapper.hpp"
+
+#include <memory>
+
+template <class Interface>
+class FunctionWrapper : public IWrapper<Interface>
+{
+public:
+ explicit FunctionWrapper(Interface func) : _func(func) {}
+
+ [[nodiscard]] Interface get() const;
+
+private:
+ const Interface _func;
+};
+
+#include "function_wrapper.tpp"
diff --git a/src/DI/function_wrapper.tpp b/src/DI/function_wrapper.tpp
new file mode 100644
index 0000000..4e09957
--- /dev/null
+++ b/src/DI/function_wrapper.tpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "function_wrapper.hpp"
+
+template <class Interface>
+Interface FunctionWrapper<Interface>::get() const
+{
+ return _func;
+}
diff --git a/src/DI/interfaces/wrapper.hpp b/src/DI/interfaces/wrapper.hpp
new file mode 100644
index 0000000..3cc75a0
--- /dev/null
+++ b/src/DI/interfaces/wrapper.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <memory>
+
+// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
+class IGenericWrapper
+{
+public:
+ virtual ~IGenericWrapper() = default;
+};
+
+template <class Interface>
+class IWrapper : public IGenericWrapper
+{
+public:
+ [[nodiscard]] virtual Interface get() const = 0;
+};
diff --git a/src/DI/object_type.cpp b/src/DI/object_type.cpp
new file mode 100644
index 0000000..60c7c78
--- /dev/null
+++ b/src/DI/object_type.cpp
@@ -0,0 +1,18 @@
+#include "object_type.hpp"
+
+BaseObjectType::BaseObjectType(const std::type_info &type_info) : _type_info(type_info) {}
+
+bool BaseObjectType::operator==(const BaseObjectType &object_type) const
+{
+ return hash() == object_type.hash();
+}
+
+std::size_t BaseObjectType::hash() const
+{
+ return _type_info.hash_code();
+}
+
+std::size_t ObjectTypeHasher::operator()(const BaseObjectType &object_type) const
+{
+ return object_type.hash();
+}
diff --git a/src/DI/object_type.hpp b/src/DI/object_type.hpp
new file mode 100644
index 0000000..f690a64
--- /dev/null
+++ b/src/DI/object_type.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <typeinfo>
+
+class BaseObjectType
+{
+public:
+ explicit BaseObjectType(const std::type_info &type_info);
+
+ bool operator==(const BaseObjectType &object_type) const;
+
+ [[nodiscard]] std::size_t hash() const;
+
+private:
+ const std::type_info &_type_info;
+};
+
+template <class Object>
+class ObjectType : public BaseObjectType
+{
+public:
+ ObjectType() : BaseObjectType(typeid(Object)) {}
+};
+
+class IObjectTypeHasher
+{
+public:
+ virtual std::size_t operator()(const BaseObjectType &object_type) const = 0;
+};
+
+class ObjectTypeHasher : public IObjectTypeHasher
+{
+public:
+ std::size_t operator()(const BaseObjectType &object_type) const override;
+};
diff --git a/src/DI/object_wrapper.hpp b/src/DI/object_wrapper.hpp
new file mode 100644
index 0000000..0ae66df
--- /dev/null
+++ b/src/DI/object_wrapper.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "DI/container.hpp"
+#include "DI/interfaces/wrapper.hpp"
+
+#include <memory>
+
+template <class Interface, class ObjectImpl>
+class ObjectWrapper : public IWrapper<std::shared_ptr<Interface>>
+{
+public:
+ explicit ObjectWrapper(const Container &container) : _container(container) {}
+
+ [[nodiscard]] std::shared_ptr<Interface> get() const;
+
+private:
+ const Container &_container;
+};
+
+#include "object_wrapper.tpp"
diff --git a/src/DI/object_wrapper.tpp b/src/DI/object_wrapper.tpp
new file mode 100644
index 0000000..7efefc4
--- /dev/null
+++ b/src/DI/object_wrapper.tpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "object_wrapper.hpp"
+
+template <class Interface, class ObjectImpl>
+std::shared_ptr<Interface> ObjectWrapper<Interface, ObjectImpl>::get() const
+{
+ return ObjectImpl::resolve(_container);
+}