feat(cdr)!: reflection-driven CDR/XCDR serialization (replaces CdrWriter/CdrReader) - #705
Conversation
… library The cdr component now vendors finger563/cdr (detail/ submodule): the compiler generates CDR serialization from plain struct definitions — no IDL, no hand-written write/read sequences. Adds XCDR2 (delimited/ appendable + DHEADER schema evolution), both endiannesses, std::expected errors with field names, bounded types, and PL_CDR parameter-list helpers for RTPS discovery. Wire format is byte-verified against pycdr2 (CycloneDDS). Depends on the new reflect_cpp component; requires C++23 (default on IDF 5.2+ toolchains). BREAKING CHANGE: espp::CdrWriter / espp::CdrReader are gone; use cdr::serialize / cdr::deserialize<T> / cdr::param_list_writer instead. Example builds on ESP32-S3 / IDF 6 (389 KB total image incl. logger+fmt). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… API - rtps: discovery string/octet-sequence parameters serialize via cdr::serialize_body / deserialize_body; PL_CDR encapsulation handled inline (the old CdrWriter/CdrReader helpers are gone) - pc tests + rtps/p4 examples: uint32 payload helpers use cdr::serialize<cdr::xcdr1> / cdr::deserialize<uint32_t> - lib: espp builds C++23; cdr/reflect-cpp detail headers added to the include set; cdr python bindings removed — the python side of a CDR message is a plain pycdr2 dataclass (or struct.pack for primitives), so espp.CdrWriter/CdrReader no longer exist - python: rtps scripts use pure-python CDR helpers for uint32 payloads Verified: rtps example builds on ESP32-S3/IDF 6; host lib + _espp python module build; pc rtps_pubsub end-to-end test passes (16/16 samples through SPDP/SEDP discovery + user data on the new serializer). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Updates the sphinx page and example README for the new struct-based serialize/deserialize API, and excludes the vendored detail/ submodule from cppcheck (matching lib/). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
✅Static analysis result - no issues found! ✅ |
There was a problem hiding this comment.
Pull request overview
This PR replaces the project’s manual espp::CdrWriter/espp::CdrReader implementation with a reflection-driven CDR/XCDR serialization library (finger563/cdr) vendored as a submodule, and migrates RTPS + examples/PC tooling to the new API while removing the old Python bindings.
Changes:
- Swap
components/cdrto a header-only umbrella over the vendoredcdrlibrary +reflect_cpp, and update docs/manifests accordingly. - Migrate RTPS parameter encode/decode and examples/PC tests from
espp::CdrWriter/Readertocdr::{serialize,serialize_body,deserialize,deserialize_body}. - Remove
cdrpybind bindings and replace Python RTPS scripts’ UInt32 payload helpers with pure-structpacking/unpacking; bump host builds to C++23.
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| suppressions.txt | Suppress cppcheck findings in the vendored components/cdr/detail/* tree. |
| .gitmodules | Add components/cdr/detail/cdr submodule (finger563/cdr). |
| components/cdr/CMakeLists.txt | Register cdr as an interface/header-only component; include vendored headers; require reflect_cpp. |
| components/cdr/include/cdr.hpp | Replace old API with an umbrella header that includes <cdr/cdr.hpp> and documents the new model. |
| components/cdr/src/cdr.cpp | Remove now-unneeded source file (header-only). |
| components/cdr/README.md | Rewrite component README for reflection-driven CDR/XCDR and std::expected-based API. |
| components/cdr/idf_component.yml | Update description/tags; bump IDF requirement to >=5.2; add reflect_cpp dependency. |
| components/cdr/example/CMakeLists.txt | Include reflect_cpp and bump example C++ standard to 23. |
| components/cdr/example/README.md | Update example description to match the new library capabilities and examples. |
| components/cdr/example/main/cdr_example.cpp | Replace old imperative reader/writer example with reflection-driven serialize/deserialize + param list demo. |
| doc/en/data/cdr.rst | Update documentation to describe the new reflection-driven library and capabilities. |
| components/rtps/src/rtps.cpp | Migrate discovery parameter encoding/decoding from old CDR helpers to new cdr::* helpers; inline PL_CDR encapsulation handling. |
| components/rtps/example/main/rtps_example.cpp | Switch UInt32 payload helper to cdr::serialize<cdr::xcdr1> / cdr::deserialize<uint32_t>. |
| components/esp32-p4-function-ev-board/example/main/esp32_p4_function_ev_board_example.cpp | Same UInt32 helper migration as RTPS example. |
| pc/tests/rtps_common.hpp | Switch PC test helpers to new cdr serialization/deserialization API with std::expected guards. |
| pc/CMakeLists.txt | Bump host build standard to C++23. |
| lib/CMakeLists.txt | Build host library with C++23 compile features. |
| lib/espp.cmake | Remove old cdr source + bindings; add include paths for vendored cdr and reflect-cpp; bump python module to C++23. |
| lib/autogenerate_bindings.py | Update notes to reflect removal of CDR Python bindings and template-based API. |
| lib/python_bindings/module.cpp | Stop registering removed py_init_cdr; update binding comment. |
| lib/python_bindings/cdr_bindings.cpp | Delete old pybind11 bindings for espp::CdrWriter/espp::CdrReader. |
| python/rtps_publisher.py | Replace espp.CdrWriter usage with struct.pack-based encapsulated UInt32 payload. |
| python/rtps_subscriber.py | Replace espp.CdrReader usage with struct.unpack_from and encapsulation-endianness handling. |
| python/rtps_pubsub.py | Same as publisher/subscriber: pure-python UInt32 CDR payload helpers. |
Suppressed comments (1)
components/rtps/src/rtps.cpp:461
cdr::serialize_body(...)is dereferenced without checking for failure. If serialization fails,*bodyis undefined behavior. Guard the result and drop the parameter on failure.
void append_parameter_octet_sequence(ByteWriter &writer, ParameterId id,
std::span<const uint8_t> bytes) {
auto body = cdr::serialize_body<cdr::xcdr1>(std::vector<uint8_t>(bytes.begin(), bytes.end()));
append_cdr_parameter(writer, id, *body);
}
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Drop the parameter instead of dereferencing a failed std::expected, mirroring the oversized-parameter handling in append_cdr_parameter. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 25 out of 25 changed files in this pull request and generated no new comments.
Suppressed comments (4)
pc/CMakeLists.txt:3
- pc/tests CMakeLists still declares cmake_minimum_required(VERSION 3.11) but now requests C++23. CMake 3.11 predates C++23 support and may fail at configure/generate time; bump the minimum CMake version (or otherwise guard) to match the C++ standard requirement.
cmake_minimum_required (VERSION 3.11)
set(CMAKE_CXX_STANDARD 23)
python/rtps_pubsub.py:40
- deserialize_uint32 validates only the 2-byte representation id and ignores the 2-byte encapsulation options field. For CDR/XCDR1 the options field is reserved and should be 0; rejecting non-zero options avoids accepting malformed/unsupported payloads and then decoding them as if they were valid.
if len(data) < 8 or data[0] != 0x00 or data[1] not in (0x00, 0x01):
python/rtps_subscriber.py:32
- deserialize_uint32 validates only the 2-byte representation id and ignores the 2-byte encapsulation options field. For CDR/XCDR1 the options field is reserved and should be 0; rejecting non-zero options avoids accepting malformed/unsupported payloads and then decoding them as if they were valid.
if len(data) < 8 or data[0] != 0x00 or data[1] not in (0x00, 0x01):
components/rtps/src/rtps.cpp:514
- parse_parameter_list checks only the 2-byte PL_CDR_LE representation id (0x0003) but does not validate the 2-byte encapsulation options field. The options field is reserved and should be 0; rejecting non-zero options avoids treating malformed/unsupported parameter lists as valid.
if (payload.size() < 4 || payload[0] != 0x00 || payload[1] != 0x03) {
Description
Continuation of #704 (stacked on the now-merged #703; GitHub could not reopen/retarget it after the base branch was deleted, so this PR carries the same branch with its review feedback applied — see #704 for the earlier review discussion).
Replaces the manual
espp::CdrWriter/espp::CdrReadercomponent with finger563/cdr, a reflection-driven CDR/XCDR serialization library (vendored as adetail/submodule): the compiler generates serialization code from plain struct definitions — no IDL compiler, no hand-written write/read call sequences.What the new library adds over the old component:
pycdr2dataclass, no native bindingsstd::expectederrors with code, payload offset, and failing field name; bounds-checked, fuzz-tested deserializers (ASan/UBSan-clean incl. a ~46k-case mutation stress suite in the library repo)cdr::bounded_string<N>/bounded_vector<T, N>, PL_CDRparam_list_writer/param_list_readerfor SPDP/SEDP, zero-allocationserialize_into, body-only variantsBREAKING CHANGE
espp::CdrWriter/espp::CdrReaderare gone, including their Python bindings (espp.CdrWriter/espp.CdrReader). Migrations in this PR:cdr::serialize_body/deserialize_body; PL_CDR encapsulation handled inline; oversized parameters are dropped rather than truncating the 16-bit parameterLengthcdr::serialize<cdr::xcdr1>/cdr::deserialize<uint32_t>, with guards on thestd::expectedresultspycdr2/struct.pack)Review feedback from #704 is incorporated (separate error checks in the example, parameterLength bound guard, expected-deref guards).
Verification
cdrandrtpsexamples build on ESP32-S3 (IDF 6; CI's v5.5.1 defaults tognu++2b, providingstd::expected)espp_pclib +_espppython module build (C++23)pc/build/rtps_pubsubend-to-end test passes: 16/16 samples through SPDP/SEDP discovery + user data on the new serializerNotes
std::expected) — default on IDF 5.2+ toolchains; manifest declaresidf: >=5.2reflect_cppsubmodule pin and finger563/cdr's FetchContent tag on the same reflect-cpp version (currently v0.25.0)🤖 Generated with Claude Code