[ntcore] Refactor meta-topic decoding from glass (#4809)

This commit is contained in:
Peter Johnson
2022-12-31 12:01:51 -08:00
committed by GitHub
parent b632b288a3
commit 1562eae74a
7 changed files with 666 additions and 150 deletions

View File

@@ -0,0 +1,210 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <fmt/format.h>
#include <wpi/MessagePack.h>
#include <wpi/mpack.h>
#include "ntcore_cpp.h"
using namespace mpack;
using namespace nt::meta;
static SubscriberOptions DecodeSubscriberOptions(mpack_reader_t& r) {
SubscriberOptions options;
uint32_t numMapElem = mpack_expect_map(&r);
for (uint32_t j = 0; j < numMapElem; ++j) {
std::string key;
mpack_expect_str(&r, &key);
if (key == "topicsonly") {
options.topicsOnly = mpack_expect_bool(&r);
} else if (key == "all") {
options.sendAll = mpack_expect_bool(&r);
} else if (key == "periodic") {
options.periodic = mpack_expect_float(&r);
} else if (key == "prefix") {
options.prefixMatch = mpack_expect_bool(&r);
} else {
// TODO: Save other options
mpack_discard(&r);
}
}
mpack_done_map(&r);
return options;
}
std::optional<std::vector<ClientPublisher>> nt::meta::DecodeClientPublishers(
std::span<const uint8_t> data) {
mpack_reader_t r;
mpack_reader_init_data(&r, data);
uint32_t numPub = mpack_expect_array_max(&r, 1000);
std::vector<ClientPublisher> publishers;
publishers.reserve(numPub);
for (uint32_t i = 0; i < numPub; ++i) {
ClientPublisher pub;
uint32_t numMapElem = mpack_expect_map(&r);
for (uint32_t j = 0; j < numMapElem; ++j) {
std::string key;
mpack_expect_str(&r, &key);
if (key == "uid") {
pub.uid = mpack_expect_i64(&r);
} else if (key == "topic") {
mpack_expect_str(&r, &pub.topic);
} else {
mpack_discard(&r);
}
}
mpack_done_map(&r);
publishers.emplace_back(std::move(pub));
}
mpack_done_array(&r);
if (mpack_reader_destroy(&r) == mpack_ok) {
return {std::move(publishers)};
} else {
return {};
}
}
std::optional<std::vector<ClientSubscriber>> nt::meta::DecodeClientSubscribers(
std::span<const uint8_t> data) {
mpack_reader_t r;
mpack_reader_init_data(&r, data);
uint32_t numSub = mpack_expect_array_max(&r, 1000);
std::vector<ClientSubscriber> subscribers;
subscribers.reserve(numSub);
for (uint32_t i = 0; i < numSub; ++i) {
ClientSubscriber sub;
uint32_t numMapElem = mpack_expect_map(&r);
for (uint32_t j = 0; j < numMapElem; ++j) {
std::string key;
mpack_expect_str(&r, &key);
if (key == "uid") {
sub.uid = mpack_expect_i64(&r);
} else if (key == "topics") {
uint32_t numPrefix = mpack_expect_array_max(&r, 100);
sub.topics.reserve(numPrefix);
for (uint32_t k = 0; k < numPrefix; ++k) {
std::string val;
if (mpack_expect_str(&r, &val) == mpack_ok) {
sub.topics.emplace_back(std::move(val));
}
}
mpack_done_array(&r);
} else if (key == "options") {
sub.options = DecodeSubscriberOptions(r);
} else {
mpack_discard(&r);
}
}
mpack_done_map(&r);
subscribers.emplace_back(std::move(sub));
}
mpack_done_array(&r);
if (mpack_reader_destroy(&r) == mpack_ok) {
return {std::move(subscribers)};
} else {
return {};
}
}
std::optional<std::vector<TopicPublisher>> nt::meta::DecodeTopicPublishers(
std::span<const uint8_t> data) {
mpack_reader_t r;
mpack_reader_init_data(&r, data);
uint32_t numPub = mpack_expect_array_max(&r, 1000);
std::vector<TopicPublisher> publishers;
publishers.reserve(numPub);
for (uint32_t i = 0; i < numPub; ++i) {
TopicPublisher pub;
uint32_t numMapElem = mpack_expect_map(&r);
for (uint32_t j = 0; j < numMapElem; ++j) {
std::string key;
mpack_expect_str(&r, &key);
if (key == "pubuid") {
pub.pubuid = mpack_expect_i64(&r);
} else if (key == "client") {
mpack_expect_str(&r, &pub.client);
} else {
mpack_discard(&r);
}
}
mpack_done_map(&r);
publishers.emplace_back(std::move(pub));
}
mpack_done_array(&r);
if (mpack_reader_destroy(&r) == mpack_ok) {
return {std::move(publishers)};
} else {
return {};
}
}
std::optional<std::vector<TopicSubscriber>> nt::meta::DecodeTopicSubscribers(
std::span<const uint8_t> data) {
mpack_reader_t r;
mpack_reader_init_data(&r, data);
uint32_t numSub = mpack_expect_array_max(&r, 1000);
std::vector<TopicSubscriber> subscribers;
subscribers.reserve(numSub);
for (uint32_t i = 0; i < numSub; ++i) {
TopicSubscriber sub;
uint32_t numMapElem = mpack_expect_map(&r);
for (uint32_t j = 0; j < numMapElem; ++j) {
std::string key;
mpack_expect_str(&r, &key);
if (key == "subuid") {
sub.subuid = mpack_expect_i64(&r);
} else if (key == "client") {
mpack_expect_str(&r, &sub.client);
} else if (key == "options") {
sub.options = DecodeSubscriberOptions(r);
} else {
mpack_discard(&r);
}
}
mpack_done_map(&r);
subscribers.emplace_back(std::move(sub));
}
mpack_done_array(&r);
if (mpack_reader_destroy(&r) == mpack_ok) {
return {std::move(subscribers)};
} else {
return {};
}
}
std::optional<std::vector<Client>> nt::meta::DecodeClients(
std::span<const uint8_t> data) {
mpack_reader_t r;
mpack_reader_init_data(&r, data);
uint32_t numClients = mpack_expect_array_max(&r, 100);
std::vector<Client> clients;
clients.reserve(numClients);
for (uint32_t i = 0; i < numClients; ++i) {
Client client;
uint32_t numMapElem = mpack_expect_map(&r);
for (uint32_t j = 0; j < numMapElem; ++j) {
std::string key;
mpack_expect_str(&r, &key);
if (key == "id") {
mpack_expect_str(&r, &client.id);
} else if (key == "conn") {
mpack_expect_str(&r, &client.conn);
} else if (key == "ver") {
client.version = mpack_expect_u16(&r);
} else {
mpack_discard(&r);
}
}
mpack_done_map(&r);
clients.emplace_back(std::move(client));
}
mpack_done_array(&r);
if (mpack_reader_destroy(&r) == mpack_ok) {
return {std::move(clients)};
} else {
return {};
}
}

View File

@@ -0,0 +1,138 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include <optional>
#include <vector>
#include "Value_internal.h"
#include "ntcore_cpp.h"
using namespace nt;
using namespace nt::meta;
static void ConvertToC(const SubscriberOptions& in,
NT_Meta_SubscriberOptions* out) {
out->periodic = in.periodic;
out->topicsOnly = in.topicsOnly;
out->sendAll = in.sendAll;
out->prefixMatch = in.prefixMatch;
}
static void ConvertToC(const TopicPublisher& in, NT_Meta_TopicPublisher* out) {
ConvertToC(in.client, &out->client);
out->pubuid = in.pubuid;
}
static void ConvertToC(const TopicSubscriber& in,
NT_Meta_TopicSubscriber* out) {
ConvertToC(in.client, &out->client);
out->subuid = in.subuid;
ConvertToC(in.options, &out->options);
}
static void ConvertToC(const ClientPublisher& in,
NT_Meta_ClientPublisher* out) {
out->uid = in.uid;
ConvertToC(in.topic, &out->topic);
}
static void ConvertToC(const ClientSubscriber& in,
NT_Meta_ClientSubscriber* out) {
out->uid = in.uid;
out->topics = ConvertToC<NT_String>(in.topics, &out->topicsCount);
ConvertToC(in.options, &out->options);
}
static void ConvertToC(const Client& in, NT_Meta_Client* out) {
ConvertToC(in.id, &out->id);
ConvertToC(in.conn, &out->conn);
out->version = in.version;
}
template <typename O, typename I>
static O* ConvertToC(const std::optional<std::vector<I>>& in, size_t* out_len) {
if (in) {
if (O* rv = ConvertToC<O>(*in, out_len)) {
return rv;
} else {
return static_cast<O*>(wpi::safe_malloc(0)); // return non-NULL
}
} else {
*out_len = 0;
return nullptr;
}
}
extern "C" {
struct NT_Meta_TopicPublisher* NT_Meta_DecodeTopicPublishers(
const uint8_t* data, size_t size, size_t* count) {
return ConvertToC<NT_Meta_TopicPublisher>(DecodeTopicPublishers({data, size}),
count);
}
struct NT_Meta_TopicSubscriber* NT_Meta_DecodeTopicSubscribers(
const uint8_t* data, size_t size, size_t* count) {
return ConvertToC<NT_Meta_TopicSubscriber>(
DecodeTopicSubscribers({data, size}), count);
}
struct NT_Meta_ClientPublisher* NT_Meta_DecodeClientPublishers(
const uint8_t* data, size_t size, size_t* count) {
return ConvertToC<NT_Meta_ClientPublisher>(
DecodeClientPublishers({data, size}), count);
}
struct NT_Meta_ClientSubscriber* NT_Meta_DecodeClientSubscribers(
const uint8_t* data, size_t size, size_t* count) {
return ConvertToC<NT_Meta_ClientSubscriber>(
DecodeClientSubscribers({data, size}), count);
}
struct NT_Meta_Client* NT_Meta_DecodeClients(const uint8_t* data, size_t size,
size_t* count) {
return ConvertToC<NT_Meta_Client>(DecodeClients({data, size}), count);
}
void NT_Meta_FreeTopicPublishers(struct NT_Meta_TopicPublisher* arr,
size_t count) {
for (size_t i = 0; i < count; ++i) {
std::free(arr[i].client.str);
}
std::free(arr);
}
void NT_Meta_FreeTopicSubscribers(struct NT_Meta_TopicSubscriber* arr,
size_t count) {
for (size_t i = 0; i < count; ++i) {
std::free(arr[i].client.str);
}
std::free(arr);
}
void NT_Meta_FreeClientPublishers(struct NT_Meta_ClientPublisher* arr,
size_t count) {
for (size_t i = 0; i < count; ++i) {
std::free(arr[i].topic.str);
}
std::free(arr);
}
void NT_Meta_FreeClientSubscribers(struct NT_Meta_ClientSubscriber* arr,
size_t count) {
for (size_t i = 0; i < count; ++i) {
NT_FreeStringArray(arr[i].topics, arr[i].topicsCount);
}
std::free(arr);
}
void NT_Meta_FreeClients(struct NT_Meta_Client* arr, size_t count) {
for (size_t i = 0; i < count; ++i) {
std::free(arr[i].id.str);
std::free(arr[i].conn.str);
}
std::free(arr);
}
} // extern "C"