tiny.reticulum.carrier
Defined in tiny.reticulum.
The unit of bytes a node hands to one network interface, and an interface that keeps those bytes in memory.
API (21)
Actions
Public operations.
Frame.initFrame.sliceMemory.activateMemory.countMemory.deinitMemory.initMemory.popMemory.push
Types and contracts
Public types and contracts.
FrameFrame.InitErrorIndexMemoryMemory.CapacityMemory.ExhaustionMemory.InitErrorMemory.LimitsMemory.Storage
Values and defaults
Public values and defaults.
Memory.claimMemory.storage_alignmentMemory.work_limitsframe_bytes_max: 564 bytes, the most one frame holds, a 500-byte packet plus at most a 64-byte Ed25519 signature.
Source
Source: lib/reticulum/src/carrier/memory.zig:27
zig
pub const Memory = struct { phase: alloc_phase.capacity.Phase, capacity: MemoryCapacity, storage: Storage, frames: []carrier.Frame, start: usize = 0, len: usize = 0, pub const storage_alignment: usize = 8; pub const Storage = []align(storage_alignment) u8; pub const Limits: type = MemoryLimits; pub const Capacity: type = MemoryCapacity; pub const Exhaustion = error{Full}; pub const InitError = Capacity.DeriveError || error{StorageLengthMismatch}; pub const work_limits: alloc_phase.capacity.WorkLimits = .{ .transition_steps_max = 1, .cleanup_steps_per_call_max = 0, .cleanup_calls_at_capacity_max = 0, }; pub const claim: alloc_phase.capacity.Declaration = .{ .source = .{ .id = "reticulum.carrier_memory", .kind = .phase_static, .limit_source = .caller, .storage = .{ .covered = &.{.{ .id = "caller_frame_fifo", .lifetime = .transferred, .detail = "caller storage for a bounded FIFO of inline carrier frames", }}, .excluded = &.{ "caller frame inputs and returned frame values", "interface devices and operating-system transport state", }, }, .capacity = .{ .inputs = &.{alloc_phase.capacity.bindInput( Limits, "frames_max", "frames_max", )}, .type_selectors = &.{alloc_phase.capacity.bindType(carrier.Frame, "frame")}, .nodes = &.{ .{ .input = 0 }, .{ .scale = .{ .node = 0, .coefficient = .{ .size_of_concrete_type = 0 }, } }, }, .assertions = &.{.{ .scope = .closure_total, .measure = .retained, .relation = .exact, .expression = 1, }}, }, .overload = .{ .kind = .reject_before_mutation, .detail = "full frame admission preserves the retained FIFO", }, .risks = .{ .transitive = .{ .status = .excluded, .detail = "carrier memory calls no allocating owner", }, .foreign = .{ .status = .excluded, .detail = "carrier memory crosses no operating-system boundary", }, }, .work = .{ .equation = "push and pop each perform one bounded transition" }, .obligations = &.{ .{ .key = "reticulum_carrier_memory_capacity", .role = .capacity_model }, .{ .key = "reticulum_carrier_memory_overload", .role = .overload }, .{ .key = "reticulum_carrier_memory_work", .role = .work_bound }, }, }, .bindings = .{ .owner = @This(), .seal = .{ .family = alloc_phase.capacity.selector(@This().activate), .premise = .{ .class = .checked_semantic_fact, .authority = .checker }, }, .teardown = .{ .family = alloc_phase.capacity.selector(@This().deinit), .premise = .{ .class = .checked_semantic_fact, .authority = .checker }, }, }, }; pub fn init(storage: Storage, limits: Limits) InitError!Memory { const capacity = try Capacity.derive(limits); if (storage.len != capacity.storage_bytes) return error.StorageLengthMismatch; const frames = std.mem.bytesAsSlice(carrier.Frame, storage); for (frames) |*frame| frame.* = .{}; return .{ .phase = .initialization, .capacity = capacity, .storage = storage, .frames = frames, }; } pub fn activate(self: *Memory) void { std.debug.assert(self.phase == .initialization); std.debug.assert(self.len == 0); self.phase = .steady; } pub fn push(self: *Memory, frame: carrier.Frame) Exhaustion!void { std.debug.assert(self.phase == .steady); std.debug.assert(self.len <= self.capacity.frames_max); if (self.len == self.capacity.frames_max) return error.Full; const index = (self.start + self.len) % self.capacity.frames_max; self.frames[index] = frame; self.len += 1; } pub fn pop(self: *Memory) ?carrier.Frame { std.debug.assert(self.phase == .steady); std.debug.assert(self.len <= self.capacity.frames_max); if (self.len == 0) return null; const frame = self.frames[self.start]; self.start = (self.start + 1) % self.capacity.frames_max; self.len -= 1; return frame; } pub fn count(self: *const Memory) usize { std.debug.assert(self.phase == .steady); return self.len; } pub fn deinit(self: *Memory) Storage { std.debug.assert(self.phase == .steady); self.phase = .teardown; const storage = self.storage; self.* = undefined; return storage; }};Source: lib/reticulum/src/carrier/root.zig
zig
//! The unit of bytes a node hands to one network interface, and an interface//! that keeps those bytes in memory.//!//! A Reticulum node sends over whatever moves bytes, a radio, a serial line, or//! a socket, so the code above the interface deals in one unit and one index,//! whatever the device. That unit has to have a size the program knows before//! it starts, because a node holds those units in storage the caller supplied.//! Testing a protocol needs an interface that gives the same answer on every//! run.//!//! One unit runs longer than the 500-byte packet inside it, because a closed//! network appends an authentication code of up to 64 bytes. A real device//! brings a clock and a driver with it, and both make a test answer differently//! from one run to the next.//!//! The subtree follows Reticulum 1.5.0, the reference implementation, pinned to//! one upstream commit by the package README and the generated conformance//! corpus. What it takes is the frame bound of Reticulum@1.5.0//! RNS/Transport.py:1247 and Reticulum@1.5.0 RNS/Reticulum.py:800.//!//! Each unit (a *frame*) is one fixed 564-byte value with a length beside it,//! holding one packet plus at most a 64-byte signature, so a queue of frames is//! a plain array in caller storage. The in-memory interface is a bounded queue//! carved out of caller storage, which hands frames back in the order it took//! them and refuses a frame once it is full, leaving what it holds untouched.//! The subtree names its pieces: the frame bound, the carrier index, the frame,//! and the in-memory interface.//!//! - *carrier*: one network interface a node sends and receives frames over,//! named by a byte index.const wire = @import("../wire/root.zig");/// 564 bytes, the most one frame holds, a 500-byte packet plus at most a/// 64-byte Ed25519 signature. A frame is the bytes handed to one network/// interface. A caller sizes the buffer it reads an arriving frame into, and/// the storage it hands the in-memory interface, by this bound, following/// Reticulum@1.5.0 RNS/Transport.py:1247 and Reticulum@1.5.0/// RNS/Reticulum.py:800.pub const frame_bytes_max: usize = @as(usize, wire.mtu) + 64;pub const Index = u8;pub const Frame = struct { bytes: [frame_bytes_max]u8 = @splat(0), len: u16 = 0, pub const InitError = error{TooLong}; pub fn init(bytes: []const u8) InitError!Frame { if (bytes.len > frame_bytes_max) return error.TooLong; var frame = Frame{}; @memcpy(frame.bytes[0..bytes.len], bytes); frame.len = @intCast(bytes.len); return frame; } pub fn slice(self: *const Frame) []const u8 { std.debug.assert(self.len <= frame_bytes_max); return self.bytes[0..self.len]; }};const std = @import("std");pub const Memory = @import("memory.zig").Memory;Source: lib/reticulum/src/root.zig:58
zig
pub const carrier = @import("carrier/root.zig");Audit
| Definitions | 22 |
|---|---|
| Public names | 22 |
| Members | 10 |
| Version | 26.7.0 |
| Revision | daab053ee433 |