...
This commit is contained in:
parent
75ec7065d2
commit
d9c87aed1f
@ -5,14 +5,21 @@ project(ADC LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
|
||||
set(ADC_COMMON_HEADERS
|
||||
common/adc_value_holder.h
|
||||
)
|
||||
|
||||
set(ADC_DEVICE_HEADERS
|
||||
device/adc_value_holder.h
|
||||
device/adc_device_attribute.h
|
||||
device/adc_device_command.h
|
||||
)
|
||||
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
add_library(${PROJECT_NAME} INTERFACE ${ADC_DEVICE_HEADERS})
|
||||
add_library(${PROJECT_NAME} INTERFACE ${ADC_COMMON_HEADERS} ${ADC_DEVICE_HEADERS}
|
||||
common/adc_traits.h)
|
||||
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_20)
|
||||
# target_link_libraries(${PROJECT_NAME} INTERFACE ASIO::ASIO)
|
||||
target_include_directories(
|
||||
|
||||
83
common/adc_traits.h
Normal file
83
common/adc_traits.h
Normal file
@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
/*
|
||||
|
||||
ABSTRACT DEVICE COMPONENTS LIBRARY
|
||||
|
||||
*/
|
||||
|
||||
|
||||
namespace adc::traits
|
||||
{
|
||||
|
||||
// deduce returned type of callable
|
||||
template <typename T>
|
||||
using adc_retval_t = std::invoke_result_t<std::remove_cvref_t<T>>;
|
||||
|
||||
|
||||
// helper classes
|
||||
template <typename... Ts>
|
||||
struct adc_func_traits_helper_t;
|
||||
|
||||
template <typename R>
|
||||
struct adc_func_traits_helper_t<R> {
|
||||
using ret_t = R;
|
||||
using args_t = std::tuple<>;
|
||||
using arg1_t = void;
|
||||
};
|
||||
|
||||
template <typename R, typename Arg, typename... Args>
|
||||
struct adc_func_traits_helper_t<R, Arg, Args...> {
|
||||
using ret_t = R;
|
||||
using args_t = std::tuple<Arg, Args...>;
|
||||
using arg1_t = Arg;
|
||||
};
|
||||
|
||||
|
||||
// callable traits
|
||||
|
||||
template <typename F>
|
||||
struct adc_func_traits;
|
||||
|
||||
template <typename R, typename... Args>
|
||||
struct adc_func_traits<R (*)(Args...)> : adc_func_traits_helper_t<R, Args...> {
|
||||
};
|
||||
|
||||
template <typename R, typename... Args>
|
||||
struct adc_func_traits<R(Args...)> : adc_func_traits_helper_t<R, Args...> {
|
||||
};
|
||||
|
||||
template <typename C, typename R, typename... Args>
|
||||
struct adc_func_traits<R (C::*)(Args...)> : adc_func_traits_helper_t<R, Args...> {
|
||||
};
|
||||
|
||||
template <typename C, typename R, typename... Args>
|
||||
struct adc_func_traits<R (C::*)(Args...) const> : adc_func_traits_helper_t<R, Args...> {
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
struct adc_func_traits : adc_func_traits<decltype(&F::operator())> {
|
||||
};
|
||||
|
||||
|
||||
// deduce type
|
||||
template <typename T>
|
||||
using adc_deduced_type =
|
||||
std::conditional_t<std::is_lvalue_reference_v<T> && !std::is_const_v<std::remove_reference_t<T>>,
|
||||
T,
|
||||
std::remove_cvref_t<T>>;
|
||||
|
||||
|
||||
// perfect-forwarding wrapper
|
||||
template <typename T, typename... Ts>
|
||||
auto adc_pf_wrapper(T&& v, Ts&&... vs)
|
||||
{
|
||||
return std::tuple<adc_deduced_type<T>, adc_deduced_type<Ts>...>(std::forward<T>(v), std::forward<Ts>(vs)...);
|
||||
}
|
||||
|
||||
|
||||
} // namespace adc::traits
|
||||
@ -11,11 +11,11 @@
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <ranges>
|
||||
#include <system_error>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <typeindex>
|
||||
|
||||
#include "adc_traits.h"
|
||||
|
||||
namespace adc
|
||||
{
|
||||
@ -46,70 +46,6 @@ namespace adc
|
||||
{
|
||||
|
||||
|
||||
namespace traits
|
||||
{
|
||||
|
||||
// deduce returned type of callable
|
||||
template <typename T>
|
||||
using adc_retval_t = std::invoke_result_t<std::remove_cvref_t<T>>;
|
||||
|
||||
|
||||
// helper classes
|
||||
template <typename... Ts>
|
||||
struct adc_func_traits_helper_t;
|
||||
|
||||
template <typename R>
|
||||
struct adc_func_traits_helper_t<R> {
|
||||
using ret_t = R;
|
||||
using args_t = std::tuple<>;
|
||||
using arg1_t = void;
|
||||
};
|
||||
|
||||
template <typename R, typename Arg, typename... Args>
|
||||
struct adc_func_traits_helper_t<R, Arg, Args...> {
|
||||
using ret_t = R;
|
||||
using args_t = std::tuple<Arg, Args...>;
|
||||
using arg1_t = Arg;
|
||||
};
|
||||
|
||||
|
||||
// callable traits
|
||||
|
||||
template <typename F>
|
||||
struct adc_func_traits;
|
||||
|
||||
template <typename R, typename... Args>
|
||||
struct adc_func_traits<R (*)(Args...)> : adc_func_traits_helper_t<R, Args...> {
|
||||
};
|
||||
|
||||
template <typename R, typename... Args>
|
||||
struct adc_func_traits<R(Args...)> : adc_func_traits_helper_t<R, Args...> {
|
||||
};
|
||||
|
||||
template <typename C, typename R, typename... Args>
|
||||
struct adc_func_traits<R (C::*)(Args...)> : adc_func_traits_helper_t<R, Args...> {
|
||||
};
|
||||
|
||||
template <typename C, typename R, typename... Args>
|
||||
struct adc_func_traits<R (C::*)(Args...) const> : adc_func_traits_helper_t<R, Args...> {
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
struct adc_func_traits : adc_func_traits<decltype(&F::operator())> {
|
||||
};
|
||||
|
||||
|
||||
// deduce type
|
||||
template <typename T>
|
||||
using adc_deduced_type =
|
||||
std::conditional_t<std::is_lvalue_reference_v<T> && !std::is_const_v<std::remove_reference_t<T>>,
|
||||
T,
|
||||
std::remove_cvref_t<T>>;
|
||||
|
||||
|
||||
} // namespace traits
|
||||
|
||||
|
||||
|
||||
// error category
|
||||
struct AdcValueHolderErrorCategory : public std::error_category {
|
||||
@ -161,7 +97,7 @@ class AdcValueHolder
|
||||
{
|
||||
protected:
|
||||
template <typename T>
|
||||
using arg_t = typename traits::adc_func_traits<T>::arg1_t;
|
||||
using arg_t = typename traits::adc_func_traits<T>::ret_t;
|
||||
|
||||
std::function<void(std::any&)> _getterWrapper;
|
||||
std::function<void(const std::any&)> _setterWrapper;
|
||||
@ -189,8 +125,7 @@ public:
|
||||
static_assert(std::is_same_v<value_t, void>, "THE getter MUST NOT RETURN void type!!!");
|
||||
|
||||
using g_t = decltype(getter);
|
||||
_getterWrapper = [wrapper =
|
||||
std::tuple<traits::adc_deduced_type<g_t>>(std::forward<g_t>(getter))](std::any& val) {
|
||||
_getterWrapper = [wrapper = traits::adc_pf_wrapper(std::forward<g_t>(getter))](std::any& val) {
|
||||
auto& getter = std::get<0>(wrapper);
|
||||
val = getter();
|
||||
};
|
||||
@ -199,16 +134,15 @@ public:
|
||||
using vld_t = decltype(validator);
|
||||
using s_t = decltype(setter);
|
||||
|
||||
if constexpr (std::is_same_v<vld_t, decltype(AdcValueHolderDummyValidator)>) {
|
||||
_setterWrapper = [wrapper = std::tuple<traits::adc_deduced_type<s_t>>(std::forward<s_t>(setter)),
|
||||
this](const std::any& val) {
|
||||
if constexpr (std::is_same_v<vld_t, decltype(AdcValueHolderDummyValidator)>) { // no validation
|
||||
_setterWrapper = [wrapper = traits::adc_pf_wrapper(std::forward<s_t>(setter)), this](const std::any& val) {
|
||||
auto& setter = std::get<0>(wrapper);
|
||||
|
||||
setter(std::any_cast<value_t>(val));
|
||||
};
|
||||
} else {
|
||||
_setterWrapper = [wrapper = std::tuple<traits::adc_deduced_type<s_t>, traits::adc_deduced_type<vld_t>>(
|
||||
std::forward<s_t>(setter), std::forward<vld_t>(validator)),
|
||||
_setterWrapper = [wrapper =
|
||||
traits::adc_pf_wrapper(std::forward<s_t>(setter), std::forward<vld_t>(validator)),
|
||||
this](const std::any& val) {
|
||||
auto& setter = std::get<0>(wrapper);
|
||||
auto& validator = std::get<1>(wrapper);
|
||||
@ -239,6 +173,17 @@ public:
|
||||
|
||||
/* PUBLIC METHODS */
|
||||
|
||||
|
||||
std::type_index valueTypeIndex() const { return _internalTypeIndex; }
|
||||
|
||||
|
||||
std::vector<std::type_index> convTypeIndices()
|
||||
{
|
||||
auto kv = std::views::keys(_convertFromInternal);
|
||||
return {kv.begin(), kv.end()};
|
||||
}
|
||||
|
||||
|
||||
template <typename UT>
|
||||
AdcValueHolder& addConvertFunc(std::invocable<std::any&> auto&& func_to_internal,
|
||||
std::invocable<std::any&> auto&& func_from_internal)
|
||||
1
device/adc_device_attribute.h
Normal file
1
device/adc_device_attribute.h
Normal file
@ -0,0 +1 @@
|
||||
#pragma once
|
||||
117
device/adc_device_command.h
Normal file
117
device/adc_device_command.h
Normal file
@ -0,0 +1,117 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
/*
|
||||
|
||||
ABSTRACT DEVICE COMPONENTS LIBRARY
|
||||
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "../common/adc_value_holder.h"
|
||||
|
||||
/*
|
||||
|
||||
*/
|
||||
|
||||
namespace adc
|
||||
{
|
||||
|
||||
template <typename IdentT, typename SerializedT = std::string>
|
||||
class AdcDeviceCommand
|
||||
{
|
||||
protected:
|
||||
IdentT _ident;
|
||||
|
||||
std::unique_ptr<AdcValueHolder> _commandArgUptr;
|
||||
|
||||
std::function<void()> _execFuncWrapper;
|
||||
std::function<void(std::any&)> _deserializerWrapper;
|
||||
|
||||
public:
|
||||
typedef IdentT ident_t;
|
||||
typedef SerializedT serialized_t;
|
||||
|
||||
|
||||
template <typename ExecFuncT,
|
||||
typename DeserializerT,
|
||||
typename ValidatorT = decltype(AdcValueHolder::AdcValueHolderDummyValidator)>
|
||||
AdcDeviceCommand(const IdentT& ident,
|
||||
ExecFuncT&& exec_func,
|
||||
DeserializerT&& deserializer,
|
||||
ValidatorT&& validator = AdcValueHolder::AdcValueHolderDummyValidator)
|
||||
: _ident(ident), _commandArgUptr()
|
||||
{
|
||||
using sign_t = traits::adc_func_traits<ExecFuncT>;
|
||||
|
||||
static_assert(std::tuple_size_v<typename sign_t::args_t> > 1,
|
||||
"COMMAND EXECUTION FUNCTION MUST ACCEPT 0 OR EXACTLY 1 ARGUMENT!!!");
|
||||
|
||||
if constexpr (std::tuple_size_v<typename sign_t::args_t>) { // command with argument
|
||||
using value_t = typename sign_t::arg1_t;
|
||||
|
||||
static_assert(std::predicate<ValidatorT, const value_t&>, "INVALID TYPE OF VALIDATOR");
|
||||
|
||||
static_assert(std::invocable<DeserializerT, const SerializedT&>, "INVALID TYPE OF DESERIALIZER");
|
||||
static_assert(std::is_convertible_v<std::invoke_result_t<DeserializerT, const SerializedT&>, value_t>,
|
||||
"INVALID RETURN TYPE OF DESERIALIZER");
|
||||
|
||||
|
||||
auto command_arg = std::shared_ptr<value_t>(value_t());
|
||||
|
||||
_commandArgUptr = std::make_unique<AdcValueHolder>(
|
||||
[command_arg]() { return *command_arg; }, [command_arg](const value_t& value) { *command_arg = value; },
|
||||
std::forward<ValidatorT>(validator));
|
||||
|
||||
_execFuncWrapper = [wrapper = traits::adc_pf_wrapper(std::forward<ExecFuncT>(exec_func)), this]() {
|
||||
auto& exec_func = std::get<0>(wrapper);
|
||||
value_t val = *_commandArgUptr;
|
||||
exec_func(val);
|
||||
};
|
||||
|
||||
|
||||
_deserializerWrapper =
|
||||
[wrapper = traits::adc_pf_wrapper(std::forward<DeserializerT>(deserializer))](std::any& val) {
|
||||
auto& deserializer = std::get<0>(wrapper);
|
||||
val = std::make_any<value_t>(deserializer(std::any_cast<SerializedT>(val)));
|
||||
};
|
||||
|
||||
// setup only convert-to-native-value function (deserializer)
|
||||
_commandArgUptr->addConvertFunc<SerializedT>(std::forward<DeserializerT>(deserializer), []() {});
|
||||
} else { // command without argument (ignore deserializer and validator)
|
||||
_execFuncWrapper = std::forward<ExecFuncT>(exec_func);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual ~AdcDeviceCommand() = default;
|
||||
|
||||
|
||||
/* PUBLIC METHODS */
|
||||
|
||||
IdentT ident() const { return ident; }
|
||||
|
||||
|
||||
template <typename ValueT>
|
||||
void operator()(const ValueT& value)
|
||||
{
|
||||
if (_commandArgUptr) { // command with argument
|
||||
*_commandArgUptr = value;
|
||||
}
|
||||
_execFuncWrapper();
|
||||
}
|
||||
|
||||
|
||||
void operator()()
|
||||
{
|
||||
if (_commandArgUptr) { // command with argument
|
||||
throw 1;
|
||||
}
|
||||
|
||||
_execFuncWrapper();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace adc
|
||||
Loading…
x
Reference in New Issue
Block a user