alloc_phase.input
Internal implementation documentation
Defined in alloc_phase.
Package overview
API (5)
Actions
Public operations.
OneRegion: Constructs an allocator-backed owner type for a single reusable input buffer based on a static specification structure.deriveCapacity: Derives an instance ofCapacityfrom a givenLimitsstructure by adding one lookahead byte to the configured input limit.
Types and contracts
Public types and contracts.
Acquisition: Packed boolean structure that enables specific input capabilities on an owner at compile time.DeriveError: Error set returned when capacity derivation fails.Overload: Defines the policy applied when an input exceeds the configured capacity limit.
Source
Source: lib/alloc/phase/src/input/one.zig:46
zig
/// Packed boolean structure that enables specific input capabilities on an/// owner at compile time. All four fields default to `false`:////// * `reader`: Enables stream acquisition through `read`.////// * `file`: Enables filesystem acquisition through `readFile` and/// `readFileWindow`./// * `preflight`: Enables size admission checks through `preflight`./// * `map_file_too_big`: Maps `error.FileTooBig` from an underlying `readFile`/// call into a capacity rejection instead of propagating the raw I/O error.////// Because an owner must support at least one input mechanism, specification/// validation requires either `reader` or `file` to be enabled. Mapping/// file-size errors requires filesystem support, so `map_file_too_big` can be/// enabled only when `file` is also set to `true`. Individual acquisition/// methods verify their corresponding flags at compile time and raise a compile/// error when invoked without the required capability enabled.pub const Acquisition = packed struct { reader: bool = false, file: bool = false, preflight: bool = false, map_file_too_big: bool = false,};Source: lib/alloc/phase/src/input/one.zig:27
zig
/// Error set returned when capacity derivation fails.////// Members:////// * `CapacityOverflow`: Adding one lookahead byte to the configured byte limit/// overflowed the range of `usize`.pub const DeriveError = error{CapacityOverflow};Source: lib/alloc/phase/src/input/one.zig:68
zig
/// Defines the policy applied when an input exceeds the configured capacity/// limit.////// Tags:////// * `terminal`: Permanently seals the owner upon capacity rejection. Any/// subsequent acquisition attempt returns the capacity error immediately/// without performing I/O or incrementing rejection counters./// * `recoverable`: Preserves owner availability across rejections. Oversized/// inputs increment the rejection counter but leave the underlying storage free/// for subsequent attempts.////// Recovery designates the ability to reuse the allocated storage for later/// inputs. It does not provide source-position rollback, record framing, or/// automatic input drainage.pub const Overload = enum { terminal, recoverable,};Source: lib/alloc/phase/src/input/one.zig:158
zig
/// Constructs an allocator-backed owner type for a single reusable input buffer/// based on a static specification structure.////// The `Spec` type parameter must satisfy several structural requirements:////// * `Limits`: Structure defining input limits. It must contain the field/// designated by `limit_field` typed as `usize`./// * `Capacity`: Structure defining storage requirements. It must expose a/// `derive(limits: Limits) DeriveError!Capacity` function, the field named by/// `limit_field` typed as `usize`, and `storage_bytes` typed as `usize`./// * `DeriveError`: Error set returned by `Capacity.derive`./// * `Exhaustion`: Error set returned when storage cannot admit an input./// * `Status`: Reporting structure returned by `status`. It must be a struct/// containing exactly seven fields for recoverable owners or eight fields for/// terminal owners: `phase: alloc_phase.capacity.Phase`, `in_use: bool`,/// `storage_bytes: usize`, the mapped limit, loaded, and high-water fields/// typed as `usize`, the mapped rejection field typed as `u64`, and/// conditionally `terminal: bool` when `overload` is `terminal`./// * `acquisition`: An instance of `Acquisition` specifying enabled I/O/// capabilities./// * `overload`: An instance of `Overload` setting either `.terminal` or/// `.recoverable` behavior./// * Field mappings: `limit_field`, `loaded_field`, `high_water_field`, and/// `rejected_field` specify field names on `Capacity` or `Status`. Callers must/// supply distinct names for these fields. Compile-time validation verifies/// field presence and total field counts, but this validation does not prove/// that mapped field names are mutually distinct./// * Error instances: `in_use_error` and `capacity_error` must both have type/// `Spec.Exhaustion`./// * `claim`: A static `alloc_phase.capacity.Declaration` metadata descriptor.////// The owner asserts that `storage_bytes` strictly exceeds the configured byte/// limit. While standard `deriveCapacity` derivation provides an exact `limit +/// 1` layout, custom `Capacity.derive` implementations may describe larger/// storage: derivation computes a `Capacity` value, while `init` allocates.////// A successful read operation returns a borrowed `[]const u8` slice pointing/// directly into the owned buffer and marks the owner as in use, including when/// the input is empty. Borrowers must consume or copy these bytes elsewhere/// before calling `release`. Slices must not be accessed after releasing the/// owner.////// A struct copy shares allocated storage but duplicates internal bookkeeping./// Copies are not independent owners: transferring exclusive ownership requires/// callers to stop using the original. Callers must serialize operations and/// ensure cleanup occurs exactly once.////// The owner is not thread-safe and performs no internal synchronization./// Callers accessing an owner across threads must provide external mutual/// exclusion.////// Lifecycle checks across initialization, steady operation, and teardown are/// enforced through debug assertions rather than explicit always-executed phase/// panics.pub fn OneRegion(comptime Spec: type) type { comptime requireSpec(Spec); return struct { phase: alloc_phase.capacity.Phase, capacity: Spec.Capacity, bytes: []u8, in_use: bool = false, terminal: bool = false, loaded_bytes: usize = 0, high_water_bytes: usize = 0, rejected_count: u64 = 0, const Self = @This(); /// Result structure returned by `readFileWindow` representing a bounded /// slice of a file read at a positional offset. /// /// Fields: /// /// * `bytes`: Borrowed const byte slice containing admitted data. Its /// length is at most the requested window size. /// * `complete`: Boolean flag set to `true` when `read_bytes <= /// window_bytes`. /// /// The `complete` flag describes only this positional read and does not /// make an immutable snapshot against concurrent modification during or /// after it. pub const FileWindow = struct { bytes: []const u8, complete: bool, }; /// Type alias for `Spec.Limits`. Defines the input limit constraints /// supplied by the caller. pub const Limits: type = Spec.Limits; /// Type alias for `Spec.Capacity`. Holds derived storage dimensions, /// including the mandatory `storage_bytes` field. pub const Capacity: type = Spec.Capacity; /// Type alias for `Spec.Exhaustion`. Represents the error set returned /// when input operations encounter a busy buffer or exceed configured /// capacity. pub const Exhaustion: type = Spec.Exhaustion; /// Error set representing failures that can occur during /// initialization. Combines allocator allocation errors with /// `Spec.DeriveError`. pub const InitError = std.mem.Allocator.Error || Spec.DeriveError; /// Static capacity declaration describing the memory allocation /// semantics of the generated owner. /// /// The declaration retains the complete `Spec.claim.source` envelope /// while establishing fresh bindings for the generated owner: /// /// * `owner`: Binds the generated owner type `Self`. /// * `source`: Binds the originating `Spec` configuration type. /// * `seal`: Binds the `activate` method selector under the /// `checked_semantic_fact` class with `checker` authority. /// * `teardown`: Binds the `deinit` method selector under the /// `checked_semantic_fact` class with `checker` authority. /// /// The bindings defined on `Spec.claim.bindings` are not reused. /// Assigning premise labels to these new bindings does not prove their /// truth. Local specification checks verify only that `claim` has type /// `alloc_phase.capacity.Declaration`. Separate structural and /// declaration checking verifies lifecycle declaration shape, but that /// check does not prove whole-program allocation freedom. pub const claim: alloc_phase.capacity.Declaration = .{ .source = Spec.claim.source, .bindings = .{ .owner = Self, .source = Spec, .seal = .{ .family = alloc_phase.capacity.selector(Self.activate), .premise = .{ .class = .checked_semantic_fact, .authority = .checker, }, }, .teardown = .{ .family = alloc_phase.capacity.selector(Self.deinit), .premise = .{ .class = .checked_semantic_fact, .authority = .checker, }, }, }, }; /// Initializes a new input region by deriving capacity and allocating /// the backing byte slice. /// /// The function derives capacity by evaluating /// `Capacity.derive(limits)`. When derivation succeeds, it allocates /// `capacity.storage_bytes` through the provided allocator. The /// initialized owner enters the `.initialization` phase and retains the /// allocated slice. The allocator handle itself is not stored on the /// instance, so callers must provide the same allocator during /// deinitialization. /// /// Initialization fails with `Spec.DeriveError` if capacity derivation /// fails, or with `error.OutOfMemory` if memory allocation fails. /// Before returning, debug assertions verify that the allocated slice /// length equals `storage_bytes` and strictly exceeds the configured /// byte limit. pub fn init(allocator: std.mem.Allocator, limits: Limits) InitError!Self { const capacity = try Capacity.derive(limits); const bytes = try allocator.alloc(u8, capacity.storage_bytes); const storage = Self{ .phase = .initialization, .capacity = capacity, .bytes = bytes, }; storage.assertRegion(); return storage; } /// Transitions the owner from the initialization phase into steady /// operation. /// /// Callers must activate the owner before performing input operations. /// The function verifies through debug assertions that the owner /// resides in the `.initialization` phase and that the backing buffer /// satisfies region invariants. Once activated, `phase` transitions to /// `.steady`, permitting acquisition calls. pub fn activate(self: *Self) void { std.debug.assert(self.phase == .initialization); self.assertRegion(); self.phase = .steady; } /// Performs a size admission check for an expected input length without /// executing I/O or modifying buffer contents. /// /// This method requires `Spec.acquisition.preflight` to be enabled at /// compile time. Before evaluating the size, it verifies that the owner /// is available in steady operation. If an operation is currently /// active, it returns `Spec.in_use_error`. If the owner was previously /// sealed in a terminal state, it returns `Spec.capacity_error`. /// /// The proposed length `input_bytes` is cast to `usize`. If the value /// overflows `usize` or exceeds the configured byte limit, the method /// invokes internal rejection, incrementing the saturating rejection /// counter and applying the configured overload policy before returning /// `Spec.capacity_error`. /// /// A successful preflight check confirms only that the proposed size /// fits within the configured limit. It does not reserve storage, lock /// the buffer, or establish an atomic guarantee between checking a size /// and executing a later read. pub fn preflight(self: *Self, input_bytes: u64) Exhaustion!void { comptime requireAcquisition(Spec.acquisition.preflight, "preflight"); try self.requireAvailable(); const bounded = std.math.cast(usize, input_bytes) orelse return self.reject(); if (bounded > self.limitBytes()) return self.reject(); } /// Reads data from a stream reader into the owned buffer and admits the /// resulting slice if its length falls within the configured limit. /// /// This method requires `Spec.acquisition.reader` to be enabled at /// compile time. It requires the owner to be available in steady /// operation, returning `Spec.in_use_error` if an active borrow exists /// or `Spec.capacity_error` if the owner is terminal. /// /// The method invokes `reader.readSliceShort` over the allocated /// storage slice. If reading from the underlying stream returns a /// `ShortError` such as `ReadFailed`, that error propagates directly to /// the caller. A read failure can occur after writing bytes into the /// buffer and consuming bytes from the stream, without establishing a /// borrow or recording a rejection. The method promises neither buffer /// rollback nor stream rewind nor record framing. /// /// When reading completes without stream error, the read byte count is /// evaluated: /// /// * If the count is at most the configured limit, the slice /// `self.bytes[0..input_bytes]` is admitted. The owner records the /// loaded length, updates the high-water mark, sets `in_use` to `true`, /// and returns the borrowed slice. /// * If the count exceeds the configured limit, the method rejects the /// input. It increments the rejection counter, transitions to terminal /// if configured, and returns `Spec.capacity_error`. /// /// When using helper-based capacity derivation through /// `deriveCapacity`, an oversized input fills the `limit + 1` storage /// bytes and triggers a capacity rejection after reading. This consumes /// `limit + 1` bytes from the stream without draining trailing input. /// Because reader implementations may buffer additional data, /// subsequent reads cannot assume framing alignment with a subsequent /// record. pub fn read( self: *Self, reader: *std.Io.Reader, ) (Exhaustion || std.Io.Reader.ShortError)![]const u8 { comptime requireAcquisition(Spec.acquisition.reader, "reader"); try self.requireAvailable(); const input_bytes = try reader.readSliceShort(self.bytes); return try self.admit(input_bytes); } /// Reads a file from a directory into the bounded buffer and admits the /// resulting slice if the read length does not exceed the configured /// limit. /// /// This method requires `Spec.acquisition.file` to be enabled at /// compile time. It checks that the owner is available in steady /// operation before opening the file. /// /// Reading is executed through `dir.readFile` into the allocated buffer /// slice. Under the pinned standard library implementation, an ordinary /// oversized file fills the buffer prefix before admission rejects the /// input. Opening errors propagate directly, while a read error can /// occur after partial buffer writes and no borrow is admitted. /// /// Handling of `error.FileTooBig` depends on compile-time /// configuration: /// /// * When `Spec.acquisition.map_file_too_big` is `true`, /// `error.FileTooBig` is converted into a capacity rejection. This /// increments the rejection counter, transitions to terminal if /// configured, and returns `Spec.capacity_error`. /// * When `Spec.acquisition.map_file_too_big` is `false`, /// `error.FileTooBig` propagates directly to the caller without /// incrementing the rejection counter or modifying terminal state. /// /// All other filesystem I/O errors propagate directly to the caller /// without a capacity rejection or terminal transition under either /// setting. On success, the method returns a borrowed slice of the /// admitted bytes and marks the owner as in use. pub fn readFile( self: *Self, dir: std.Io.Dir, io: std.Io, file_path: []const u8, ) ![]const u8 { comptime requireAcquisition(Spec.acquisition.file, "file"); try self.requireAvailable(); const file = if (comptime Spec.acquisition.map_file_too_big) dir.readFile(io, file_path, self.bytes) catch |err| switch (err) { error.FileTooBig => return self.reject(), else => return err, } else try dir.readFile(io, file_path, self.bytes); return try self.admit(file.len); } /// Reads a bounded positional window from a file at a specified offset /// without treating trailing bytes as a capacity rejection. /// /// This method requires `Spec.acquisition.file` to be enabled at /// compile time. Callers must supply a window size satisfying `0 < /// window_bytes <= limit`, which debug assertions verify. The owner /// must be available in steady operation before opening the target /// file. /// /// The method opens the file and reads up to `window_bytes + 1` bytes /// at the specified offset using positional I/O into `self.bytes[0 .. /// window_bytes + 1]`. Any filesystem I/O error during open or read /// propagates directly to the caller without a capacity rejection or /// borrow, though the buffer may be partially written. /// /// The read byte count determines completion and admission: /// /// * If the number of read bytes is less than or equal to /// `window_bytes`, `complete` is set to `true`. /// * If reading produces `window_bytes + 1` bytes, additional data /// exists beyond the window, setting `complete` to `false`. This /// condition does not trigger a capacity rejection or modify terminal /// status, even on terminal owners. /// /// The method admits `@min(read_bytes, window_bytes)`, which marks the /// owner as in use and returns a borrowed slice. An immediate EOF /// returning zero bytes still establishes an admitted zero-byte borrow. /// The `complete` flag describes only this positional read and is not /// an instantaneous snapshot against concurrent modifications. pub fn readFileWindow( self: *Self, dir: std.Io.Dir, io: std.Io, file_path: []const u8, offset: u64, window_bytes: usize, ) !FileWindow { comptime requireAcquisition(Spec.acquisition.file, "file"); try self.requireAvailable(); std.debug.assert(window_bytes > 0); std.debug.assert(window_bytes <= self.limitBytes()); var file = try dir.openFile(io, file_path, .{}); defer file.close(io); const read_bytes = try file.readPositionalAll( io, self.bytes[0 .. window_bytes + 1], offset, ); const complete = read_bytes <= window_bytes; const admitted = try self.admit(@min(read_bytes, window_bytes)); return .{ .bytes = admitted, .complete = complete }; } /// Releases an active borrow, allowing the internal buffer to be reused /// by future input operations. /// /// Callers must call this method only when the owner is in the /// `.steady` phase, holds an active borrow (`in_use` is `true`), and is /// not in a terminal state. Debug assertions verify these /// preconditions. /// /// Calling release sets `in_use` to `false` and resets `loaded_bytes` /// to zero. It does not overwrite or sanitize existing byte values in /// the buffer. Historical tracking metrics, including the high-water /// mark and the cumulative rejection count, remain intact across /// release calls. pub fn release(self: *Self) void { std.debug.assert(self.phase == .steady); std.debug.assert(self.in_use); std.debug.assert(!self.terminal); self.in_use = false; self.loaded_bytes = 0; } /// Constructs and returns a snapshot of owner metrics and lifecycle /// state as a `Spec.Status` structure. /// /// The method copies configured status fields by value under caller /// serialization. Because the owner does not use atomic operations or /// internal synchronization, this method does not produce a coherent /// snapshot across concurrent unsynchronized access. /// /// The returned snapshot contains the following fields: /// /// * `phase`: Current lifecycle phase (`.initialization`, `.steady`, or /// `.teardown`). /// * `in_use`: Boolean flag indicating whether a borrowed buffer slice /// is currently outstanding. /// * `terminal`: Present on terminal owners to indicate whether /// capacity exhaustion permanently sealed the owner. /// * Configured limit field: Configured maximum byte limit derived from /// capacity. /// * `storage_bytes`: Total declared capacity of the buffer. Because /// this value reflects declared specification capacity, it does not /// represent a live allocation measurement and remains readable after /// teardown. /// * Configured loaded field: Number of admitted bytes currently held /// by an active borrow. This field is zero whenever the owner is not in /// use. /// * Configured high-water field: Largest admitted byte count observed /// across all successful reads since initialization. Oversized inputs /// rejected during admission do not update this value. /// * Configured rejected field: Cumulative saturating count of capacity /// rejections. pub fn status(self: *const Self) Spec.Status { var result: Spec.Status = undefined; result.phase = self.phase; result.in_use = self.in_use; if (comptime @hasField(Spec.Status, "terminal")) { result.terminal = self.terminal; } @field(result, Spec.limit_field) = self.limitBytes(); result.storage_bytes = self.capacity.storage_bytes; @field(result, Spec.loaded_field) = self.loaded_bytes; @field(result, Spec.high_water_field) = self.high_water_bytes; @field(result, Spec.rejected_field) = self.rejected_count; return result; } /// Deinitializes the owner and frees its allocated byte buffer using /// the provided allocator. /// /// Callers must supply the same allocator used for `init`. The method /// verifies through debug assertions that the owner has not already /// entered teardown and that no borrowed slice is currently in use /// (`in_use` is `false`). /// /// Deinitialization transitions `phase` to `.teardown`, frees the /// allocated memory slice, clears the internal buffer slice to empty, /// and resets `loaded_bytes` to zero. Callers may invoke this method /// while the owner is still in the `.initialization` phase to clean up /// resources after a failed startup sequence. Cumulative metrics and /// capacity declarations remain stored on the instance after /// deinitialization completes. pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { std.debug.assert(self.phase != .teardown); std.debug.assert(!self.in_use); self.assertRegion(); self.phase = .teardown; allocator.free(self.bytes); self.bytes = &.{}; self.loaded_bytes = 0; } /// Verifies that the owner is ready to accept a new input operation. /// /// Debug assertions confirm that the owner resides in the `.steady` /// phase, that buffer invariants hold, and that previous loaded bytes /// did not exceed the limit. If the owner is marked terminal, the /// function returns `Spec.capacity_error` without incrementing the /// rejection counter. If a borrow is currently active, it returns /// `Spec.in_use_error` without incrementing the rejection counter. When /// available, debug assertions verify that `loaded_bytes` is zero. fn requireAvailable(self: *Self) Exhaustion!void { std.debug.assert(self.phase == .steady); self.assertRegion(); std.debug.assert(self.loaded_bytes <= self.limitBytes()); if (self.terminal) return Spec.capacity_error; if (self.in_use) return Spec.in_use_error; std.debug.assert(self.loaded_bytes == 0); } /// Admits a specified number of bytes into the region or rejects the /// payload if it exceeds the configured limit. /// /// Debug assertions verify that the owner is in steady operation /// without an active borrow or terminal state, and that the requested /// byte count does not exceed allocated storage. If `input_bytes` /// exceeds the configured byte limit, the function invokes `reject`. /// Otherwise, it marks the buffer as in use, records `loaded_bytes`, /// updates `high_water_bytes` if the new length exceeds previous /// admissions, and returns a borrowed slice over the admitted bytes. fn admit(self: *Self, input_bytes: usize) Exhaustion![]const u8 { std.debug.assert(self.phase == .steady); std.debug.assert(!self.in_use); std.debug.assert(!self.terminal); std.debug.assert(input_bytes <= self.capacity.storage_bytes); if (input_bytes > self.limitBytes()) return self.reject(); self.in_use = true; self.loaded_bytes = input_bytes; self.high_water_bytes = @max(self.high_water_bytes, input_bytes); return self.bytes[0..input_bytes]; } /// Records an input capacity rejection and updates owner overload /// state. /// /// Debug assertions verify that the owner is in steady operation, is /// not in use, is not already terminal, and holds zero loaded bytes. If /// `Spec.overload` is configured as `.terminal`, the owner enters the /// terminal state. The cumulative rejection counter is incremented /// using saturating addition, and the function returns /// `Spec.capacity_error`. fn reject(self: *Self) Exhaustion { std.debug.assert(self.phase == .steady); std.debug.assert(!self.in_use); std.debug.assert(!self.terminal); std.debug.assert(self.loaded_bytes == 0); self.terminal = Spec.overload == .terminal; self.rejected_count +|= 1; return Spec.capacity_error; } /// Helper function returning the configured byte limit stored on /// `self.capacity` using the field name defined by `Spec.limit_field`. fn limitBytes(self: *const Self) usize { return @field(self.capacity, Spec.limit_field); } /// Helper function asserting that the backing byte slice length matches /// `storage_bytes` and strictly exceeds the configured byte limit. fn assertRegion(self: *const Self) void { std.debug.assert(self.bytes.len == self.capacity.storage_bytes); std.debug.assert(self.capacity.storage_bytes > self.limitBytes()); } };}Source: lib/alloc/phase/src/input/one.zig:87
zig
/// Derives an instance of `Capacity` from a given `Limits` structure by adding/// one lookahead byte to the configured input limit.////// The input limit is retrieved from the field named by `limit_field` on/// `limits`. Both the limit field on `Limits` and `Capacity` and the/// `storage_bytes` field on `Capacity` must be typed as `usize`. When addition/// overflows `usize`, the function returns `error.CapacityOverflow`. A limit of/// zero derives a storage size of one byte.////// The returned `Capacity` structure initializes only the field named by/// `limit_field` and `storage_bytes`. Any additional fields present on/// `Capacity` remain undefined. Callers must keep `limit_field` distinct from/// `storage_bytes` so that writing `storage_bytes` does not overwrite the limit/// field.pub fn deriveCapacity( comptime Limits: type, comptime Capacity: type, comptime limit_field: []const u8, limits: Limits,) DeriveError!Capacity { comptime requireCapacityTypes(Limits, Capacity, limit_field); const limit_bytes = @field(limits, limit_field); const storage_bytes = try alloc_phase.capacity.add(usize, limit_bytes, 1); std.debug.assert(storage_bytes > limit_bytes); std.debug.assert(storage_bytes != 0); var capacity: Capacity = undefined; @field(capacity, limit_field) = limit_bytes; capacity.storage_bytes = storage_bytes; return capacity;}Source: lib/alloc/phase/src/input/root.zig
zig
//! ## Package overview//!//! When we ingest external input from streams or files, we want to accept//! bounded payloads using a single reusable byte allocation without allocating//! on every message or resizing buffers on the fly. We configure an explicit//! upper bound on accepted length, allocate storage once, and reuse that//! storage across successive operations while detecting oversized inputs before//! admitting them.//!//! ## One buffer and lookahead//!//! The core challenge in bounded ingestion sits at the boundary of the limit.//! If we configure our system to accept at most `n` bytes and allocate an//! `n`-byte buffer, filling that buffer completely leaves an ambiguity: did the//! input stream end precisely at `n` bytes, or does more data remain waiting in//! the channel? To resolve whether the input fits or exceeds our boundary, this//! implementation reserves space for one extra byte. For an accepted limit of//! `n` bytes, the backing buffer holds `n + 1` bytes. When we read from the//! source into the buffer://!//! - If the source yields between 0 and `n` bytes before reaching end-of-file,//! the input fits within our configured boundary and we admit it.//! - If the source yields `n + 1` bytes, the input exceeds our limit and we//! reject it immediately, without allocating a second buffer.//!//! We term this calculation *capacity derivation*. The standard helper//! `deriveCapacity` computes this boundary for an owner. Given a configuration//! structure containing a byte limit field of type `usize`, it uses checked//! integer addition to compute `n + 1`. If adding one to the limit overflows//! `usize`, derivation fails with `error.CapacityOverflow`. When a caller//! configures a limit of zero, derivation reserves one byte, which allows an//! empty input to be distinguished from an input containing data.//!//! The `deriveCapacity` helper initializes only two fields in the resulting//! capacity record: the configured limit and the derived `storage_bytes`. The//! limit field name and `storage_bytes` must be distinct. Any additional fields//! declared on the capacity type remain undefined, so a custom capacity type//! that requires extra fields must populate them in a custom derivation//! function.//!//! The generic container `OneRegion(Spec)` produces an allocator-backed owner//! around this storage model. While `deriveCapacity` enforces the standard `n +//! 1` sizing rule, a custom derivation function may describe larger storage//! when required by domain constraints: derivation computes a `Capacity` value,//! while `init` allocates the storage. The owner asserts that `storage_bytes`//! strictly exceeds the configured input limit.//!//! ## A successful borrow and release//!//! Because a single byte buffer is reused across requests, concurrent access//! would corrupt in-flight payloads. An outstanding borrow represents temporary//! exclusive access granted to an admitted input. Until that borrow is//! relinquished, the owner enforces busy protection across subsequent//! acquisition and preflight calls.//!//! The lifecycle of an input owner progresses through three sequential phases://! initialization, steady operation, and teardown. Calling `init` enters the//! initialization phase, calling `activate` advances to steady operation, and//! calling `deinit` enters teardown. Calling `deinit` requires that no borrow//! remains outstanding. If startup fails prior to activation, `deinit` can be//! called directly from the initialization phase to free the buffer.//!//! During initialization, `init` derives the capacity and requests a single//! contiguous slice of `storage_bytes` from the provided allocator. If capacity//! derivation overflows or the allocator fails, `init` returns an error union//! of `DeriveError` and `std.mem.Allocator.Error`. Once allocated, the owner//! retains the byte slice but does not retain an allocator handle. In steady//! operation, the owner methods do not call the initialization allocator. The//! absence of a retained allocator on the owner does not prevent arbitrary//! readers or filesystem code from allocating dynamically or performing//! external work.//!//! Phase transitions are guarded by debug assertions (`std.debug.assert`),//! which verify that `activate` is called only from the initialization phase//! and that `deinit` is called with no active borrow. These debug assertions//! differ from the explicit wrong-phase panics enforced by the separate phase//! allocator.//!//! In steady operation, calling `read` ingests data into the buffer and admits//! the payload if the returned length does not exceed the configured limit. A//! successful read returns a borrowed constant slice (`[]const u8`) and sets//! the internal `in_use` flag. Even an empty zero-byte read establishes an//! active borrow and marks the owner busy. While `in_use` remains true, any//! attempt to read, window, or preflight another input returns `in_use_error`.//! This failure indicates a busy owner and does not increment the capacity//! rejection counter.//!//! When the caller finishes processing the borrowed slice, it invokes//! `release`. Calling `release` sets `in_use` to false and resets the loaded//! byte counter to zero. It does not zero or scrub the underlying memory, nor//! does it reset historical rejection counts or high-water marks.//!//! Because reads overwrite the backing buffer, a caller that needs to retain//! admitted bytes across subsequent operations must copy them into separate//! storage before calling `release`. A fixed stack array provides a convenient//! target for preserving small records without allocating heap memory.//!//! Copies of an owner struct share the underlying byte slice while duplicating//! internal bookkeeping. Because copies are not independent owners, callers//! must serialize operations and ensure that cleanup occurs exactly once.//! Calling `deinit` requires that no borrow remains outstanding, transitions//! the phase to teardown, and frees the slice using the same allocator passed//! during initialization. The owner provides no secondary abort or partial//! teardown routines.//!//! In the Issue tool, body storage adopts this borrow discipline. Its//! `BodySource` container pairs a borrowed slice of the input region with an//! optional pointer to the owner. When processing finishes or an empty body//! triggers an early exit, the consumer releases the borrow before reporting//! results. Command-line arguments provided directly in the process invocation//! bypass the input region entirely, leaving the buffer available for file or//! standard-input ingestion.//!//! ## Failure and recovery//!//! When an incoming payload exceeds the configured limit, the owner rejects the//! admission. How the owner responds to this overload depends on whether it is//! configured with a terminal or recoverable policy://!//! - A terminal owner treats an oversized input as a permanent boundary fault.//! Upon rejection, it increments a saturating 64-bit rejection counter, sets//! an internal `terminal` flag, and refuses all subsequent read attempts with//! `capacity_error` without incrementing the counter again.//! - A recoverable owner increments the rejection counter but leaves `terminal`//! false. Storage remains immediately available to accept another input//! without an acknowledgement step.//!//! Recovery denotes the ability to reuse the owned memory buffer for a future//! request: it does not imply stream rewinding, transaction rollback, or//! automatic framing.//!//! When reading from a stream through `Reader.readSliceShort`, capacity//! rejection under the standard derivation helper occurs after reading up to//! `limit + 1` logical bytes into the buffer. The owner does not drain any//! remaining bytes left in the underlying stream. If an external caller//! attempts to read from that same stream again, the retry does not guarantee//! alignment with the start of a logical record. User reader implementations//! may also maintain internal buffers or perform dynamic allocations outside//! the owner's knowledge. If a stream encounters an I/O failure such as//! `ReadFailed`, the failure can consume source bytes and overwrite buffer//! contents. In that situation, no borrow is admitted and the owner's capacity//! rejection counter does not increment.//!//! To avoid reading unwanted bytes when an input size is known beforehand, an//! application can call `preflight`. The `preflight` method accepts an expected//! size as a 64-bit integer, checks that the owner is available, and verifies//! that the size fits within `usize` and does not exceed the limit. If the//! proposed size cannot be represented in `usize` or exceeds the limit,//! `preflight` rejects the request, updates rejection accounting, and returns//! `capacity_error`. A successful preflight verifies available space, but it//! neither reserves storage nor forms an atomic transaction with a subsequent//! read.//!//! Calling `status` returns a snapshot structure by value containing the//! current phase, the `in_use` flag, the configured limit, the declared storage//! size, the currently loaded bytes, the high-water mark of admitted bytes, the//! cumulative rejection count, and the terminal flag for terminal owners. The//! high-water mark records the largest admitted input, ignoring rejected//! attempts. Following `deinit`, the historical counters and declared capacity//! fields remain readable in the returned status snapshot, which means//! `storage_bytes` reports declared storage size rather than live retained heap//! memory.//!//! The Peek image decoding pipeline relies on a recoverable configuration. Its//! loader reads image files into the input buffer, holds the borrow while//! decoding pixel data into external image structures, and releases the owner//! immediately after decoding. If an oversized image is rejected, the owner//! remains active, enabling subsequent file reads to reuse the same memory//! allocation.//!//! ## Whole files versus windows//!//! Reading files introduces distinct concerns regarding whole-file ingestion//! versus positional slice inspection.//!//! Calling `readFile` reads an input file into the bounded buffer using the//! standard library directory interface. When reading an ordinary file whose//! size exceeds the limit, the reader fills the buffer prefix and the owner//! rejects the operation. The acquisition specification provides a//! configuration flag named `map_file_too_big`://!//! - When `map_file_too_big` is enabled, an underlying `FileTooBig` error//! returned by the filesystem maps directly into the owner's capacity//! rejection, incrementing the rejection counter and setting the terminal//! flag if configured.//! - When `map_file_too_big` is disabled, `FileTooBig` propagates outward as a//! filesystem error, bypassing rejection accounting and leaving the terminal//! flag unset.//! - Other filesystem errors, such as missing files or access faults, propagate//! unchanged under either setting without modifying capacity counters.//!//! When inputs exceed the capacity of our buffer, reading the entire file at//! once is impossible. Instead, we inspect bounded portions of the file using//! `readFileWindow`.//!//! Calling `readFileWindow` requires that file acquisition is enabled, that//! storage is available, and that the requested window length satisfies `0 <//! window_bytes <= limit`. The method reads up to `window_bytes + 1` bytes at a//! specified file offset, admits `min(read_count, window_bytes)`, and returns a//! `FileWindow` structure containing the borrowed slice and a boolean//! `complete` flag.//!//! If the file contains bytes beyond the requested window, the lookahead byte//! is populated, `complete` is set to false, and the admitted slice contains//! exactly `window_bytes`. An incomplete window read does not trigger a//! capacity rejection, even when the owner is configured as terminal. If the//! offset sits at end-of-file, a zero-byte read completes successfully and//! still establishes an active borrow. The `complete` flag describes only the//! result of this specific positional read: it does not provide an//! instantaneous file-length snapshot or guarantee that the file will not grow//! concurrently.//!//! Glom demonstrates how windowed ingestion coordinates with record framing.//! Glom ingests structured transcript files using a terminal input owner with//! preflight enabled. Because individual transcript records vary in length and//! files can grow large, its parser reads a positional window from the file. If//! `complete` is false, the window ended before the end of the file. Glom//! inspects the admitted bytes for the last newline character, processes//! complete lines up to that delimiter, releases the borrow, and advances its//! file offset to resume reading. If a maximum-sized window contains no newline//! delimiter at all, the consumer itself raises a record-framing error. Framing//! logic remains the responsibility of the consumer, while the input region//! guarantees only the bounded byte window.//!//! ## Declaration scope and interface shapes//!//! To integrate an input owner with verification and capacity tooling, we//! encapsulate its configuration within a `Spec` structure. A specification//! packages input limit and capacity types, error sets, status layout, enabled//! acquisition capabilities, overload policy, and a formal capacity//! `Declaration`.//!//! The status structure must declare exactly seven fields for recoverable//! owners or eight fields for terminal owners. While the generic checker//! validates the field count and types, it does not verify that custom field//! mappings are distinct from one another. We must supply distinct field names//! to prevent diagnostic collisions.//!//! The capacity `Declaration` establishes the structural contract of the owner//! for this example://!//! - Validation of `phase_static` requires valid seal and teardown bindings.//! The tag describes a claim and does not govern actual allocation behavior//! or enforce an operational lifetime. The limit source is marked as//! `.caller`, indicating that limits are supplied at initialization.//! - The storage section specifies covered memory, naming the single//! steady-state input buffer and describing its purpose. Excluded clauses//! document runtime resources that sit outside the claim, such as stream//! reader handles and destination parsing structures.//! - The capacity model defines an expression graph capturing the `n + 1`//! derivation. An input node binds the limit field, an integer constant node//! provides the literal 1, and an addition node sums them. An assertion//! declares that total retained storage matches this expression.//! - The overload policy is declared as `.drop`, documenting that oversized//! input is rejected while storage remains available for a later attempt. The//! `.drop` policy does not preserve previously released payload bytes://! subsequent reads can overwrite released bytes in the backing buffer.//! - Transitive and foreign operational risks are marked as `.open`,//! acknowledging that reader streams or filesystem calls can incur effects//! outside the region boundaries.//! - The declaration lists obligations for the capacity model and the overload//! policy.//!//! When `OneRegion(Spec)` generates an owner, it constructs fresh bindings//! linking the owner type, the specification, and selectors for `activate` and//! `deinit`. It does not reuse any bindings declared on `Spec.claim`. Claim//! declarations and premise labels such as `.checked_semantic_fact` provide//! structural metadata for verification tools: they do not establish proven//! semantic facts or whole-program safety guarantees.//!//! We validate this generated structure at compile time using//! `alloc_phase.capacity.requireAllocatorRejectingOwnerShape(Storage)`. This//! function performs structural reflection, checking that the owner provides//! required lifecycle functions, exposes an exhaustion error set on receiver//! methods, and presents a compatible claim.//!//! The following test illustrates a specification and recoverable input owner://!//! ```zig//! const std = @import("std");//! const alloc_phase = @import("alloc_phase");//!//! pub const InputLimits = struct {//! max_bytes: usize,//! };//!//! pub const InputCapacity = struct {//! max_bytes: usize,//! storage_bytes: usize,//!//! pub fn derive(limits: InputLimits) alloc_phase.input.DeriveError!InputCapacity {//! return alloc_phase.input.deriveCapacity(InputLimits, InputCapacity, "max_bytes", limits);//! }//! };//!//! pub const InputExhaustion = error{//! InputStorageBusy,//! InputCapacityExceeded,//! };//!//! pub const InputStatus = struct {//! phase: alloc_phase.capacity.Phase,//! in_use: bool,//! max_bytes: usize,//! storage_bytes: usize,//! loaded_bytes: usize,//! high_water_bytes: usize,//! rejected_count: u64,//! };//!//! pub const Spec = struct {//! pub const Limits = InputLimits;//! pub const Capacity = InputCapacity;//! pub const Exhaustion = InputExhaustion;//! pub const Status = InputStatus;//! pub const DeriveError = alloc_phase.input.DeriveError;//! pub const acquisition: alloc_phase.input.Acquisition = .{//! .reader = true,//! .preflight = true,//! };//! pub const overload: alloc_phase.input.Overload = .recoverable;//! pub const limit_field = "max_bytes";//! pub const loaded_field = "loaded_bytes";//! pub const high_water_field = "high_water_bytes";//! pub const rejected_field = "rejected_count";//! pub const in_use_error: Exhaustion = error.InputStorageBusy;//! pub const capacity_error: Exhaustion = error.InputCapacityExceeded;//!//! pub const claim: alloc_phase.capacity.Declaration = .{//! .source = .{//! .id = "guide.recoverable_reader",//! .kind = .phase_static,//! .limit_source = .caller,//! .storage = .{//! .covered = &.{//! .{//! .id = "reusable_input_buffer",//! .lifetime = .steady,//! .detail = "one reusable input and lookahead byte region",//! },//! },//! .excluded = &.{//! "stream reader buffering and allocator handles",//! "caller payload storage outside the borrowed window",//! },//! },//! .capacity = .{//! .inputs = &.{//! alloc_phase.capacity.bindInput(InputLimits, "max_bytes", "max_bytes"),//! },//! .type_selectors = &.{},//! .nodes = &.{//! .{ .input = 0 },//! .{ .constant = 1 },//! .{ .add = .{ .left = 0, .right = 1 } },//! },//! .assertions = &.{//! .{//! .scope = .closure_total,//! .measure = .retained,//! .relation = .exact,//! .expression = 2,//! },//! },//! },//! .overload = .{//! .kind = .drop,//! .detail = "oversized input is rejected while storage remains available for a later attempt",//! },//! .risks = .{//! .transitive = .{//! .status = .open,//! .detail = "stream operations may perform external allocations",//! },//! .foreign = .{//! .status = .open,//! .detail = "kernel stream handles remain unmanaged",//! },//! },//! .obligations = &.{//! .{ .key = "input_capacity_model", .role = .capacity_model },//! .{ .key = "input_overload_policy", .role = .overload },//! },//! },//! .bindings = .{},//! };//! };//!//! pub const Storage = alloc_phase.input.OneRegion(Spec);//!//! comptime {//! alloc_phase.capacity.requireAllocatorRejectingOwnerShape(Storage);//! }//!//! test "recoverable input storage lifecycle, borrow discipline, and reuse" {//! const allocator = std.testing.allocator;//! var storage = try Storage.init(allocator, .{ .max_bytes = 5 });//! defer storage.deinit(allocator);//! defer if (storage.in_use) storage.release();//!//! storage.activate();//!//! var first_reader: std.Io.Reader = .fixed("hello");//! const borrowed = try storage.read(&first_reader);//!//! try std.testing.expectEqual(@as(usize, 5), borrowed.len);//! try std.testing.expectEqualStrings("hello", borrowed);//! try std.testing.expectError(error.InputStorageBusy, storage.preflight(0));//!//! var preserved: [5]u8 = undefined;//! @memcpy(&preserved, borrowed);//!//! storage.release();//!//! try std.testing.expectEqualStrings("hello", &preserved);//!//! const status_after_release = storage.status();//! try std.testing.expect(!status_after_release.in_use);//! try std.testing.expectEqual(@as(usize, 0), status_after_release.loaded_bytes);//! try std.testing.expectEqual(@as(usize, 5), status_after_release.high_water_bytes);//! try std.testing.expectEqual(@as(u64, 0), status_after_release.rejected_count);//!//! try std.testing.expectError(error.InputCapacityExceeded, storage.preflight(6));//!//! const status_after_reject = storage.status();//! try std.testing.expectEqual(@as(u64, 1), status_after_reject.rejected_count);//!//! var second_reader: std.Io.Reader = .fixed("zig");//! const second_borrow = try storage.read(&second_reader);//!//! try std.testing.expectEqualStrings("zig", second_borrow);//!//! const status_final = storage.status();//! try std.testing.expect(status_final.in_use);//! try std.testing.expectEqual(@as(usize, 3), status_final.loaded_bytes);//! try std.testing.expectEqual(@as(usize, 5), status_final.high_water_bytes);//!//! try std.testing.expectEqualStrings("hello", &preserved);//!//! storage.release();//! }//! ```//!//! The source unit tests for `alloc_phase.input` assert capacity derivation//! from 31 to 32 bytes, overflow detection at integer limits, initialization//! failure under allocation faults, exact acceptance of fitting payloads, busy//! errors during active borrows, saturating rejection counters on terminal//! owners, and recoverable reuse following an oversized preflight check.//! Additional property tests assert `n + 1` allocation sizing for limits up to//! 4096 bytes, and consumer test suites exercise windowed reads alongside file//! boundary handling.const one = @import("one.zig");/// Packed boolean structure that enables specific input capabilities on an/// owner at compile time. All four fields default to `false`:////// * `reader`: Enables stream acquisition through `read`.////// * `file`: Enables filesystem acquisition through `readFile` and/// `readFileWindow`./// * `preflight`: Enables size admission checks through `preflight`./// * `map_file_too_big`: Maps `error.FileTooBig` from an underlying `readFile`/// call into a capacity rejection instead of propagating the raw I/O error.////// Because an owner must support at least one input mechanism, specification/// validation requires either `reader` or `file` to be enabled. Mapping/// file-size errors requires filesystem support, so `map_file_too_big` can be/// enabled only when `file` is also set to `true`. Individual acquisition/// methods verify their corresponding flags at compile time and raise a compile/// error when invoked without the required capability enabled.pub const Acquisition = one.Acquisition;/// Error set returned when capacity derivation fails.////// Members:////// * `CapacityOverflow`: Adding one lookahead byte to the configured byte limit/// overflowed the range of `usize`.pub const DeriveError = one.DeriveError;/// Constructs an allocator-backed owner type for a single reusable input buffer/// based on a static specification structure.////// The `Spec` type parameter must satisfy several structural requirements:////// * `Limits`: Structure defining input limits. It must contain the field/// designated by `limit_field` typed as `usize`./// * `Capacity`: Structure defining storage requirements. It must expose a/// `derive(limits: Limits) DeriveError!Capacity` function, the field named by/// `limit_field` typed as `usize`, and `storage_bytes` typed as `usize`./// * `DeriveError`: Error set returned by `Capacity.derive`./// * `Exhaustion`: Error set returned when storage cannot admit an input./// * `Status`: Reporting structure returned by `status`. It must be a struct/// containing exactly seven fields for recoverable owners or eight fields for/// terminal owners: `phase: alloc_phase.capacity.Phase`, `in_use: bool`,/// `storage_bytes: usize`, the mapped limit, loaded, and high-water fields/// typed as `usize`, the mapped rejection field typed as `u64`, and/// conditionally `terminal: bool` when `overload` is `terminal`./// * `acquisition`: An instance of `Acquisition` specifying enabled I/O/// capabilities./// * `overload`: An instance of `Overload` setting either `.terminal` or/// `.recoverable` behavior./// * Field mappings: `limit_field`, `loaded_field`, `high_water_field`, and/// `rejected_field` specify field names on `Capacity` or `Status`. Callers must/// supply distinct names for these fields. Compile-time validation verifies/// field presence and total field counts, but this validation does not prove/// that mapped field names are mutually distinct./// * Error instances: `in_use_error` and `capacity_error` must both have type/// `Spec.Exhaustion`./// * `claim`: A static `alloc_phase.capacity.Declaration` metadata descriptor.////// The owner asserts that `storage_bytes` strictly exceeds the configured byte/// limit. While standard `deriveCapacity` derivation provides an exact `limit +/// 1` layout, custom `Capacity.derive` implementations may describe larger/// storage: derivation computes a `Capacity` value, while `init` allocates.////// A successful read operation returns a borrowed `[]const u8` slice pointing/// directly into the owned buffer and marks the owner as in use, including when/// the input is empty. Borrowers must consume or copy these bytes elsewhere/// before calling `release`. Slices must not be accessed after releasing the/// owner.////// A struct copy shares allocated storage but duplicates internal bookkeeping./// Copies are not independent owners: transferring exclusive ownership requires/// callers to stop using the original. Callers must serialize operations and/// ensure cleanup occurs exactly once.////// The owner is not thread-safe and performs no internal synchronization./// Callers accessing an owner across threads must provide external mutual/// exclusion.////// Lifecycle checks across initialization, steady operation, and teardown are/// enforced through debug assertions rather than explicit always-executed phase/// panics.pub const OneRegion = one.OneRegion;/// Defines the policy applied when an input exceeds the configured capacity/// limit.////// Tags:////// * `terminal`: Permanently seals the owner upon capacity rejection. Any/// subsequent acquisition attempt returns the capacity error immediately/// without performing I/O or incrementing rejection counters./// * `recoverable`: Preserves owner availability across rejections. Oversized/// inputs increment the rejection counter but leave the underlying storage free/// for subsequent attempts.////// Recovery designates the ability to reuse the allocated storage for later/// inputs. It does not provide source-position rollback, record framing, or/// automatic input drainage.pub const Overload = one.Overload;/// Derives an instance of `Capacity` from a given `Limits` structure by adding/// one lookahead byte to the configured input limit.////// The input limit is retrieved from the field named by `limit_field` on/// `limits`. Both the limit field on `Limits` and `Capacity` and the/// `storage_bytes` field on `Capacity` must be typed as `usize`. When addition/// overflows `usize`, the function returns `error.CapacityOverflow`. A limit of/// zero derives a storage size of one byte.////// The returned `Capacity` structure initializes only the field named by/// `limit_field` and `storage_bytes`. Any additional fields present on/// `Capacity` remain undefined. Callers must keep `limit_field` distinct from/// `storage_bytes` so that writing `storage_bytes` does not overwrite the limit/// field.pub const deriveCapacity = one.deriveCapacity;Source: lib/alloc/phase/src/root.zig:115
zig
/// Bounded reusable input buffer storage (`OneRegion`). Configures a reusable/// byte buffer, enforces exclusive borrow and release discipline, and provides/// recoverable or terminal overload options. See/// [input/root.zig](input/root.zig).pub const input = @import("input/root.zig");Audit
| Definitions | 6 |
|---|---|
| Public names | 6 |
| Members | 7 |
| Version | 26.7.0 |
| Revision | daab053ee433 |