14using Packet = std::vector<uint8_t>;
15using PacketSpan = std::span<const uint8_t>;
18enum class TypeId : uint8_t {
62template <
typename... Fields>
74template <
typename... Fields>
76 static constexpr TypeId value = TypeId::Record;
80struct TypeIdMap<bool> {
81 static constexpr TypeId value = TypeId::Boolean;
85struct TypeIdMap<std::string> {
86 static constexpr TypeId value = TypeId::String;
90struct TypeIdMap<double> {
91 static constexpr TypeId value = TypeId::Double;
95struct TypeIdMap<float> {
96 static constexpr TypeId value = TypeId::Float;
100struct TypeIdMap<uint8_t> {
101 static constexpr TypeId value = TypeId::Uint8;
105struct TypeIdMap<uint16_t> {
106 static constexpr TypeId value = TypeId::Uint16;
110struct TypeIdMap<uint32_t> {
111 static constexpr TypeId value = TypeId::Uint32;
115struct TypeIdMap<uint64_t> {
116 static constexpr TypeId value = TypeId::Uint64;
120struct TypeIdMap<int8_t> {
121 static constexpr TypeId value = TypeId::Int8;
125struct TypeIdMap<int16_t> {
126 static constexpr TypeId value = TypeId::Int16;
130struct TypeIdMap<int32_t> {
131 static constexpr TypeId value = TypeId::Int32;
135struct TypeIdMap<int64_t> {
136 static constexpr TypeId value = TypeId::Int64;
141 requires std::is_same_v<T, int>
143 static_assert(
sizeof(T) ==
sizeof(int32_t),
"VDP requires a 32-bit int");
144 static constexpr TypeId value = TypeId::Int32;
148template <TypeId FixedPo
intType,
typename Storage>
150 static constexpr TypeId type = FixedPointType;
183template <TypeId Id,
typename Storage>
185 static constexpr TypeId value = Id;
189template <
typename T,
typename =
void>
194struct HasTypeId<T, std::void_t<decltype(TypeIdMap<T>::value)>> : std::true_type {};
203template <
typename... Fields>
204struct IsField<Record<Fields...>> : std::true_type {};
206template <
typename... Fields>
208struct TypeIdMap<std::tuple<Fields...>> {
209 static constexpr TypeId value = TypeId::Record;
216template <TypeId Id,
typename Storage>
220std::string to_string(TypeId t);
233 Field(std::string name, T& value) : name_(std::move(name)), value_(value) {};
236 const std::string&
get_name()
const {
return name_; };
242 const TypeId
get_type()
const {
return TypeIdMap<T>::value; }
250 out.push_back(
static_cast<uint8_t
>(
get_type()));
251 out.insert(out.end(), name_.begin(), name_.end());
263 if constexpr (std::is_same_v<T, std::string>) {
264 VDP::Packet out(value_.begin(), value_.end());
268 VDP::Packet out(
sizeof(T));
269 std::memcpy(out.data(), &value_,
sizeof(T));
279 if constexpr (std::is_same_v<T, std::string>) {
282 auto str_end = std::find(packet_in.begin(), packet_in.end(), uint8_t(0));
284 auto length = str_end - packet_in.begin();
286 value_.assign(packet_in.begin(), str_end);
294 std::memcpy(&value_, packet_in.data(),
sizeof(T));
303 std::string out = std::string(depth * 2,
' ') + name_ +
" : ";
306 if constexpr (std::is_same_v<T, std::string>) {
309 }
else if constexpr (std::is_same_v<T, bool>) {
311 return out + (value_ ?
"true" :
"false");
312 }
else if constexpr (std::is_integral_v<T>) {
318 if (std::is_signed_v<T>) {
319 return out + std::to_string(
static_cast<int64_t
>(value_));
321 return std::to_string(
static_cast<uint64_t
>(value_));
323 }
else if constexpr (std::is_floating_point_v<T>) {
325 return std::to_string(value_);
332 if constexpr (std::is_signed_v<
decltype(value_.raw_value)>) {
333 return std::to_string(
static_cast<int64_t
>(value_.raw_value));
335 return std::to_string(
static_cast<uint64_t
>(value_.raw_value));
339 static_assert(std::is_same_v<T, void>,
"data_to_string does not support this type");
345 return std::string(depth * 2,
' ') + name_ +
" : " + VDP::to_string(
get_type());
355Field(std::string, T&) -> Field<T>;
361template <
typename... Fields>
365 "Record elements must all be Field or Record objects");
373 explicit Record(std::string name, Fields&... fields)
374 : name_(std::move(name)), value_(fields...) {}
377 const std::string&
get_name()
const {
return name_; }
386 static constexpr std::size_t
size() {
return sizeof...(Fields); }
389 template <std::
size_t I>
391 return std::get<I>(value_);
396 static_assert(
sizeof...(Fields) <= 255,
"A record cannot contain more than 255 fields");
400 out.push_back(
static_cast<uint8_t
>(TypeId::Record));
403 out.insert(out.end(), this->get_name().begin(), this->get_name().end());
406 out.push_back((
static_cast<uint8_t
>(
size())));
410 [&](
const auto&... fields) {
414 Packet field_schema = fields.serialize_schema();
416 out.insert(out.end(), field_schema.begin(), field_schema.end());
432 [&](
const auto&... fields) {
436 Packet field_schema = fields.serialize_data();
438 out.insert(out.end(), field_schema.begin(), field_schema.end());
448 std::size_t offset = 0;
451 [&](
auto&... fields) {
454 auto read_bytes = fields.apply_update(pac_in.subspan(offset));
455 offset += read_bytes;
468 std::string out = std::string(depth * 2,
' ') + this->
get_name() +
" : {\n";
475 [&](
const auto&... fields) {
476 ([&] { out += fields.data_to_string(depth + 1) +=
",\n"; }(), ...);
479 out += std::string(depth * 2,
' ') +
"}";
488 std::string out = std::string(depth * 2,
' ') + this->
get_name() +
" : record {\n";
495 [&](
const auto&... fields) {
496 ([&] { out += fields.schema_to_string(depth + 1) +
",\n"; }(), ...);
499 out += std::string(depth * 2,
' ') +
"}";
505 std::tuple<Fields&...> value_;
509template <
typename... Fields>
510Record(std::string, Fields&...) -> Record<Fields...>;
Field proto.
Definition types.h:224
std::string schema_to_string(std::size_t depth=0) const
Gets the field's schema as a string.
Definition types.h:344
VDP::Packet serialize_schema() const
Serializes the field's schema in the form of a VDP::Packet.
Definition types.h:248
std::string data_to_string(std::size_t depth=0) const
Gets the field's data as a string.
Definition types.h:301
Field(std::string name, T &value)
Constructor for a field, a form of data to be sent to the debug board.
Definition types.h:233
const std::string & get_name() const
Gets the name of the field.
Definition types.h:236
const TypeId get_type() const
Gets the type of the field in the form of a TypeId enum.
Definition types.h:242
VDP::Packet serialize_data() const
Serializes the field's data in the form of a VDP::Packet.
Definition types.h:261
size_t apply_update(const VDP::PacketSpan packet_in)
Deserializes a packet's data and applies it to the field.
Definition types.h:278
const T & get_value() const
Gets the value currently stored by the field.
Definition types.h:239
Record proto.
Definition types.h:362
VDP::Packet serialize_data() const
Serializes the record's data in the form of a VDP::Packet.
Definition types.h:428
std::string data_to_string(std::size_t depth=0) const
Converts a record's held data to a human readable string.
Definition types.h:467
std::string schema_to_string(std::size_t depth=0) const
converts a record's schema to a human readable string
Definition types.h:487
size_t apply_update(VDP::PacketSpan pac_in)
Deserializes a packet of data and applies it to the Record's fields.
Definition types.h:447
Record(std::string name, Fields &... fields)
Constructs a Record, a field that contains a tuple of other fields.
Definition types.h:373
TypeId get_type() const
Gets the TypeId of the record.
Definition types.h:380
const std::string & get_name() const
Gets the name of the record.
Definition types.h:377
static constexpr std::size_t size()
Getsthe size of the held tuple.
Definition types.h:386
VDP::Packet serialize_schema() const
Serializes the record's schema in the form of a VDP::Packet.
Definition types.h:395
const auto & get() const
Gets the field at a specified index of the held tuple.
Definition types.h:390
const auto & get_value() const
Gets the value stored by the record.
Definition types.h:383
Template for fixed point types.
Definition types.h:149
Primary template to check if a type has an associated id.
Definition types.h:190
Check for if a held field type is a Field.
Definition types.h:198
Check for if a held field type is a fixed point type.
Definition types.h:214