ProtoCore v0.0.1
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
frame.h File Reference

Declarative frame builder: a frame is a static table of typed fields, built by one engine. More...

#include "shared_primitives/strbuf.h"
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>

Go to the source code of this file.

Classes

struct  pc_field
 One field of a frame. Frames are static const pc_field[], so they live in rodata. More...
 

Macros

#define PC_STR   {PC_FK_STR, 0, 0, nullptr}
 
#define PC_U32   {PC_FK_U32, 0, 0, nullptr}
 
#define PC_U64   {PC_FK_U64, 0, 0, nullptr}
 
#define PC_I64   {PC_FK_I64, 0, 0, nullptr}
 
#define PC_CH   {PC_FK_CH, 0, 0, nullptr}
 
#define PC_JSON   {PC_FK_JSON, 0, 0, nullptr}
 
#define PC_XML   {PC_FK_XML, 0, 0, nullptr}
 
#define PC_END   {PC_FK_END, 0, 0, nullptr}
 

Enumerations

enum  pc_fk : uint8_t {
  PC_FK_END = 0 , PC_FK_LIT , PC_FK_STR , PC_FK_U32 ,
  PC_FK_U64 , PC_FK_I64 , PC_FK_DEC , PC_FK_HEX ,
  PC_FK_OCT , PC_FK_G , PC_FK_FIX , PC_FK_CH ,
  PC_FK_JSON , PC_FK_XML
}
 Field kinds. The value is an opcode, so this is deliberately a plain byte enum. More...
 

Functions

size_t pc_frame_build (char *out, size_t cap, const pc_field *spec,...)
 Build spec into out (capacity cap), taking one variadic argument per valued field.
 
size_t pc_frame_vbuild (char *out, size_t cap, const pc_field *spec, va_list ap)
 va_list form, for a caller that already has one.
 
size_t pc_frame_append (char *out, size_t cap, const pc_field *spec,...)
 Append spec to the NUL-terminated contents already in out.
 

Detailed Description

Declarative frame builder: a frame is a static table of typed fields, built by one engine.

The problem this solves. Replacing printf-style formatting with hand-written pc_sb append sequences trades one call for a dozen, and every one of those dozens is new code with its own chance of a wrong order, a missing separator, or a forgotten overflow test. Across the ~160 formatting sites in this library that is well over a thousand new lines, none of which any test covers individually. A frame SPEC moves that structure into data: the shape of the frame is a static const pc_field[] in rodata, the engine that walks it is one function, and the engine is what gets tested. Adding a frame after that adds a table, not logic.

Why not a format string. A format string encodes the same table, but re-parses it from text on every call - scanning characters, decoding widths, dispatching per conversion - to rediscover what was known when the code was written. The spec is pre-decoded: the engine reads an opcode and a width from a struct and jumps. Nothing is parsed at runtime, and no float formatter is linked in unless a frame actually declares a float field.

Contract.

  • Returns the number of bytes written (excluding the NUL) on success.
  • Returns 0 if the frame does not fit, and writes ‘out[0] = ’\0'. There is no truncation: a partial frame is a protocol violation, and a caller that ignores the return still finds a valid empty C string rather than half a header or stale bytes from a previous build. -outis always NUL-terminated on both paths, so a caller may always read it as a string.
  • A NULLPC_FK_STR` argument renders as empty, never as a crash or "(null)".

Arguments are passed variadically in spec order, one per field that declares one (PC_FK_LIT and PC_FK_END take none). They are read at their default-promoted types, so a uint8_t passed to PC_FK_U32 arrives as unsigned and a float passed to PC_FK_G arrives as double, which is what the engine expects. The compiler cannot check that arity, but a spec's field count and its call sites are visible in the same translation unit, so it is checkable offline - that gate lands with the rollout, and until it does a mismatched spec is caught only by its test.

Author
Douglas Quigg (dstroy0)
Date
2026

Definition in file frame.h.

Macro Definition Documentation

◆ PC_STR

#define PC_STR   {PC_FK_STR, 0, 0, nullptr}

Definition at line 103 of file frame.h.

◆ PC_U32

#define PC_U32   {PC_FK_U32, 0, 0, nullptr}

Definition at line 104 of file frame.h.

◆ PC_U64

#define PC_U64   {PC_FK_U64, 0, 0, nullptr}

Definition at line 105 of file frame.h.

◆ PC_I64

#define PC_I64   {PC_FK_I64, 0, 0, nullptr}

Definition at line 106 of file frame.h.

◆ PC_CH

#define PC_CH   {PC_FK_CH, 0, 0, nullptr}

Definition at line 107 of file frame.h.

◆ PC_JSON

#define PC_JSON   {PC_FK_JSON, 0, 0, nullptr}

Definition at line 108 of file frame.h.

◆ PC_XML

#define PC_XML   {PC_FK_XML, 0, 0, nullptr}

Definition at line 109 of file frame.h.

◆ PC_END

#define PC_END   {PC_FK_END, 0, 0, nullptr}

Definition at line 110 of file frame.h.

Enumeration Type Documentation

◆ pc_fk

enum pc_fk : uint8_t

Field kinds. The value is an opcode, so this is deliberately a plain byte enum.

Enumerator
PC_FK_END 

terminator; takes no argument

PC_FK_LIT 

literal text from lit; takes no argument

PC_FK_STR 

const char * (NULL renders as empty)

PC_FK_U32 

uint32_t, plain decimal

PC_FK_U64 

uint64_t, plain decimal

PC_FK_I64 

int64_t, signed decimal

PC_FK_DEC 

uint32_t, decimal zero-padded to width

PC_FK_HEX 

uint64_t, lowercase hex zero-padded to width

PC_FK_OCT 

uint64_t, octal zero-padded to width

PC_FK_G 

double, printf %.<width>g (width 0 means 6)

PC_FK_FIX 

double, printf %.<width>f

PC_FK_CH 

char

PC_FK_JSON 

const char *, emitted as a quoted JSON string literal

PC_FK_XML 

const char *, XML-escaped

Definition at line 53 of file frame.h.

Function Documentation

◆ pc_frame_build()

size_t pc_frame_build ( char *  out,
size_t  cap,
const pc_field spec,
  ... 
)

Build spec into out (capacity cap), taking one variadic argument per valued field.

Returns
bytes written, or 0 if the frame did not fit (in which case out is set empty).

Definition at line 100 of file frame.cpp.

References pc_frame_vbuild().

◆ pc_frame_vbuild()

size_t pc_frame_vbuild ( char *  out,
size_t  cap,
const pc_field spec,
va_list  ap 
)

◆ pc_frame_append()

size_t pc_frame_append ( char *  out,
size_t  cap,
const pc_field spec,
  ... 
)

Append spec to the NUL-terminated contents already in out.

The append idiom this library uses for header and cookie accumulation: on overflow the buffer is rewound to its previous length, so a frame is added whole or not at all and a half-written line never reaches the wire.

Returns
the new total length, or 0 if the frame did not fit (previous contents preserved).

Definition at line 109 of file frame.cpp.

References pc_frame_vbuild().