ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
codec.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file codec.h
6 * @brief One binary codec interface; a wire encoding is an instance of it.
7 *
8 * CBOR and MessagePack encode the same ten things - unsigned, signed, bytes, string, bool, null,
9 * float, array header, map header - into different bytes. Written out separately they were two
10 * parallel APIs over two field-identical cursor structs, and a caller had to pick one at the call
11 * site, so SenML-over-CBOR and SenML-over-MessagePack could not be the same code.
12 *
13 * They are one interface with two instances. The operations, their order, and their signatures are
14 * fixed here; a format supplies the function pointers. Order is load-bearing: it is the field order
15 * of the table, so a format whose operations drift out of order fails to compile rather than
16 * silently binding the wrong encoder.
17 *
18 * Dispatch is a `static const` table of plain function pointers in rodata, the same shape as
19 * ProtoHandler. Not virtual, not RTTI, not std::function (SRCBANNED #22): the set of reachable
20 * targets stays a closed list the linker can see whole, so the worst-case path is still a number.
21 *
22 * The region types come from span.h and the byte verbs from bytes.h - a codec does no allocation and
23 * owns no buffer; it writes into a pc_span the caller bound and reads from a pc_cspan.
24 *
25 * @author Douglas Quigg (dstroy0)
26 * @date 2026
27 */
28
29#ifndef PROTOCORE_CODEC_H
30#define PROTOCORE_CODEC_H
31
32#include "protocore_config.h" // PC_NEED_CBOR / PC_ENABLE_MSGPACK gate the instances below
34#include <stddef.h>
35#include <stdint.h>
36
37/**
38 * @brief The next item's type, reported by pc_codec::peek without consuming it.
39 *
40 * One set of names across every format: CBOR calls a byte string "bytes" and MessagePack calls it
41 * "bin"; CBOR has "null" and MessagePack "nil". They are the same item, so they get one name here
42 * and the format maps its own tag onto it.
43 */
44enum class pc_codec_type : uint8_t
45{
46 PC_CODEC_UINT = 0,
55 PC_CODEC_INVALID ///< end of buffer, a prior error, or an item this format does not carry
56};
57
58/**
59 * @brief A wire encoding: the ten writes, the peek, and the nine reads.
60 *
61 * Field order is the operation order every format declares and implements in. `int`, `bool` and
62 * `float` are keywords, so the members carry the put_ / get_ prefix that says which direction they
63 * run in.
64 */
66{
67 // --- encode into a caller-bound pc_span ---
68 void (*put_uint)(pc_span *w, uint64_t v);
69 void (*put_int)(pc_span *w, int64_t v);
70 void (*put_bytes)(pc_span *w, const uint8_t *data, size_t len);
71 void (*put_str)(pc_span *w, const char *s);
72 void (*put_str_n)(pc_span *w, const char *s, size_t len);
73 void (*put_bool)(pc_span *w, bool b);
74 void (*put_null)(pc_span *w);
75 void (*put_float)(pc_span *w, float f);
76 void (*put_array)(pc_span *w, size_t count);
77 void (*put_map)(pc_span *w, size_t count);
78
79 /**
80 * @brief Emit a map key, given both spellings of it.
81 *
82 * A spec often names the same field differently per encoding: RFC 8428 labels a SenML base name
83 * `"bn"` in JSON and `-2` in CBOR. That is the encoding's business, not the caller's, so the
84 * caller hands over both and the format picks the one it is specified to write. Without this the
85 * difference leaks upward and every producer keeps one walk per encoding.
86 */
87 void (*put_label)(pc_span *w, const char *name, int64_t num);
88
89 // --- decode from a caller-bound pc_cspan ---
91 bool (*get_uint)(pc_cspan *r, uint64_t *out);
92 bool (*get_int)(pc_cspan *r, int64_t *out);
93 bool (*get_bytes)(pc_cspan *r, const uint8_t **out, size_t *len);
94 bool (*get_str)(pc_cspan *r, const char **out, size_t *len);
95 bool (*get_array)(pc_cspan *r, size_t *count);
96 bool (*get_map)(pc_cspan *r, size_t *count);
97 bool (*get_bool)(pc_cspan *r, bool *out);
98 bool (*get_null)(pc_cspan *r);
99 bool (*get_float)(pc_cspan *r, float *out);
100};
101
102// --- the formats, as instances ---
103//
104// Storage is opaque: each table is internal linkage in codec.cpp and reached only through its
105// accessor, so no caller can name it, copy it, or keep a second one. Guarded so a build that
106// compiles a format out has no accessor to call and no table to link.
107
108#if PC_NEED_CBOR
109/** @brief CBOR (RFC 8949) as an instance of the codec interface. */
110const pc_codec *pc_codec_cbor(void);
111#endif
112
113#if PC_ENABLE_MSGPACK
114/** @brief MessagePack as an instance of the codec interface. */
115const pc_codec *pc_codec_msgpack(void);
116#endif
117
118#endif // PROTOCORE_CODEC_H
pc_codec_type
The next item's type, reported by pc_codec::peek without consuming it.
Definition codec.h:45
@ PC_CODEC_INVALID
end of buffer, a prior error, or an item this format does not carry
User-facing configuration for ProtoCore.
A byte region whose run length is bound in both directions.
A wire encoding: the ten writes, the peek, and the nine reads.
Definition codec.h:66
void(* put_uint)(pc_span *w, uint64_t v)
Definition codec.h:68
bool(* get_null)(pc_cspan *r)
Definition codec.h:98
bool(* get_bytes)(pc_cspan *r, const uint8_t **out, size_t *len)
Definition codec.h:93
void(* put_label)(pc_span *w, const char *name, int64_t num)
Emit a map key, given both spellings of it.
Definition codec.h:87
bool(* get_bool)(pc_cspan *r, bool *out)
Definition codec.h:97
bool(* get_float)(pc_cspan *r, float *out)
Definition codec.h:99
void(* put_bytes)(pc_span *w, const uint8_t *data, size_t len)
Definition codec.h:70
void(* put_float)(pc_span *w, float f)
Definition codec.h:75
bool(* get_int)(pc_cspan *r, int64_t *out)
Definition codec.h:92
void(* put_array)(pc_span *w, size_t count)
Definition codec.h:76
void(* put_null)(pc_span *w)
Definition codec.h:74
void(* put_int)(pc_span *w, int64_t v)
Definition codec.h:69
bool(* get_str)(pc_cspan *r, const char **out, size_t *len)
Definition codec.h:94
bool(* get_array)(pc_cspan *r, size_t *count)
Definition codec.h:95
pc_codec_type(* peek)(pc_cspan *r)
Definition codec.h:90
bool(* get_map)(pc_cspan *r, size_t *count)
Definition codec.h:96
bool(* get_uint)(pc_cspan *r, uint64_t *out)
Definition codec.h:91
void(* put_map)(pc_span *w, size_t count)
Definition codec.h:77
void(* put_bool)(pc_span *w, bool b)
Definition codec.h:73
void(* put_str_n)(pc_span *w, const char *s, size_t len)
Definition codec.h:72
void(* put_str)(pc_span *w, const char *s)
Definition codec.h:71
A read-only byte region.
Definition span.h:79
A writable byte region: the storage, the capacity that belongs to it, and what has been produced into...
Definition span.h:65