PhotonVision C++ dev-v2025.0.0-beta-8-2-gbd1c5c03
Loading...
Searching...
No Matches
Packet.h
Go to the documentation of this file.
1/*
2 * Copyright (C) Photon Vision.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#pragma once
19
20#include <algorithm>
21#include <bit>
22#include <cstring>
23#include <iostream>
24#include <optional>
25#include <span>
26#include <string>
27#include <vector>
28
29#include <wpi/Demangle.h>
30#include <wpi/ct_string.h>
31#include <wpi/struct/Struct.h>
32
33namespace photon {
34
35class Packet;
36
37// Struct is where all our actual ser/de methods are implemented
38template <typename T>
39struct SerdeType {};
40
41template <typename T>
42concept PhotonStructSerializable = requires(Packet& packet, const T& value) {
43 typename SerdeType<typename std::remove_cvref_t<T>>;
44
45 // MD6sum of the message definition
46 {
47 SerdeType<typename std::remove_cvref_t<T>>::GetSchemaHash()
48 } -> std::convertible_to<std::string_view>;
49 // JSON-encoded message chema
50 {
51 SerdeType<typename std::remove_cvref_t<T>>::GetSchema()
52 } -> std::convertible_to<std::string_view>;
53 // Unpack myself from a packet
54 {
55 SerdeType<typename std::remove_cvref_t<T>>::Unpack(packet)
56 } -> std::same_as<typename std::remove_cvref_t<T>>;
57 // Pack myself into a packet
58 {
59 SerdeType<typename std::remove_cvref_t<T>>::Pack(packet, value)
60 } -> std::same_as<void>;
61};
62
63/**
64 * A packet that holds byte-packed data to be sent over NetworkTables.
65 */
66class Packet {
67 public:
68 /**
69 * Constructs an empty packet.
70 */
71 explicit Packet(int initialCapacity = 0) : packetData(initialCapacity) {}
72
73 /**
74 * Constructs a packet with the given data.
75 * @param data The packet data.
76 */
77 explicit Packet(std::vector<uint8_t> data);
78
79 /**
80 * Clears the packet and resets the read and write positions.
81 */
82 void Clear();
83
84 /**
85 * Returns the packet data.
86 * @return The packet data.
87 */
88 inline const std::vector<uint8_t>& GetData() { return packetData; }
89
90 /**
91 * Returns the number of bytes in the data.
92 * @return The number of bytes in the data.
93 */
94 inline size_t GetDataSize() const { return packetData.size(); }
95
96 template <typename T, typename... I>
97 requires wpi::StructSerializable<T, I...>
98 inline void Pack(const T& value) {
99 // as WPI struct stuff assumes constant data length - reserve at least
100 // enough new space for our new member
101 size_t newWritePos = writePos + wpi::GetStructSize<T, I...>();
102 packetData.resize(newWritePos);
103
104 wpi::PackStruct(
105 std::span<uint8_t>{packetData.begin() + writePos, packetData.end()},
106 value);
107
108 writePos = newWritePos;
109 }
110
111 template <typename T>
113 inline void Pack(const T& value) {
115 }
116
117 template <typename T, typename... I>
118 requires wpi::StructSerializable<T, I...>
119 inline T Unpack() {
120 // Unpack this member, starting at readPos
121 T ret = wpi::UnpackStruct<T, I...>(
122 std::span<uint8_t>{packetData.begin() + readPos, packetData.end()});
123 readPos += wpi::GetStructSize<T, I...>();
124 return ret;
125 }
126
127 template <typename T>
129 inline T Unpack() {
131 }
132
133 bool operator==(const Packet& right) const;
134 bool operator!=(const Packet& right) const;
135
136 private:
137 // Data stored in the packet
138 std::vector<uint8_t> packetData{};
139
140 size_t readPos = 0;
141 size_t writePos = 0;
142};
143
144template <typename T>
145concept arithmetic = std::integral<T> || std::floating_point<T>;
146
147// support encoding vectors
148template <typename T>
150struct SerdeType<std::vector<T>> {
151 static std::vector<T> Unpack(Packet& packet) {
152 uint8_t len = packet.Unpack<uint8_t>();
153 std::vector<T> ret;
154 ret.reserve(len);
155 for (size_t i = 0; i < len; i++) {
156 ret.push_back(packet.Unpack<T>());
157 }
158 return ret;
159 }
160 static void Pack(Packet& packet, const std::vector<T>& value) {
161 packet.Pack<uint8_t>(value.size());
162 for (const auto& thing : value) {
163 packet.Pack<T>(thing);
164 }
165 }
166 static constexpr std::string_view GetSchemaHash() {
167 // quick hack lol
169 }
170
171 static constexpr std::string_view GetSchema() {
172 // TODO: this gets us the plain type name of T, but this is not schema JSON
173 // compliant!
174 return "TODO[?]";
175 }
176};
177
178// support encoding optional types
179template <typename T>
180 requires(PhotonStructSerializable<T> || arithmetic<T>)
181struct SerdeType<std::optional<T>> {
182 static std::optional<T> Unpack(Packet& packet) {
183 if (packet.Unpack<uint8_t>() == 1u) {
184 return packet.Unpack<T>();
185 } else {
186 return std::nullopt;
187 }
188 }
189 static void Pack(Packet& packet, const std::optional<T>& value) {
190 packet.Pack<uint8_t>(value.has_value());
191 if (value) {
192 packet.Pack<T>(*value);
193 }
194 }
195 static constexpr std::string_view GetSchemaHash() {
196 // quick hack lol
198 }
199
200 static constexpr std::string_view GetSchema() {
201 // TODO: this gets us the plain type name of T, but this is not schema JSON
202 // compliant!
203 return "TODO?";
204 }
205};
206
207} // namespace photon
A packet that holds byte-packed data to be sent over NetworkTables.
Definition Packet.h:66
void Pack(const T &value)
Definition Packet.h:113
T Unpack()
Definition Packet.h:129
size_t GetDataSize() const
Returns the number of bytes in the data.
Definition Packet.h:94
T Unpack()
Definition Packet.h:119
bool operator==(const Packet &right) const
bool operator!=(const Packet &right) const
Packet(int initialCapacity=0)
Constructs an empty packet.
Definition Packet.h:71
const std::vector< uint8_t > & GetData()
Returns the packet data.
Definition Packet.h:88
void Clear()
Clears the packet and resets the read and write positions.
void Pack(const T &value)
Definition Packet.h:98
Packet(std::vector< uint8_t > data)
Constructs a packet with the given data.
Definition Packet.h:42
Definition Packet.h:145
Definition VisionEstimation.h:32
static void Pack(Packet &packet, const std::optional< T > &value)
Definition Packet.h:189
static std::optional< T > Unpack(Packet &packet)
Definition Packet.h:182
static constexpr std::string_view GetSchema()
Definition Packet.h:200
static constexpr std::string_view GetSchemaHash()
Definition Packet.h:195
static constexpr std::string_view GetSchema()
Definition Packet.h:171
static std::vector< T > Unpack(Packet &packet)
Definition Packet.h:151
static constexpr std::string_view GetSchemaHash()
Definition Packet.h:166
static void Pack(Packet &packet, const std::vector< T > &value)
Definition Packet.h:160
Definition Packet.h:39