MMgr v1.0.0
Zero-heap memory manager in C11. One borrowed buffer, carved by asserted offset.
Loading...
Searching...
No Matches
octetus_introitus_exitus.h
Go to the documentation of this file.
1/* MMgr - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2 * SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Commercial OR LicenseRef-Educational
3 *
4 * Every use falls under AGPL-3.0-or-later unless you hold explicit permission, which is either a
5 * negotiated commercial licensing contract or an educator's license issued to you personally.
6 */
7/**
8 * @file octetus_introitus_exitus.h
9 * @brief Byte verbs that append into a caller's span or read out of it.
10 * @author dstroy0 (Douglas Quigg) <dquigg123@gmail.com>
11 * @date 2026-08-29
12 *
13 * @note These act on a caller's span and hold nothing of their own. The span carries the cursor and
14 * the sticky flag. A caller may append a whole message and test once at the end.
15 * @note mmgr_byteio_put, mmgr_byteio_put_be and mmgr_byteio_raw return nothing. What a writer emits
16 * and how big its buffer is are both fixed before the build, and so writing past the end means the
17 * program is wrong. Those three assert, store nothing, and latch overflow to keep a wrong
18 * program off the end, and none of that leaves a caller anything to act on.
19 * @note mmgr_byteio_take_be and mmgr_byteio_rd_str answer EMBED_FALSE when the bytes are not there,
20 * set the read span's err, and leave the cursor and the output where they were. A reader is
21 * handed whatever was sent to it. A short read is a runtime fact and not a build
22 * failure. The cursor does not advance on failure, because a caller that keeps reading still
23 * needs it to mean something.
24 * @note mmgr_byteio_mpint_fixed is neither of those. It writes a whole field and not appending,
25 * and answers whether the integer fit, and so its own declaration carries the contract.
26 * @note Whole values move a word at a time. The big endian entries reverse once and then store or
27 * load at the widest step the count allows, instead of walking bytes.
28 */
29#ifndef MMGR_OCTETUS_INTROITUS_EXITUS_H
30#define MMGR_OCTETUS_INTROITUS_EXITUS_H
31
32#include "spatium/spatium.h"
33
34#include "mmgr.h"
35
36EMBED_BEGIN_DECLS
37
38/**
39 * @brief Arguments for the byteio calls, where each call reads only the members it needs.
40 *
41 * @note put reads write_span and byte. put_be reads write_span, value and bytes. raw reads
42 * write_span, src and bytes. take_be reads read_span, bytes and out. rd_str reads read_span,
43 * blob and blob_bytes. mpint_fixed reads write_span, src and bytes, where bytes is the
44 * integer's length and not a big endian width.
45 */
46typedef struct
47{
48 mmgr_span *const write_span; /**< Span put, put_be and raw append into, or mpint_fixed fills [BORROWS]. */
49 mmgr_cspan *const read_span; /**< Span take_be and rd_str read from [BORROWS]. */
50 const uint8_t *const src; /**< Bytes raw appends, or the integer mpint_fixed reads [BORROWS]. */
51 uint64_t *const out; /**< Where take_be stores the value it read [BORROWS]. */
52 const uint8_t **const blob; /**< Where rd_str points at the payload it found [BORROWS]. */
53 size_t *const blob_bytes; /**< Where rd_str stores that payload's length [BORROWS]. */
54 const uint64_t value; /**< Value put_be writes, taken from its low bytes. */
55 const size_t bytes; /**< Bytes the call moves, 1 through 8 for the big endian entries. */
56 const uint8_t byte; /**< The single byte put appends. */
58
59/**
60 * @brief Type of the byteio dispatch table.
61 *
62 * @note EMBED_TABLE_LAYOUT asserts the six members sit at consecutive EMBED_FUNCTION_POINTER_BYTES offsets, with
63 * nothing else.
64 * @note put, put_be and raw answer nothing, because a span latches its own failure and leaves a
65 * caller nothing to act on.
66 * @note take_be and rd_str answer, because a read that did not happen has to be distinguishable
67 * from one that read a zero. mpint_fixed answers whether the integer fit the field.
68 */
69typedef struct
70{
71 void (*put)(const OctetusCfg *args); /**< Appends one byte. */
72 void (*put_be)(const OctetusCfg *args); /**< Appends bytes of a value, most significant first. */
73 void (*raw)(const OctetusCfg *args); /**< Appends a run of bytes as they are. */
74 embed_bool (*take_be)(const OctetusCfg *args); /**< Reads a big endian value and advances past it. */
75 embed_bool (*rd_str)(const OctetusCfg *args); /**< Reads a length-prefixed run and points at it. */
76 embed_bool (*mpint_fixed)(const OctetusCfg *args); /**< Right-aligns an integer into a fixed field. */
78EMBED_TABLE_LAYOUT(OctetusIntroitusExitusNs, put, put_be, raw, take_be, rd_str, mpint_fixed);
79
80/**
81 * @brief Appends args->byte to args->write_span.
82 *
83 * @param[in,out] args Span and the byte to append [BORROWS].
84 * @warning Appending past the span's cap is a build failure. It asserts, stores nothing and latches
85 * overflow. pos counts the byte either way.
86 */
87void mmgr_byteio_put(const OctetusCfg *args);
88
89/**
90 * @brief Appends the low args->bytes of args->value to args->write_span, most significant byte first.
91 *
92 * @param[in,out] args Span, value and byte count [BORROWS].
93 * @note The value is reversed once and then stored at the widest step the count allows. A count of
94 * eight is one store and a count of seven is three.
95 * @warning Appending past the span's cap is a build failure. It asserts, stores nothing and latches
96 * overflow. pos advances either way.
97 * @warning args->bytes must be 1 through 8.
98 */
100
101/**
102 * @brief Appends args->bytes from args->src to args->write_span as they are.
103 *
104 * @param[in,out] args Span, source and byte count [BORROWS].
105 * @warning Appending past the span's cap is a build failure. It asserts, stores nothing and latches
106 * overflow. pos advances either way.
107 * @warning args->src must be readable for args->bytes, and must not overlap the span's buffer.
108 */
109void mmgr_byteio_raw(const OctetusCfg *args);
110
111/**
112 * @brief Reads a big endian value of args->bytes at args->read_span's cursor and advances past it.
113 *
114 * @param[in,out] args Span, byte count and where to store the value [BORROWS].
115 * @return EMBED_TRUE when the bytes were there, EMBED_FALSE when the span was short.
116 * @note Reads at the cursor and nowhere else. A codec that leads with a tag advances past it itself.
117 * @note A read reaching past the end sets the span's err and leaves the cursor and args->out untouched.
118 * @warning args->bytes must be 1 through 8.
119 */
120embed_bool mmgr_byteio_take_be(const OctetusCfg *args);
121
122/**
123 * @brief Reads a big endian 32-bit length at args->read_span's cursor, then points args->blob at the
124 * run behind it.
125 *
126 * @param[in,out] args Span, and where to report the run and its length [BORROWS].
127 * @return EMBED_TRUE when the length and its run both lay within the span.
128 * @note Nothing is copied. args->blob points into the span's own bytes, and so it lives only as long as
129 * they do [BORROWS].
130 * @note The cursor advances past the length and the run together. A caller reading a sequence of
131 * these needs to track nothing between them.
132 * @note A run reaching past the end leaves the cursor where it started, sets the span's err, and
133 * writes nothing through args->blob or args->blob_bytes. The length alone having been read does
134 * not move the cursor either, since a partial read is not a read.
135 */
136embed_bool mmgr_byteio_rd_str(const OctetusCfg *args);
137
138/**
139 * @brief Right-aligns the big endian integer at args->src into args->write_span's whole buffer, zero
140 * filling ahead of it.
141 *
142 * @param[in,out] args The integer with its length in args->src and args->bytes, and the field as
143 * args->write_span [BORROWS].
144 * @return EMBED_TRUE when the integer fits the field, EMBED_FALSE when it does not.
145 * @note Leading zero bytes of the integer are skipped before the width is tested. A value carrying
146 * a sign byte still fits a field of its own size.
147 * @note The field is written whole and not appended to. On success args->write_span's cursor ends
148 * at its cap.
149 * @note Nothing is written to the field when it returns EMBED_FALSE, but args->write_span's overflow
150 * is latched. A span tested later reports the failure too.
151 * @warning args->src must be readable for args->bytes, and must not overlap args->write_span's buffer.
152 */
153embed_bool mmgr_byteio_mpint_fixed(const OctetusCfg *args);
154
155/**
156 * @brief Dispatch table instance named byteio, with each member set to its mmgr_byteio_ function.
157 */
158EMBED_TABLE_STORAGE OctetusIntroitusExitusNs byteio EMBED_UNUSED = {
159 .put = mmgr_byteio_put,
160 .put_be = mmgr_byteio_put_be,
161 .raw = mmgr_byteio_raw,
162 .take_be = mmgr_byteio_take_be,
163 .rd_str = mmgr_byteio_rd_str,
164 .mpint_fixed = mmgr_byteio_mpint_fixed,
165};
166
167EMBED_END_DECLS
168
169#endif
The embedded_types headers every module builds on.
void mmgr_byteio_put_be(const OctetusCfg *args)
Appends the low args->bytes of args->value to args->write_span, most significant byte first.
static const OctetusIntroitusExitusNs byteio
Dispatch table instance named byteio, with each member set to its mmgr_byteio_ function.
embed_bool mmgr_byteio_rd_str(const OctetusCfg *args)
Reads a big endian 32-bit length at args->read_span's cursor, then points args->blob at the run behin...
embed_bool mmgr_byteio_mpint_fixed(const OctetusCfg *args)
Right-aligns the big endian integer at args->src into args->write_span's whole buffer,...
void mmgr_byteio_raw(const OctetusCfg *args)
Appends args->bytes from args->src to args->write_span as they are.
embed_bool mmgr_byteio_take_be(const OctetusCfg *args)
Reads a big endian value of args->bytes at args->read_span's cursor and advances past it.
void mmgr_byteio_put(const OctetusCfg *args)
Appends args->byte to args->write_span.
Spans over a caller's buffer, the two span types, and the spat dispatch table.
Arguments for the byteio calls, where each call reads only the members it needs.
mmgr_cspan *const read_span
const uint8_t **const blob
uint64_t *const out
const uint8_t *const src
mmgr_span *const write_span
const uint64_t value
size_t *const blob_bytes
Type of the byteio dispatch table.
embed_bool(*) take_be(const OctetusCfg *args)
void(*) put(const OctetusCfg *args)
void(*) put_be(const OctetusCfg *args)
embed_bool(*) mpint_fixed(const OctetusCfg *args)
embed_bool(*) rd_str(const OctetusCfg *args)
void(*) raw(const OctetusCfg *args)
A buffer being read: its bytes, how far the reader has gone, and whether it ran out.
Definition spatium.h:63
A buffer being filled: its bytes, how far the writer has gone, and whether it ran out.
Definition spatium.h:47