ProtoCore v1.0.16
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
hex.h
Go to the documentation of this file.
1// ProtoCore v1.0.16 - Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file hex.h
6 * @brief Base-16 conversion between raw bytes and their ASCII digits.
7 *
8 * Four operations cover every hex site in the library: one nibble out, one digit in, a machine
9 * word out, and a byte run in either direction. Each writes into a caller-owned buffer, takes no
10 * heap and no `<stdlib.h>`, and is inline so an unused one costs nothing.
11 *
12 * The decoders report failure through a negative return rather than a sentinel digit, so a
13 * malformed byte can never be mistaken for a valid zero.
14 *
15 * @author Douglas Quigg (dstroy0)
16 * @date 2026
17 */
18
19#ifndef PROTOCORE_HEX_H
20#define PROTOCORE_HEX_H
21
22#include "protocore_config.h" // the entry point: protocore_types.h for the widths
23
24/**
25 * @brief The two digit tables: the only thing this module owns.
26 *
27 * One definition for the whole library rather than a copy per translation unit. Immutable, so a
28 * site that only needs a digit indexes it directly instead of going through a call.
29 */
30typedef struct
31{
32 const char *lower; ///< the 16 hex digits, lowercase
33 const char *upper; ///< the 16 hex digits, uppercase - for the protocols that specify capitals
35
36/** @brief The digit tables every hex site reads. */
37extern const HexStorage PROTOCORE_HEX;
38
39/** @brief What a digit conversion names: one nibble, or one character. */
40typedef struct
41{
42 uint8_t nibble; ///< the nibble a digit lookup renders
43 char ch; ///< the character a value lookup reads
44 uint32_t v; ///< the value a u32 render writes
45 proto_bool upper; ///< render A-F rather than a-f
46} HexArgs;
47
48/** @brief The buffers a run conversion moves between. */
49typedef struct
50{
51 const uint8_t *in; ///< the bytes an encode reads
52 const char *text; ///< the characters a decode reads
53 uint32_t n; ///< how many bytes to encode, or how many characters to decode
54 char *out; ///< where an encode or a u32 render writes
55 uint8_t *bytes; ///< where a decode writes
56 uint32_t cap; ///< how much room that has
57} HexIoArgs;
58
59/**
60 * @brief Hex digits, and the conversions both directions.
61 *
62 * A caller sets the members a call takes, invokes it through ::Hex, and reads the outcome off the
63 * same handle. The digit tables are behind @ref internal.
64 *
65 * @var HexNs::args one nibble, or one character
66 * @var HexNs::io the buffers a run conversion moves between
67 * @var HexNs::ch the digit a lookup rendered
68 * @var HexNs::i8 the value a digit lookup read, or -1 when it is not a hex digit
69 * @var HexNs::u8 digits a u32 render wrote (1..8)
70 * @var HexNs::i32 bytes a decode wrote, or -1 on a refusal
71 * @var HexNs::digit the hex character for a nibble
72 * @var HexNs::val the value of a hex character
73 * @var HexNs::u32 render a value as lowercase hex, most significant digit first
74 * @var HexNs::encode render a byte run as hex characters plus a NUL
75 * @var HexNs::decode read a hex run back into bytes
76 *
77 * u32 writes no `0x` prefix, no NUL, and no leading zeros, which is the form the HTTP/1.1 chunked
78 * size line takes; zero renders as a single "0" and @c io.out needs room for 8 characters.
79 *
80 * encode needs @c io.out to hold 2 * @c io.n + 1; the caller owns that bound, since a byte run has
81 * no self-describing end. decode refuses an odd length or a result larger than @c io.cap without
82 * writing anything; a bad digit stops the run where it is found.
83 */
84typedef struct
85{
88 char ch;
89 int8_t i8;
90 uint8_t u8;
91 int32_t i32;
92} HexVars;
93
94/** @brief The operands and the outcome. */
95extern HexVars HexV;
96
97/** @brief The entries. */
98typedef struct
99{
100 void (*const digit)(uint8_t *work);
101 void (*const val)(uint8_t *work);
102 void (*const u32)(uint8_t *work);
103 void (*const encode)(uint8_t *work);
104 void (*const decode)(uint8_t *work);
105} HexNs;
106
107// What the table binds, defined once in the .c and taking one parameter each: everything
108// else an entry needs is an operand in HexV or a region of the borrow at a fixed offset.
109void protocore_hex_digit(uint8_t *work);
110void protocore_hex_val(uint8_t *work);
111void protocore_hex_u32(uint8_t *work);
112void protocore_hex_encode(uint8_t *work);
113void protocore_hex_decode(uint8_t *work);
114
115// `static const`, initialised HERE rather than `extern` against a definition in the .c: a
116// const object whose initializer every translation unit can see is a COMPILE-TIME FACT, so
117// `Hex.digit(work)` resolves to a named function and becomes a DIRECT call. An extern table
118// leaves the call indirect and the symbol live at every level, -O2 -flto included.
119static const HexNs Hex __attribute__((unused)) = {
121 .val = protocore_hex_val,
122 .u32 = protocore_hex_u32,
123 .encode = protocore_hex_encode,
124 .decode = protocore_hex_decode,
125};
126
127#endif // PROTOCORE_HEX_H
void protocore_hex_u32(uint8_t *work)
HexVars HexV
The operands and the outcome.
void protocore_hex_digit(uint8_t *work)
void protocore_hex_val(uint8_t *work)
void protocore_hex_encode(uint8_t *work)
void protocore_hex_decode(uint8_t *work)
const HexStorage PROTOCORE_HEX
The digit tables every hex site reads.
What a digit conversion names: one nibble, or one character.
Definition hex.h:41
uint32_t v
the value a u32 render writes
Definition hex.h:44
char ch
the character a value lookup reads
Definition hex.h:43
proto_bool upper
render A-F rather than a-f
Definition hex.h:45
uint8_t nibble
the nibble a digit lookup renders
Definition hex.h:42
The buffers a run conversion moves between.
Definition hex.h:50
uint32_t cap
how much room that has
Definition hex.h:56
uint8_t * bytes
where a decode writes
Definition hex.h:55
uint32_t n
how many bytes to encode, or how many characters to decode
Definition hex.h:53
const char * text
the characters a decode reads
Definition hex.h:52
const uint8_t * in
the bytes an encode reads
Definition hex.h:51
char * out
where an encode or a u32 render writes
Definition hex.h:54
The entries.
Definition hex.h:99
void(*const digit)(uint8_t *work)
Definition hex.h:100
The two digit tables: the only thing this module owns.
Definition hex.h:31
const char * upper
the 16 hex digits, uppercase - for the protocols that specify capitals
Definition hex.h:33
const char * lower
the 16 hex digits, lowercase
Definition hex.h:32
Definition hex.h:85
char ch
Definition hex.h:88
uint8_t u8
Definition hex.h:90
HexArgs args
Definition hex.h:86
int32_t i32
Definition hex.h:91
int8_t i8
Definition hex.h:89
HexIoArgs io
Definition hex.h:87
_Bool proto_bool
The truth value.
Definition types.h:64