-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdemo.cpp
More file actions
103 lines (92 loc) · 3.99 KB
/
Copy pathdemo.cpp
File metadata and controls
103 lines (92 loc) · 3.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// demo.cpp — Erlang bit syntax, side by side with its erlbits equivalent.
//
// NOTE: this file requires a C++26 compiler with P2996 reflection AND
// annotation support enabled (see README.md). It will not compile with
// today's mainstream compilers — that's expected, since the feature it's
// demonstrating doesn't exist yet outside experimental branches. The parts
// of erlbits.hpp this demo exercises (bit_writer/bit_reader) are already
// unit-tested separately in bitcore_test.cpp.
#include "erlbits.hpp"
#include <cstdint>
#include <vector>
#include <iostream>
#include <iomanip>
using namespace bitsyntax;
// ---------------------------------------------------------------------------
// Example 1 — a simple packet header.
//
// Erlang:
// pack(Version, Type, Len, Body) ->
// <<Version:4, Type:4, Len:16, Body/binary>>.
//
// unpack(Bin) ->
// <<Version:4, Type:4, Len:16, Body/binary>> = Bin,
// {Version, Type, Len, Body}.
// ---------------------------------------------------------------------------
struct Packet {
std::uint8_t version [[=bits{4}]];
std::uint8_t type [[=bits{4}]];
std::uint16_t length [[=bits{16}]];
std::vector<std::byte> body [[=rest]];
};
// ---------------------------------------------------------------------------
// Example 2 — literal ("magic number") matching, sign, and endianness.
//
// Erlang:
// <<16#89504E47:32, Width:32/little, Height:32/little, Depth:8/signed>> = Bin
// (loosely: a PNG-flavored header with a little-endian width/height and a
// signed depth field, just to exercise /signed and /little together)
// ---------------------------------------------------------------------------
struct ImageHeader {
std::uint32_t magic [[=bits{32}, =expect<std::uint32_t>{0x89504E47}]];
std::uint32_t width [[=bits{32}, =little]];
std::uint32_t height [[=bits{32}, =little]];
std::int8_t depth [[=bits{8}, =is_signed]];
};
// ---------------------------------------------------------------------------
// Example 3 — unit multiplier, like Erlang's `Size/unit:Unit`.
//
// Erlang:
// <<Checksum:4/unit:8, Rest/binary>> = Bin % Checksum is 4*8 = 32 bits
// ---------------------------------------------------------------------------
struct Frame {
std::uint32_t checksum [[=bits{4}]] [[=unit{8}]]; // 4 * 8 = 32 bits
std::vector<std::byte> payload [[=rest]];
};
static void hex_dump(const std::vector<std::byte>& b) {
for (auto byte : b) std::cout << std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(static_cast<unsigned char>(byte)) << " ";
std::cout << std::dec << "\n";
}
int main() {
// --- Packet: pack then unpack, round trip ---
Packet p{.version = 10, .type = 3, .length = 0x1234,
.body = {std::byte{'h'}, std::byte{'i'}}};
auto packed = pack(p);
std::cout << "Packet bytes: ";
hex_dump(packed);
Packet p2 = unpack<Packet>(packed);
std::cout << "Round-tripped: version=" << (int)p2.version
<< " type=" << (int)p2.type
<< " length=0x" << std::hex << p2.length << std::dec
<< " body_len=" << p2.body.size() << "\n";
// --- ImageHeader: literal check + little-endian + signed ---
ImageHeader h{.magic = 0x89504E47, .width = 1920, .height = 1080, .depth = -8};
auto hbytes = pack(h);
ImageHeader h2 = unpack<ImageHeader>(hbytes); // throws match_error if magic is wrong
std::cout << "Image: " << h2.width << "x" << h2.height
<< " depth=" << (int)h2.depth << "\n";
// Corrupt the magic number and show the badmatch-style failure:
hbytes[0] = std::byte{0x00};
try {
unpack<ImageHeader>(hbytes);
} catch (const match_error& e) {
std::cout << "Expected failure: " << e.what() << "\n";
}
// --- Frame: unit multiplier ---
Frame f{.checksum = 0xDEADBEEF, .payload = {std::byte{1}, std::byte{2}, std::byte{3}}};
auto fbytes = pack(f);
std::cout << "Frame bytes: ";
hex_dump(fbytes);
return 0;
}