Files
cpp-thirdparty/noarch/include/kangaru/detail/injected.hpp
Bassem Girgis 81b4b9e273 Initial commit
2018-12-20 17:34:07 -06:00

127 lines
3.0 KiB
C++

#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_INJECTED_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_INJECTED_HPP
#include "utils.hpp"
#include "single.hpp"
#include "traits.hpp"
namespace kgr {
struct Container;
namespace detail {
template<typename T, typename = void>
struct BaseInjectedHelper {
virtual ~BaseInjectedHelper() = default;
kgr::detail::Sink forward();
};
template<typename T>
struct BaseInjectedHelper<T, void_t<ServiceType<T>>> {
virtual ~BaseInjectedHelper() = default;
virtual ServiceType<T> forward() = 0;
};
template<typename T>
struct BaseInjected : BaseInjectedHelper<T> {};
template<typename T>
struct SingleInjected final : BaseInjected<T> {
friend struct kgr::Container;
template<typename... Args, enable_if_t<is_brace_constructible<T, Args...>::value, int> = 0>
explicit SingleInjected(Args&&... args) : _service{std::forward<Args>(args)...} {}
template<typename... Args, enable_if_t<!is_brace_constructible<T, Args...>::value && std::is_constructible<T, Args...>::value, int> = 0>
explicit SingleInjected(Args&&... args) : _service(std::forward<Args>(args)...) {}
ServiceType<T> forward() override {
return _service.forward();
}
private:
T& get() {
return _service;
}
const T& get() const {
return _service;
}
T _service;
};
template<typename Original, typename Service>
struct ServiceOverride final : BaseInjected<Service> {
explicit ServiceOverride(Original& service) : _service{service} {}
ServiceType<Service> forward() override {
return static_cast<ServiceType<Service>>(_service.forward());
}
private:
Original& _service;
};
template<typename T>
struct Injected final {
friend struct kgr::Container;
template<typename... Args, enable_if_t<is_brace_constructible<T, Args...>::value, int> = 0>
explicit Injected(Args&&... args) : _service{std::forward<Args>(args)...} {}
template<typename... Args, enable_if_t<!is_brace_constructible<T, Args...>::value && std::is_constructible<T, Args...>::value, int> = 0>
explicit Injected(Args&&... args) : _service(std::forward<Args>(args)...) {}
ServiceType<T> forward() {
return _service.forward();
}
private:
T& get() {
return _service;
}
const T& get() const {
return _service;
}
T _service;
};
template<typename>
struct original;
template<typename T>
struct original<BaseInjected<T>&> {
using type = T;
};
template<typename T>
struct original<Injected<T>&&> {
using type = T;
};
template<typename T>
using original_t = typename original<T>::type;
template<std::size_t n, typename F>
using injected_argument_t = original_t<function_argument_t<n, F>>;
} // namespace detail
template<typename T>
using Inject = typename std::conditional<!detail::is_service<T>::value || detail::is_single<T>::value,
detail::BaseInjected<T>&,
detail::Injected<T>&&>::type;
template<typename... Args>
std::tuple<detail::remove_rvalue_reference_t<Args>...> inject(Args&&... args) {
return std::tuple<detail::remove_rvalue_reference_t<Args>...>{std::forward<Args>(args)...};
}
} // namespace kgr
#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_INJECTED_HPP