Declarative serialization components for the Flowduino ESPressio Development Platform.
0.10.2
Version 0.10.2 makes the fallback branch in detailed deserialization
unambiguous to compilers, eliminating GCC's -Wmisleading-indentation
diagnostic when downstream consumers build ESPressio Serializable headers with
warnings treated as errors.
There are no API, runtime-behaviour, or wire-format changes in this patch.
Version 0.10.1 hardens BinaryArchive when decoding untrusted or malformed
ESPB v2 payloads. The default Load() overload now applies embedded-friendly
limits for nesting depth, aggregate node count, object members, array elements,
property-name length, and string length. Allocation or decoder exceptions are
converted into a clean invalid-archive result rather than escaping into the
application.
Applications with different requirements can supply explicit limits:
ESPressio::Serializable::BinaryArchive archive;
ESPressio::Serializable::BinaryArchiveDecodeLimits limits;
limits.MaximumDepth = 16;
limits.MaximumTotalNodes = 1024;
limits.MaximumObjectMembers = 256;
limits.MaximumArrayElements = 1024;
limits.MaximumNameLength = 256;
limits.MaximumStringLength = 16 * 1024;
if (!archive.Load(data, size, limits)) {
// Malformed, truncated, unsupported, or outside the configured limits.
}The no-options overload remains source-compatible and uses the library defaults. The ESPB v2 wire format is unchanged.
For diagnostics, protocol inspection, and other cases that do not require an
owned SerializationNode tree, 0.10.1 also adds an allocation-free ESPB v2
traversal API:
ESPressio::Serializable::BinaryArchiveDecodeLimits limits;
limits.MaximumDepth = 12;
limits.MaximumTotalNodes = 1024;
if (ESPressio::Serializable::ValidateBinaryArchive(
data,
size,
limits
)) {
// Structurally valid and within the configured limits.
}TraverseBinaryArchive() accepts a BinaryArchiveVisitor and streams object,
array, property, and scalar callbacks directly from the encoded bytes. The
traversal uses std::string_view for borrowed names/string values and does not
construct a second tree or copy payload strings merely to inspect them.
This is particularly useful on ESP32 for diagnostic paths where attempting to build another heap-backed tree during low-memory conditions would itself be undesirable.
Version 0.10.0 adds a public direct Binary serialization/deserialization API for latency-sensitive integrations such as ESPressio Event Transport.
std::vector<uint8_t> bytes;
ESPressio::Serializable::SerializeDirectBinary(
object,
bytes
);
ESPressio::Serializable::DeserializeDirectBinary(
bytes.data(),
bytes.size(),
object
);AppendDirectBinary() is also available when a caller has already reserved or
written a protocol/header prefix and wants the Serializable payload appended to
the same final buffer.
The direct path preserves the existing BinaryArchive ESPB v2 wire format.
It writes schema/property values directly to bytes and reads same-schema values
directly from the input buffer, avoiding the full intermediate
SerializationNode object tree. If a consumer requires structural schema
migration it can continue to use the existing BinaryArchive/TreeArchive path;
ESPressio Event Transport uses that path as a compatibility fallback.
ESPressio is a collection of discrete, composable component libraries built around a common development ethos:
- Light-weight --- minimise memory consumption and runtime overhead without sacrificing correctness.
- Ease of use --- provide strongly typed, developer-friendly abstractions over lower-level facilities.
- Object-oriented --- a type for everything, and everything in a type.
- SOLID --- favour focused responsibilities, extensibility, substitutable abstractions, narrow interfaces, and dependency inversion wherever practical on embedded C++ platforms.
Licensed under the Apache License 2.0. See LICENSE.
ESPressio is designed as a modular ecosystem of independently useful libraries, with required dependencies kept explicit and optional integrations introduced only when the corresponding functionality is selected.
For a complete overview of required dependencies, opt-in dependencies, and the overall hierarchy, see:
ESPressio Library Dependency Chart
- Solid relationships represent required ESPressio dependencies.
- Dashed relationships represent opt-in dependencies introduced only by the corresponding feature, integration, type, or header.
None.
Serializable types declare their schema alongside the type itself:
class Example :
public ESPressio::Serializable::
SerializableBase<Example> {
public:
uint32_t Id = 0;
String Name;
ESPRESSIO_SERIALIZABLE_TYPE(Example)
ESPRESSIO_SERIALIZABLE_SCHEMA_VERSION(1)
ESPRESSIO_SERIALIZABLE_PROPERTIES(
ESPRESSIO_PROPERTY("id", Id),
ESPRESSIO_PROPERTY("name", Name)
)
};The same declaration can be consumed by multiple archive representations.
The framework supports JSON, CBOR and Binary representations, including direct CBOR/Binary paths rather than requiring JSON as an intermediate representation.
Streaming readers/writers are available where supported by the selected archive.
The framework supports common scalar and compound values including
arithmetic types, nested Serializable objects, arrays/containers,
Arduino String, std::optional, enum mapping, and supported map/set
forms.
Properties and objects can participate in validation, including numeric constraints and application-defined validation callbacks.
Serializable types declare schema versions. Migration helpers, aliases and defaults allow older persisted or transported representations to evolve deliberately.
Schema metadata can identify fields that should be redacted in diagnostic/log-oriented representations.
Where an invalid or unsupported schema declaration can be detected statically, the library is designed to fail at compile time rather than defer the problem to runtime.
Serializable remains independent. Other libraries opt into it:
Units
-> optional Serializable Unit variants
Event
-> optional Serializable Events
-> Event Transport payloads
Ordinary usage of those libraries remains serialization-free.
- One declarative schema per type.
- Representation-neutral metadata.
- Embedded-friendly archives.
- Direct CBOR/Binary support.
- Bounded and allocation-free BinaryArchive inspection where appropriate.
- Validation and schema evolution.
- Compile-time diagnostics where possible.
- Optional rather than ecosystem-wide dependency.