-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathparse_config_glaze.cpp
More file actions
338 lines (301 loc) · 12.1 KB
/
Copy pathparse_config_glaze.cpp
File metadata and controls
338 lines (301 loc) · 12.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
#define GLZ_DISABLE_ALWAYS_INLINE
#include <string_view>
#include <cstdlib>
#include <glaze/glaze.hpp>
#include "embedded_config.hpp"
// #define JSON_FUSION_BENCHMARK_ADDITIONAL_MODELS
#ifdef JSON_FUSION_BENCHMARK_ADDITIONAL_MODELS
#include "additional_models.hpp"
#endif
// Glaze metadata with validation constraints matching JsonFusion's validations
// Using single error message for fairness (JsonFusion uses generic error codes, not custom messages)
#define ERR "err"
template <std::size_t N>
constexpr bool is_non_empty(const std::array<char, N>& arr) { return arr[0] != '\0'; }
// Motor: position and vel_limits range validation
template <>
struct glz::meta<embedded_benchmark::EmbeddedConfig::Controller::Motor> {
using T = embedded_benchmark::EmbeddedConfig::Controller::Motor;
static constexpr auto validate_position = [](const T&, const std::array<double, 3>& pos) {
for (const auto& v : pos) if (v < -1000.0 || v > 1000.0) return false;
return true;
};
static constexpr auto validate_vel_limits = [](const T&, const std::array<float, 3>& vel) {
for (const auto& v : vel) if (v < -1000.0f || v > 1000.0f) return false;
return true;
};
static constexpr auto value = object(
&T::id, &T::name,
"position", read_constraint<&T::position, validate_position, ERR>,
"vel_limits", read_constraint<&T::vel_limits, validate_vel_limits, ERR>,
&T::inverted
);
};
// Sensor: range_min and range_max validation
template <>
struct glz::meta<embedded_benchmark::EmbeddedConfig::Controller::Sensor> {
using T = embedded_benchmark::EmbeddedConfig::Controller::Sensor;
static constexpr auto validate_range_min = [](const T&, float v) { return v >= -100.0f && v <= 100000.0f; };
static constexpr auto validate_range_max = [](const T&, double v) { return v >= -1000.0 && v <= 100000.0; };
static constexpr auto value = object(
&T::type, &T::model,
"range_min", read_constraint<&T::range_min, validate_range_min, ERR>,
"range_max", read_constraint<&T::range_max, validate_range_max, ERR>,
&T::active
);
};
// Controller: loop_hz range, motors_count/sensors_count min 1
template <>
struct glz::meta<embedded_benchmark::EmbeddedConfig::Controller> {
using T = embedded_benchmark::EmbeddedConfig::Controller;
static constexpr auto validate_loop_hz = [](const T&, int v) { return v >= 10 && v <= 10000; };
static constexpr auto validate_motors_count = [](const T&, size_t v) { return v >= 1; };
static constexpr auto validate_sensors_count = [](const T&, size_t v) { return v >= 1; };
static constexpr auto value = object(
&T::name,
"loop_hz", read_constraint<&T::loop_hz, validate_loop_hz, ERR>,
&T::motors,
"motors_count", read_constraint<&T::motors_count, validate_motors_count, ERR>,
&T::sensors,
"sensors_count", read_constraint<&T::sensors_count, validate_sensors_count, ERR>
);
};
// Target: device_id required
template <>
struct glz::meta<embedded_benchmark::RpcCommand::Target> {
using T = embedded_benchmark::RpcCommand::Target;
static constexpr auto value = object(&T::device_id, &T::subsystem);
static constexpr bool requires_key(std::string_view key, bool) {
return key == "device_id";
}
};
// Parameter: key required, float_value range validation
template <>
struct glz::meta<embedded_benchmark::RpcCommand::Parameter> {
using T = embedded_benchmark::RpcCommand::Parameter;
static constexpr auto validate_float = [](const T&, const std::optional<double>& v) {
return !v.has_value() || (*v >= -1000000.0 && *v <= 1000000.0);
};
static constexpr auto value = object(
&T::key, &T::int_value,
// "float_value", read_constraint<&T::float_value, validate_float, ERR>, // TODO: does not work for round-trip, need to report this to Glaze team
"float_value", &T::float_value,
&T::bool_value, &T::string_value
);
static constexpr bool requires_key(std::string_view key, bool) {
return key == "key";
}
};
// ExecutionOptions: timeout_ms required, range validations
template <>
struct glz::meta<embedded_benchmark::RpcCommand::ExecutionOptions> {
using T = embedded_benchmark::RpcCommand::ExecutionOptions;
static constexpr auto validate_timeout = [](const T&, uint32_t v) { return v <= 300000; };
static constexpr auto validate_retries = [](const T&, uint8_t v) { return v <= 5; };
static constexpr auto value = object(
"timeout_ms", read_constraint<&T::timeout_ms, validate_timeout, ERR>,
&T::retry_on_failure,
"max_retries", read_constraint<&T::max_retries, validate_retries, ERR>
);
static constexpr bool requires_key(std::string_view key, bool) {
return key == "timeout_ms";
}
};
// ResponseConfig: acknowledge and send_result required
template <>
struct glz::meta<embedded_benchmark::RpcCommand::ResponseConfig> {
using T = embedded_benchmark::RpcCommand::ResponseConfig;
static constexpr auto value = object(&T::callback_url, &T::acknowledge, &T::send_result);
static constexpr bool requires_key(std::string_view key, bool) {
return key == "acknowledge" || key == "send_result";
}
};
// RpcCommand: priority range, counts min 1, required fields
template <>
struct glz::meta<embedded_benchmark::RpcCommand> {
using T = embedded_benchmark::RpcCommand;
static constexpr auto validate_priority = [](const T&, uint8_t v) { return v <= 10; };
static constexpr auto validate_targets_count = [](const T&, size_t v) { return v >= 1; };
static constexpr auto validate_params_count = [](const T&, size_t v) { return v >= 1; };
static constexpr auto value = object(
&T::command_id, &T::timestamp_us, &T::sequence,
"priority", read_constraint<&T::priority, validate_priority, ERR>,
&T::targets,
"targets_count", read_constraint<&T::targets_count, validate_targets_count, ERR>,
&T::params,
"params_count", read_constraint<&T::params_count, validate_params_count, ERR>,
&T::execution, &T::response_config
);
static constexpr bool requires_key(std::string_view key, bool) {
return key == "command_id" || key == "timestamp_us" || key == "targets" || key == "params";
}
};
// Global config instance (will go in .bss section)
embedded_benchmark::EmbeddedConfig g_config;
#ifdef JF_PERF_ROUNDTRIP
// Instruction-benchmark mode: serialize into a dedicated scratch buffer (also
// avoids glz::write's unbounded write into the caller's buffer). The code-size
// benchmark (no macro) is unaffected.
static char jf_perf_scratch[16384];
extern "C" void cfg_mid(); // parse/serialize boundary markers (defined in the runner)
extern "C" void rpc_mid();
#endif
extern "C" __attribute__((used)) bool parse_config(const char* data, size_t size) {
auto error = glz::read<glz::opts_size{}>(g_config, std::string_view(data, size));
#ifdef JF_PERF_ROUNDTRIP
cfg_mid();
auto w_err = glz::write<glz::opts_size{}>(g_config, jf_perf_scratch);
#else
char* d = const_cast<char*>(data);
auto w_err = glz::write<glz::opts_size{}>(g_config, d);
#endif
return !error && !w_err;
}
struct opts_size_strict : glz::opts_size {
bool error_on_missing_keys = true;
};
extern "C" __attribute__((used)) bool parse_rpc_command(const char* data, size_t size) {
#ifdef JF_PERF_ROUNDTRIP
embedded_benchmark::RpcCommand cmd{}; // zero-init: full-array serialize touches unused slots
#else
embedded_benchmark::RpcCommand cmd;
#endif
auto error = glz::read<opts_size_strict{}>(cmd, std::string_view(data, size));
#ifdef JF_PERF_ROUNDTRIP
rpc_mid();
auto w_err = glz::write<glz::opts_size{}>(cmd, jf_perf_scratch);
#else
char* d = const_cast<char*>(data);
auto w_err = glz::write<glz::opts_size{}>(cmd, d);
#endif
return !error && !w_err;
}
#ifdef JSON_FUSION_BENCHMARK_ADDITIONAL_MODELS
// Single unified parsing function for all additional models
extern "C" __attribute__((used)) bool parse_additional_model(int model_id, const char* data, size_t size) {
std::string_view json(data, size);
switch(model_id) {
case 1: {
code_size_test::DeviceMetadata model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 2: {
code_size_test::SensorReadings model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 3: {
code_size_test::SystemStats model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 4: {
code_size_test::NetworkPacket model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 5: {
code_size_test::ImageDescriptor model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 6: {
code_size_test::AudioConfig model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 7: {
code_size_test::CacheEntry model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 8: {
code_size_test::FileMetadata model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 9: {
code_size_test::TransactionRecord model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 10: {
code_size_test::TelemetryPacket model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 11: {
code_size_test::RobotCommand model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 12: {
code_size_test::WeatherData model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 13: {
code_size_test::DatabaseQuery model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 14: {
code_size_test::VideoStream model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 15: {
code_size_test::EncryptionContext model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 16: {
code_size_test::MeshNode model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 17: {
code_size_test::GameState model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 18: {
code_size_test::LogEntry model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 19: {
code_size_test::CalendarEvent model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
case 20: {
code_size_test::HardwareProfile model;
auto error = glz::read<glz::opts_size{}>(model, json);
return !error;
}
default:
return false;
}
}
#endif
// Entry point - ensures parse_config is not eliminated by linker
// In a real embedded system, this would be your main loop
int main() {
// Call parse_config to ensure it's included in binary
volatile bool result = parse_config("", 0);
volatile bool rpc_result = parse_rpc_command("", 0);
(void)result;
(void)rpc_result;
#ifdef JSON_FUSION_BENCHMARK_ADDITIONAL_MODELS
// Call additional model parser for all 20 models to ensure they're included in binary
for (int i = 1; i <= 20; i++) {
volatile bool r = parse_additional_model(i, "", 0);
(void)r;
}
#endif
// Infinite loop (typical for embedded without OS)
while(1) {}
return 0;
}