add ability of authomatic attribute-value type conversion (for user

given types!)
This commit is contained in:
2026-07-15 15:52:10 +03:00
parent 6e1ef26aa6
commit bdaaaab559
2 changed files with 105 additions and 27 deletions

View File

@@ -6,50 +6,71 @@ using namespace adc;
int main()
{
std::string id1 = "1", id2 = "2";
int i = 10;
double d = 8.1;
std::string s{"dwedjkwlk"};
AdcGenericDevice<> dev("DEV#1");
std::println("add RW-attr with id='{}' (val={})", id1, i);
dev.addAttr(
"1", [&i]() -> adc_result_t<int> { return i; },
id1, [&i]() -> adc_result_t<int> { return i; },
[&i](int ii) -> adc_error_t {
i = ii;
return AdcDeviceErrorCode::ERROR_OK;
});
},
std::tuple<double, int, long>{});
dev.addAttr("2", [&d]() -> adc_result_t<double> { return d; }, nullptr);
std::println("add RO-attr with id='{}' (val={})", id2, d);
dev.addAttr(id2, [&d]() -> adc_result_t<double> { return d; }, nullptr);
adc_result_t<int> ri = dev["1"];
std::print("get '{}'-attr value as native int:\t", id1);
adc_result_t<int> ri = dev[id1];
if (ri) {
std::println("dev[1] = {}", ri.value());
std::println("dev[{}] = {}", id1, ri.value());
} else {
std::println("cannot get dev[1] as int: {}", ri.error().message());
std::println("cannot get dev[{}] as int: {}", id1, ri.error().message());
}
auto err = dev["1"] = 77;
int ii = 77;
std::print("set '{}'-attr value to {} as native int:\t", id1, ii);
auto err = dev[id1] = ii;
if (err) {
std::println("cannot set dev[1] as int: {}", err.message());
std::println("cannot set dev[{}] as int: {}", id1, err.message());
} else {
std::println("OK");
}
adc_result_t<double> rd = dev["1"];
std::print("get '{}'-attr value as double:\t", id1);
adc_result_t<double> rd = dev[id1];
if (rd) {
std::println("dev[1] = {}", rd.value());
std::println("dev[{}] = {}", id1, rd.value());
} else {
std::println("cannot get dev[1] as double: {}", rd.error().message());
std::println("cannot get dev[{}] as double: {}", id1, rd.error().message());
}
ri = dev["1"];
if (ri) {
std::println("dev[1] = {}", ri.value());
} else {
std::println("cannot get dev[1] as int: {}", ri.error().message());
}
err = dev["2"] = 0.29817;
double dd = 33.333;
std::print("set '{}'-attr value to {} as double:\t", id1, dd);
err = dev[id1] = dd;
if (err) {
std::println("cannot set dev[2] as double: {}", err.message());
std::println("cannot set dev[{}] as double: {}", id1, err.message());
} else {
std::println("OK");
}
std::print("get '{}'-attr value as native int:\t", id1);
ri = dev[id1];
if (ri) {
std::println("dev[{}] = {}", id1, ri.value());
} else {
std::println("cannot get dev[{}] as int: {}", id1, ri.error().message());
}
err = dev[id2] = 0.29817;
if (err) {
std::println("cannot set dev[{}] as double: {}", id2, err.message());
}
return 0;

View File

@@ -133,8 +133,49 @@ class AdcGenericDevice
protected:
template <typename VT>
struct attr_t {
std::function<adc_result_t<VT>()> getter;
std::function<adc_error_t(VT const&)> setter;
std::function<adc_result_t<VT>()> getter{};
std::function<adc_error_t(VT const&)> setter{};
template <typename UT>
requires(requires(VT v, UT u) { v = u; } && !std::same_as<VT, UT>)
attr_t& operator=(attr_t<UT> const& other)
{
if (other.getter) {
getter = [&other]() -> adc_result_t<VT> {
auto val = other.getter();
if (val) {
return static_cast<VT>(val.value());
}
return std::unexpected(val.error());
};
} else { // write-only attribute
getter = nullptr;
}
if (other.setter) {
setter = [&other](VT const& v) { return other.setter(static_cast<UT>(v)); };
} else { // read-only attribute
setter = nullptr;
}
return *this;
}
template <typename UT>
requires requires(VT v, UT u) { v = u; }
operator attr_t<UT>() const
{
return attr_t<UT>{.getter = [this]() -> adc_result_t<UT> {
auto val = getter();
if (val) {
return static_cast<UT>(val.value());
} else {
return std::unexpected(val.error());
}
},
.setter = [this](UT const& u) { return setter(static_cast<VT>(u)); }};
}
adc_error_t serialize(snplib::snplib_output_char_range_c auto& output,
snplib::snplib_serialization_params_c auto const& params)
@@ -200,7 +241,7 @@ protected:
template <typename VT>
adc_error_t operator=(VT&& val)
{
auto attr = _dev._attrs.template get<attr_t<std::decay_t<VT>>>(_id);
auto attr = _dev._attrs.template get<attr_t<std::remove_cvref_t<VT>>>(_id);
if (attr) {
if (attr.value().setter) {
return attr.value().setter(std::forward<VT>(val));
@@ -228,6 +269,22 @@ protected:
snplib::HeterogenMap<ATTR_ID_T> _attrs{};
public:
static constexpr std::tuple<bool,
char,
short,
int,
long,
long long,
unsigned char,
unsigned short,
unsigned int,
unsigned long,
unsigned long long,
float,
double,
long double>
arithmetic_t{};
typedef DEV_ID_T device_id_t;
typedef ATTR_ID_T attr_id_t;
typedef CMD_ID_T cmd_id_t;
@@ -255,9 +312,8 @@ public:
_commands.emplace(std::move(id), std::forward<ET>(exec_func));
}
// template <typename GT, typename ST, typename... VTs>
template <adclib_attr_getter_c GT, adclib_attr_setter_c ST>
void addAttr(ATTR_ID_T id, GT&& getter, ST&& setter)
template <typename GT, typename ST, typename... VTs>
void addAttr(ATTR_ID_T id, GT&& getter, ST&& setter, std::tuple<VTs...> = std::tuple<>{})
{
using v_t = snplib_attr_value_deduced_t<GT, ST>;
static_assert(!std::is_void_v<v_t>, "Getter and setter cannot be nullptr_t at the same time!");
@@ -266,7 +322,8 @@ public:
static_assert(std::invocable<ST, v_t const&>, "Invalid setter argument type!");
}
_attrs.push(std::move(id), attr_t<v_t>{.getter = std::forward<GT>(getter), .setter = std::forward<ST>(setter)});
_attrs.push(std::move(id), attr_t<v_t>{.getter = std::forward<GT>(getter), .setter = std::forward<ST>(setter)},
std::tuple<attr_t<VTs>...>{});
}
adc_error_t operator()(CMD_ID_T id)