[wpiutil] Struct: Add info template parameter pack (#6086)

This allows using Struct in a dynamically typed environment by passing
additional information to the Struct serialization functions.
This commit is contained in:
Peter Johnson
2023-12-27 07:52:18 -08:00
committed by GitHub
parent e07de37e64
commit 6a2d3c30a6
9 changed files with 995 additions and 316 deletions

View File

@@ -12,23 +12,35 @@
namespace {
struct Inner {
int a;
int b;
int a = 0;
int b = 0;
};
struct Outer {
Inner inner;
int c;
int c = 0;
};
struct Inner2 {
int a;
int b;
int a = 0;
int b = 0;
};
struct Outer2 {
Inner2 inner;
int c;
int c = 0;
};
struct ThingA {
int x = 0;
};
struct ThingB {
int x = 0;
};
struct Info1 {
int info = 0;
};
} // namespace
@@ -110,6 +122,36 @@ struct wpi::Struct<Outer2> {
}
};
template <>
struct wpi::Struct<ThingA> {
static constexpr std::string_view GetTypeString() { return "struct:ThingA"; }
static constexpr size_t GetSize() { return 1; }
static constexpr std::string_view GetSchema() { return "uint8 value"; }
static ThingA Unpack(std::span<const uint8_t> data) {
return ThingA{.x = data[0]};
}
static void Pack(std::span<uint8_t> data, const ThingA& value) {
data[0] = value.x;
}
};
template <>
struct wpi::Struct<ThingB, Info1> {
static constexpr std::string_view GetTypeString(const Info1&) {
return "struct:ThingB";
}
static constexpr size_t GetSize(const Info1&) { return 1; }
static constexpr std::string_view GetSchema(const Info1&) {
return "uint8 value";
}
static ThingB Unpack(std::span<const uint8_t> data, const Info1&) {
return ThingB{.x = data[0]};
}
static void Pack(std::span<uint8_t> data, const ThingB& value, const Info1&) {
data[0] = value.x;
}
};
namespace nt {
class StructTest : public ::testing::Test {
@@ -293,4 +335,116 @@ TEST_F(StructTest, InnerArrayNonconstexpr) {
ASSERT_EQ(vals[0].value[0].b, 2);
}
TEST_F(StructTest, StructA) {
nt::StructTopic<ThingA> topic = inst.GetStructTopic<ThingA>("a");
nt::StructPublisher<ThingA> pub = topic.Publish();
nt::StructPublisher<ThingA> pub2 = topic.PublishEx({{}});
nt::StructSubscriber<ThingA> sub = topic.Subscribe({});
nt::StructEntry<ThingA> entry = topic.GetEntry({});
pub.SetDefault({});
pub.Set({}, 5);
sub.Get();
sub.Get({});
sub.GetAtomic();
sub.GetAtomic({});
entry.SetDefault({});
entry.Set({}, 6);
entry.Get({});
}
TEST_F(StructTest, StructArrayA) {
nt::StructArrayTopic<ThingA> topic = inst.GetStructArrayTopic<ThingA>("a");
nt::StructArrayPublisher<ThingA> pub = topic.Publish();
nt::StructArrayPublisher<ThingA> pub2 = topic.PublishEx({{}});
nt::StructArraySubscriber<ThingA> sub = topic.Subscribe({});
nt::StructArrayEntry<ThingA> entry = topic.GetEntry({});
pub.SetDefault({{ThingA{}, ThingA{}}});
pub.Set({{ThingA{}, ThingA{}}}, 5);
sub.Get();
sub.Get({});
sub.GetAtomic();
sub.GetAtomic({});
entry.SetDefault({{ThingA{}, ThingA{}}});
entry.Set({{ThingA{}, ThingA{}}}, 6);
entry.Get({});
}
TEST_F(StructTest, StructFixedArrayA) {
nt::StructTopic<std::array<ThingA, 2>> topic =
inst.GetStructTopic<std::array<ThingA, 2>>("a");
nt::StructPublisher<std::array<ThingA, 2>> pub = topic.Publish();
nt::StructPublisher<std::array<ThingA, 2>> pub2 = topic.PublishEx({{}});
nt::StructSubscriber<std::array<ThingA, 2>> sub = topic.Subscribe({});
nt::StructEntry<std::array<ThingA, 2>> entry = topic.GetEntry({});
std::array<ThingA, 2> arr;
pub.SetDefault(arr);
pub.Set(arr, 5);
sub.Get();
sub.Get(arr);
sub.GetAtomic();
sub.GetAtomic(arr);
entry.SetDefault(arr);
entry.Set(arr, 6);
entry.Get(arr);
}
TEST_F(StructTest, StructB) {
Info1 info;
nt::StructTopic<ThingB, Info1> topic =
inst.GetStructTopic<ThingB, Info1>("b", info);
nt::StructPublisher<ThingB, Info1> pub = topic.Publish();
nt::StructPublisher<ThingB, Info1> pub2 = topic.PublishEx({{}});
nt::StructSubscriber<ThingB, Info1> sub = topic.Subscribe({});
nt::StructEntry<ThingB, Info1> entry = topic.GetEntry({});
pub.SetDefault({});
pub.Set({}, 5);
sub.Get();
sub.Get({});
sub.GetAtomic();
sub.GetAtomic({});
entry.SetDefault({});
entry.Set({}, 6);
entry.Get({});
}
TEST_F(StructTest, StructArrayB) {
Info1 info;
nt::StructArrayTopic<ThingB, Info1> topic =
inst.GetStructArrayTopic<ThingB, Info1>("b", info);
nt::StructArrayPublisher<ThingB, Info1> pub = topic.Publish();
nt::StructArrayPublisher<ThingB, Info1> pub2 = topic.PublishEx({{}});
nt::StructArraySubscriber<ThingB, Info1> sub = topic.Subscribe({});
nt::StructArrayEntry<ThingB, Info1> entry = topic.GetEntry({});
pub.SetDefault({{ThingB{}, ThingB{}}});
pub.Set({{ThingB{}, ThingB{}}}, 5);
sub.Get();
sub.Get({});
sub.GetAtomic();
sub.GetAtomic({});
entry.SetDefault({{ThingB{}, ThingB{}}});
entry.Set({{ThingB{}, ThingB{}}}, 6);
entry.Get({});
}
TEST_F(StructTest, StructFixedArrayB) {
Info1 info;
nt::StructTopic<std::array<ThingB, 2>, Info1> topic =
inst.GetStructTopic<std::array<ThingB, 2>, Info1>("b", info);
nt::StructPublisher<std::array<ThingB, 2>, Info1> pub = topic.Publish();
nt::StructPublisher<std::array<ThingB, 2>, Info1> pub2 =
topic.PublishEx({{}});
nt::StructSubscriber<std::array<ThingB, 2>, Info1> sub = topic.Subscribe({});
nt::StructEntry<std::array<ThingB, 2>, Info1> entry = topic.GetEntry({});
std::array<ThingB, 2> arr;
pub.SetDefault(arr);
pub.Set(arr, 5);
sub.Get();
sub.Get(arr);
sub.GetAtomic();
sub.GetAtomic(arr);
entry.SetDefault(arr);
entry.Set(arr, 6);
entry.Get(arr);
}
} // namespace nt