From 7226f236dca196b0472c3cd7d8161c6013c73da3 Mon Sep 17 00:00:00 2001 From: mosure Date: Mon, 12 Apr 2021 22:06:00 -0700 Subject: [PATCH] store inspection injectable dependencies as type alias --- include/mosure/injectable.hpp | 2 +- include/mosure/resolver.hpp | 2 +- single_include/mosure/inversify.hpp | 700 ++++++++++++++++++---------- 3 files changed, 451 insertions(+), 253 deletions(-) diff --git a/include/mosure/injectable.hpp b/include/mosure/injectable.hpp index 4ba297b..fd04c15 100644 --- a/include/mosure/injectable.hpp +++ b/include/mosure/injectable.hpp @@ -17,7 +17,7 @@ struct Inject { ); #ifdef INVERSIFY_BINDING_INSPECTION - inline static std::tuple dependencies; + using value = std::tuple; #endif template diff --git a/include/mosure/resolver.hpp b/include/mosure/resolver.hpp index f47666f..5ba5211 100644 --- a/include/mosure/resolver.hpp +++ b/include/mosure/resolver.hpp @@ -159,7 +159,7 @@ class AutoResolverBase return dep_tuple; }; - return std::apply(unroll, inversify::Injectable::dependencies); + return std::apply(unroll, typename inversify::Injectable::value{}); } #endif }; diff --git a/single_include/mosure/inversify.hpp b/single_include/mosure/inversify.hpp index b29a164..dc58f30 100644 --- a/single_include/mosure/inversify.hpp +++ b/single_include/mosure/inversify.hpp @@ -58,15 +58,15 @@ SOFTWARE. namespace mosure::inversify { - template - struct Symbol { - static_assert( - !std::is_abstract(), - "inversify::Container cannot bind/get abstract class value (use a smart pointer instead)." - ); +template +struct Symbol { + static_assert( + !std::is_abstract(), + "inversify::Container cannot bind/get abstract class value (use a smart pointer instead)." + ); - using value = Interface; - }; + using value = Interface; +}; } @@ -74,32 +74,32 @@ namespace mosure::inversify { namespace mosure::inversify { - template < - typename T, - typename... SymbolTypes - > - class BindingTo; - - template < - template class Implementation, - typename... SymbolTypes - > - class IContainer { - public: - template - inversify::BindingTo& bind() { - auto crtpImplementation = static_cast *>(this); - - return crtpImplementation->template bind(); - } - - template - typename T::value get() { - auto crtpImplementation = static_cast *>(this); - - return crtpImplementation->template get(); - } - }; +template < + typename T, + typename... SymbolTypes +> +class BindingTo; + +template < + template class Implementation, + typename... SymbolTypes +> +class IContainer { +public: + template + inversify::BindingTo& bind() { + auto crtpImplementation = static_cast *>(this); + + return crtpImplementation->template bind(); + } + + template + typename T::value get() { + auto crtpImplementation = static_cast *>(this); + + return crtpImplementation->template get(); + } +}; } @@ -107,13 +107,13 @@ namespace mosure::inversify { namespace mosure::inversify { - template - class Container; +template +class Container; - template - struct Context { - inversify::IContainer& container; - }; +template +struct Context { + inversify::IContainer& container; +}; } @@ -128,18 +128,25 @@ namespace mosure::inversify { namespace mosure::inversify { - template - using Factory = std::function&)>; +template +using Factory = std::function&)>; } // #include +#include #include #include #include +#ifdef INVERSIFY_BINDING_INSPECTION +#include +#include +#include +#endif + // #include // #include @@ -165,211 +172,402 @@ namespace mosure::inversify { namespace mosure::inversify::meta { - template< - typename T, - typename... Types - > - inline constexpr bool contains_v = std::disjunction_v< - std::is_same... - >; +template< + typename T, + typename... Types +> +inline constexpr bool contains_v = std::disjunction_v< + std::is_same... +>; - template - struct is_empty : std::false_type { }; +template +struct is_empty : std::false_type { }; - template<> - struct is_empty<> : std::true_type { }; +template<> +struct is_empty<> : std::true_type { }; - template - inline constexpr bool is_empty_v = is_empty::value; +template +inline constexpr bool is_empty_v = is_empty::value; - template < - typename T, - template typename Template - > - struct is_specialization : std::false_type { }; +template < + typename T, + template typename Template +> +struct is_specialization : std::false_type { }; - template < - template typename Template, - typename... Args - > - struct is_specialization, Template> : std::true_type { }; +template < + template typename Template, + typename... Args +> +struct is_specialization, Template> : std::true_type { }; - template - struct is_unique_ptr : std::false_type { }; +template +inline constexpr bool valid_symbol_types_v = std::conjunction_v< + meta::is_specialization... +> || std::conjunction_v< + std::is_base_of, Types>... +>; - template < - typename T, - typename D - > - struct is_unique_ptr> : std::true_type { }; +} - template - struct is_shared_ptr : std::false_type { }; - template - struct is_shared_ptr> : std::true_type { }; +namespace mosure::inversify { - template - inline constexpr bool valid_symbol_types_v = std::conjunction_v< - meta::is_specialization... - > || std::conjunction_v< - std::is_base_of, Types>... - >; +template +struct Inject { + static_assert( + meta::valid_symbol_types_v, + "inversify::Injectable dependencies must be of type inversify::Symbol" + ); + +#ifdef INVERSIFY_BINDING_INSPECTION + using value = std::tuple; +#endif + + template + inline static auto resolve(const inversify::Context& context) { + return std::make_tuple(context.container.template get()...); + } +}; + +template > +struct Injectable: Inject { }; } +// #include -namespace mosure::inversify { +#include +#include - template - struct Inject { - static_assert( - meta::valid_symbol_types_v, - "inversify::Injectable dependencies must be of type inversify::Symbol" - ); - template - inline static auto resolve(const inversify::Context& context) { - return std::make_tuple(context.container.template get()...); - } - }; +namespace mosure::inversify::exceptions { - template > - struct Injectable: Inject { }; +struct ResolutionException : public std::runtime_error { + explicit ResolutionException(const std::string& msg) : std::runtime_error(msg) { } +}; } -// #include - namespace mosure::inversify { - template < - typename T, - typename U, - typename... SymbolTypes - > - inline static inversify::Factory get_auto_resolver() { - if constexpr (meta::is_unique_ptr::value) { - return [](const inversify::Context& context) { - auto expansion = [](auto&& ... deps){ - return std::make_unique(deps...); - }; - - return std::apply( - expansion, - std::move( - inversify::Injectable::resolve(context) - ) - ); - }; - } else if constexpr (meta::is_shared_ptr::value) { - return [](const inversify::Context& context) { - auto expansion = [](auto&& ... deps){ - return std::make_shared(deps...); - }; - - return std::apply( - expansion, - std::move( - inversify::Injectable::resolve(context) - ) - ); - }; - } else { - return [](const inversify::Context& context) { - return std::make_from_tuple( - inversify::Injectable::resolve(context) - ); - }; - } +#ifdef INVERSIFY_BINDING_INSPECTION +template +struct Dependency { + using symbol = Symbol; + + operator bool() { return dependent; } + + bool dependent; +}; + +template +class DependencyTuple { +public: + template + auto get() { + return std::get>(values); } -} -// #include + template + void set(bool value) { + std::get>(values).dependent = value; + } + std::tuple< + inversify::Dependency< + SymbolTypes + >... + > values; +}; +#endif -#include -#include +template < + typename T, + typename... SymbolTypes +> +class Resolver { +public: + inline virtual T resolve(const inversify::Context&) = 0; -namespace mosure::inversify::exceptions { +#ifdef INVERSIFY_BINDING_INSPECTION + inline virtual std::string getResolverLabel() const = 0; - struct ResolutionException : public std::runtime_error { - explicit ResolutionException(const std::string& msg) : std::runtime_error(msg) { } + inline virtual std::string getImplementationLabel() const { + return typeid(T).name(); }; + inline virtual inversify::DependencyTuple getDependencies() const { + return DependencyTuple{}; + } +#endif +}; + +template < + typename T, + typename... SymbolTypes +> +using ResolverPtr = std::shared_ptr>; + + +template < + typename T, + typename... SymbolTypes +> +class ConstantResolver + : public Resolver { +public: + explicit ConstantResolver(T value) : value_(value) { } + + inline T resolve(const inversify::Context&) override { + return value_; + } + +#ifdef INVERSIFY_BINDING_INSPECTION + inline virtual std::string getResolverLabel() const override { + return "constant"; + } +#endif + +private: + T value_; +}; + + +template < + typename T, + typename... SymbolTypes +> +class DynamicResolver + : public Resolver { +public: + explicit DynamicResolver(inversify::Factory factory) : factory_(factory) { } + + inline T resolve(const inversify::Context& context) override { + return factory_(context); + } + +#ifdef INVERSIFY_BINDING_INSPECTION + inline virtual std::string getResolverLabel() const override { + return "dynamic"; + } +#endif + +private: + inversify::Factory factory_; +}; + + +template +class AutoResolver; + +template < + typename T, + typename U, + typename... SymbolTypes +> +class AutoResolverBase + : public Resolver { +public: +#ifdef INVERSIFY_BINDING_INSPECTION + inline virtual std::string getResolverLabel() const override { + return "auto"; + } + + inline virtual std::string getImplementationLabel() const override { + return typeid(U).name(); + } + + inline virtual inversify::DependencyTuple getDependencies() const { + auto unroll = [](auto&&... deps) { + DependencyTuple dep_tuple; + + auto enable_dep = [&dep_tuple](auto dep) { + dep_tuple.template set(true); + }; + (enable_dep(deps), ...); + + return dep_tuple; + }; + + return std::apply(unroll, typename inversify::Injectable::value{}); + } +#endif +}; + + +template < + typename T, + typename U, + typename... SymbolTypes +> +class AutoResolver + : public AutoResolverBase { +public: + inline virtual T resolve(const inversify::Context& context) override { + return std::make_from_tuple( + inversify::Injectable::template resolve(context) + ); + } +}; + + +// unique_ptr specialization +template < + typename T, + typename U, + typename... SymbolTypes +> +class AutoResolver, U, SymbolTypes...> + : public AutoResolverBase, U, SymbolTypes...> { +public: + inline std::unique_ptr resolve(const inversify::Context& context) override { + auto expansion = [&context](auto&& ... deps){ + return std::make_unique(deps...); + }; + + return std::apply( + expansion, + std::move( + inversify::Injectable::template resolve(context) + ) + ); + } +}; + + +// shared_ptr specialization +template < + typename T, + typename U, + typename... SymbolTypes +> +class AutoResolver, U, SymbolTypes...> + : public AutoResolverBase, U, SymbolTypes...> { +public: + inline std::shared_ptr resolve(const inversify::Context& context) override { + auto expansion = [&context](auto&& ... deps){ + return std::make_shared(deps...); + }; + + return std::apply( + expansion, + std::move( + inversify::Injectable::template resolve(context) + ) + ); + } +}; + + +template < + typename T, + typename... SymbolTypes +> +class CachedResolver + : public Resolver { +static_assert( + std::is_copy_constructible_v, + "inversify::CachedResolver requires a copy constructor. Are you caching a unique_ptr?" +); + +public: + explicit CachedResolver(ResolverPtr parent) : parent_(parent) { } + + inline T resolve(const inversify::Context& context) override { + if (!hasCached_) { + hasCached_ = true; + cached_ = parent_->resolve(context); + } + + return cached_; + } + +#ifdef INVERSIFY_BINDING_INSPECTION + inline virtual std::string getResolverLabel() const override { + return std::string("cached - ") + parent_->getResolverLabel(); + } + + inline virtual std::string getImplementationLabel() const override { + return parent_->getImplementationLabel(); + } +#endif + +private: + T cached_; + std::atomic hasCached_ { false }; + ResolverPtr parent_; +}; + } +// #include + namespace mosure::inversify { - template - class BindingScope { - public: - void inSingletonScope() { - static_assert( - std::is_copy_constructible::value, - "inversify::BindingScope singleton must have copy constructor" - ); - - this->factory_ = [this, factory = std::move(factory_)](auto& context) { - if (!this->cached_set_) { - this->cached_ = factory(context); - this->cached_set_ = true; - } - - return this->cached_; - }; - } - - protected: - T cached_; - bool cached_set_ { false }; - inversify::Factory factory_; - }; +template +class BindingScope { +public: + void inSingletonScope() { + resolver_ = std::make_shared>(resolver_); + } - template - class BindingTo - : public BindingScope - { - public: - void toConstantValue(T&& value) { - this->factory_ = [val = std::move(value)](auto&) { - return val; - }; - } - - BindingScope& toDynamicValue(inversify::Factory&& factory) { - this->factory_ = std::move(factory); - - return *this; - } - - template - BindingScope& to() { - this->factory_ = inversify::get_auto_resolver(); - - return *this; - } - }; +#ifdef INVERSIFY_BINDING_INSPECTION + auto getResolver() const { + return resolver_; + } +#endif + +protected: + inversify::ResolverPtr resolver_; +}; + +template +class BindingTo + : public BindingScope +{ +public: + void toConstantValue(T&& value) { + this->resolver_ = std::make_shared>(value); + } - template - class Binding - : public BindingTo - { - public: - inline typename T::value resolve(const inversify::Context& context) { - return this->factory_(context); - } - }; + BindingScope& toDynamicValue(inversify::Factory&& factory) { + this->resolver_ = std::make_shared>(factory); + + return *this; + } + + template + BindingScope& to() { + this->resolver_ = std::make_shared>(); + + return *this; + } +}; + +template +class Binding + : public BindingTo +{ +public: + inline typename T::value resolve(const inversify::Context& context) { + if (!this->resolver_) { + throw inversify::exceptions::ResolutionException("inversify::Resolver not found. Malformed binding."); + } + + return this->resolver_->resolve(context); + } +}; } @@ -390,56 +588,56 @@ namespace mosure::inversify { namespace mosure::inversify { - template - class Container - : public inversify::IContainer - { - public: - static_assert( - meta::valid_symbol_types_v, - "inversify::Container symbols must be of type inversify::Symbol" - ); - - static_assert( - !meta::is_empty_v, - "inversify::Container must register at least one symbol" - ); - - using BindingMap = std::tuple< - inversify::Binding< - SymbolTypes, - SymbolTypes... - >... - >; - - template - inline inversify::BindingTo& bind() { - static_assert( - meta::contains_v, - "inversify::Container symbol not registered" - ); - - return std::get< - inversify::Binding - >(bindings_); - } - - template - inline typename T::value get() { - static_assert( - meta::contains_v, - "inversify::Container symbol not registered" - ); - - return std::get< - inversify::Binding - >(bindings_).resolve(context_); - } - - private: - BindingMap bindings_ {}; - inversify::Context context_ { *this }; - }; +template +class Container + : public inversify::IContainer +{ +public: + static_assert( + meta::valid_symbol_types_v, + "inversify::Container symbols must be of type inversify::Symbol" + ); + + static_assert( + !meta::is_empty_v, + "inversify::Container must register at least one symbol" + ); + + using BindingMap = std::tuple< + inversify::Binding< + SymbolTypes, + SymbolTypes... + >... + >; + + template + inline inversify::BindingTo& bind() { + static_assert( + meta::contains_v, + "inversify::Container symbol not registered" + ); + + return std::get< + inversify::Binding + >(bindings_); + } + + template + inline typename T::value get() { + static_assert( + meta::contains_v, + "inversify::Container symbol not registered" + ); + + return std::get< + inversify::Binding + >(bindings_).resolve(context_); + } + +private: + BindingMap bindings_ {}; + inversify::Context context_ { *this }; +}; }