lib/reticulum/src/wire/flags.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 
  3 pub const HeaderType = enum(u1) {
  4     one = 0,
  5     two = 1,
  6 };
  7 
  8 pub const TransportType = enum(u1) {
  9     broadcast = 0,
 10     transport = 1,
 11 };
 12 
 13 pub const DestinationType = enum(u2) {
 14     single = 0,
 15     group = 1,
 16     plain = 2,
 17     link = 3,
 18 };
 19 
 20 pub const PacketType = enum(u2) {
 21     data = 0,
 22     announce = 1,
 23     link_request = 2,
 24     proof = 3,
 25 };
 26 
 27 pub const Flags = struct {
 28     ifac: u1,
 29     header: HeaderType,
 30     context: u1,
 31     transport: TransportType,
 32     destination: DestinationType,
 33     packet: PacketType,
 34 
 35     /// Packs the six flag fields into the byte that leads a packet header: the
 36     /// access-code flag at bit 7, the header shape at bit 6, the context flag
 37     /// at bit 5, whether the packet is carried for another node at bit 4, the
 38     /// destination type at bits 3 and 2, and the packet type at bits 1 and 0,
 39     /// for a caller building that header, following Reticulum@1.5.0
 40     /// RNS/Packet.py:172-174.
 41     pub fn encode(self: Flags) u8 {
 42         return (@as(u8, self.ifac) << 7) |
 43             (@as(u8, @backingInt(self.header)) << 6) |
 44             (@as(u8, self.context) << 5) |
 45             (@as(u8, @backingInt(self.transport)) << 4) |
 46             (@as(u8, @backingInt(self.destination)) << 2) |
 47             @as(u8, @backingInt(self.packet));
 48     }
 49 
 50     /// Reads the six flag fields back out of the first byte of an arriving
 51     /// packet, at the bit positions the packing uses, following Reticulum@1.5.0
 52     /// RNS/Packet.py:251-255. Every bit pattern names a value in its field, so
 53     /// any byte decodes and encodes back to itself.
 54     pub fn decode(byte: u8) Flags {
 55         return .{
 56             .ifac = @truncate(byte >> 7),
 57             .header = @fromBackingInt(@intCast(@as(u1, @truncate(byte >> 6)))),
 58             .context = @truncate(byte >> 5),
 59             .transport = @fromBackingInt(@intCast(@as(u1, @truncate(byte >> 4)))),
 60             .destination = @fromBackingInt(@intCast(@as(u2, @truncate(byte >> 2)))),
 61             .packet = @fromBackingInt(@intCast(@as(u2, @truncate(byte)))),
 62         };
 63     }
 64 };
 65 
 66 test "Reticulum@1.5.0 RNS/Packet.py:172-174 packs each header type" {
 67     const base = Flags{
 68         .ifac = 0,
 69         .header = .one,
 70         .context = 0,
 71         .transport = .broadcast,
 72         .destination = .single,
 73         .packet = .data,
 74     };
 75     try std.testing.expectEqual(@as(u8, 0x00), base.encode());
 76     var header_two = base;
 77     header_two.header = .two;
 78     try std.testing.expectEqual(@as(u8, 0x40), header_two.encode());
 79 }
 80 
 81 test "Reticulum@1.5.0 RNS/Packet.py:172-174 packs each destination type" {
 82     var value = Flags{
 83         .ifac = 0,
 84         .header = .one,
 85         .context = 0,
 86         .transport = .broadcast,
 87         .destination = .single,
 88         .packet = .data,
 89     };
 90     for ([_]u8{ 0x00, 0x04, 0x08, 0x0c }, 0..) |expected, raw| {
 91         value.destination = @fromBackingInt(@intCast(@as(u2, @intCast(raw))));
 92         try std.testing.expectEqual(expected, value.encode());
 93     }
 94 }
 95 
 96 test "Reticulum@1.5.0 RNS/Packet.py:60-63,172 packs each packet type" {
 97     var value = Flags{
 98         .ifac = 0,
 99         .header = .one,
100         .context = 0,
101         .transport = .broadcast,
102         .destination = .single,
103         .packet = .data,
104     };
105     for ([_]u8{ 0x00, 0x01, 0x02, 0x03 }, 0..) |expected, raw| {
106         value.packet = @fromBackingInt(@intCast(@as(u2, @intCast(raw))));
107         try std.testing.expectEqual(expected, value.encode());
108     }
109 }
110 
111 test "Reticulum@1.5.0 RNS/Packet.py:251-255 preserves every flag bit" {
112     const decoded = Flags.decode(0xff);
113     try std.testing.expectEqual(@as(u1, 1), decoded.ifac);
114     try std.testing.expectEqual(HeaderType.two, decoded.header);
115     try std.testing.expectEqual(@as(u1, 1), decoded.context);
116     try std.testing.expectEqual(TransportType.transport, decoded.transport);
117     try std.testing.expectEqual(DestinationType.link, decoded.destination);
118     try std.testing.expectEqual(PacketType.proof, decoded.packet);
119     try std.testing.expectEqual(@as(u8, 0xff), decoded.encode());
120 }