lib/alloc/phase/src/input/root.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 //! ## Package overview
2 //!
3 //! When we ingest external input from streams or files, we want to accept
4 //! bounded payloads using a single reusable byte allocation without allocating
5 //! on every message or resizing buffers on the fly. We configure an explicit
6 //! upper bound on accepted length, allocate storage once, and reuse that
7 //! storage across successive operations while detecting oversized inputs before
8 //! admitting them.
9 //!
10 //! ## One buffer and lookahead
11 //!
12 //! The core challenge in bounded ingestion sits at the boundary of the limit.
13 //! If we configure our system to accept at most `n` bytes and allocate an
14 //! `n`-byte buffer, filling that buffer completely leaves an ambiguity: did the
15 //! input stream end precisely at `n` bytes, or does more data remain waiting in
16 //! the channel? To resolve whether the input fits or exceeds our boundary, this
17 //! implementation reserves space for one extra byte. For an accepted limit of
18 //! `n` bytes, the backing buffer holds `n + 1` bytes. When we read from the
19 //! source into the buffer:
20 //!
21 //! - If the source yields between 0 and `n` bytes before reaching end-of-file,
22 //! the input fits within our configured boundary and we admit it.
23 //! - If the source yields `n + 1` bytes, the input exceeds our limit and we
24 //! reject it immediately, without allocating a second buffer.
25 //!
26 //! We term this calculation *capacity derivation*. The standard helper
27 //! `deriveCapacity` computes this boundary for an owner. Given a configuration
28 //! structure containing a byte limit field of type `usize`, it uses checked
29 //! integer addition to compute `n + 1`. If adding one to the limit overflows
30 //! `usize`, derivation fails with `error.CapacityOverflow`. When a caller
31 //! configures a limit of zero, derivation reserves one byte, which allows an
32 //! empty input to be distinguished from an input containing data.
33 //!
34 //! The `deriveCapacity` helper initializes only two fields in the resulting
35 //! capacity record: the configured limit and the derived `storage_bytes`. The
36 //! limit field name and `storage_bytes` must be distinct. Any additional fields
37 //! declared on the capacity type remain undefined, so a custom capacity type
38 //! that requires extra fields must populate them in a custom derivation
39 //! function.
40 //!
41 //! The generic container `OneRegion(Spec)` produces an allocator-backed owner
42 //! around this storage model. While `deriveCapacity` enforces the standard `n +
43 //! 1` sizing rule, a custom derivation function may describe larger storage
44 //! when required by domain constraints: derivation computes a `Capacity` value,
45 //! while `init` allocates the storage. The owner asserts that `storage_bytes`
46 //! strictly exceeds the configured input limit.
47 //!
48 //! ## A successful borrow and release
49 //!
50 //! Because a single byte buffer is reused across requests, concurrent access
51 //! would corrupt in-flight payloads. An outstanding borrow represents temporary
52 //! exclusive access granted to an admitted input. Until that borrow is
53 //! relinquished, the owner enforces busy protection across subsequent
54 //! acquisition and preflight calls.
55 //!
56 //! The lifecycle of an input owner progresses through three sequential phases:
57 //! initialization, steady operation, and teardown. Calling `init` enters the
58 //! initialization phase, calling `activate` advances to steady operation, and
59 //! calling `deinit` enters teardown. Calling `deinit` requires that no borrow
60 //! remains outstanding. If startup fails prior to activation, `deinit` can be
61 //! called directly from the initialization phase to free the buffer.
62 //!
63 //! During initialization, `init` derives the capacity and requests a single
64 //! contiguous slice of `storage_bytes` from the provided allocator. If capacity
65 //! derivation overflows or the allocator fails, `init` returns an error union
66 //! of `DeriveError` and `std.mem.Allocator.Error`. Once allocated, the owner
67 //! retains the byte slice but does not retain an allocator handle. In steady
68 //! operation, the owner methods do not call the initialization allocator. The
69 //! absence of a retained allocator on the owner does not prevent arbitrary
70 //! readers or filesystem code from allocating dynamically or performing
71 //! external work.
72 //!
73 //! Phase transitions are guarded by debug assertions (`std.debug.assert`),
74 //! which verify that `activate` is called only from the initialization phase
75 //! and that `deinit` is called with no active borrow. These debug assertions
76 //! differ from the explicit wrong-phase panics enforced by the separate phase
77 //! allocator.
78 //!
79 //! In steady operation, calling `read` ingests data into the buffer and admits
80 //! the payload if the returned length does not exceed the configured limit. A
81 //! successful read returns a borrowed constant slice (`[]const u8`) and sets
82 //! the internal `in_use` flag. Even an empty zero-byte read establishes an
83 //! active borrow and marks the owner busy. While `in_use` remains true, any
84 //! attempt to read, window, or preflight another input returns `in_use_error`.
85 //! This failure indicates a busy owner and does not increment the capacity
86 //! rejection counter.
87 //!
88 //! When the caller finishes processing the borrowed slice, it invokes
89 //! `release`. Calling `release` sets `in_use` to false and resets the loaded
90 //! byte counter to zero. It does not zero or scrub the underlying memory, nor
91 //! does it reset historical rejection counts or high-water marks.
92 //!
93 //! Because reads overwrite the backing buffer, a caller that needs to retain
94 //! admitted bytes across subsequent operations must copy them into separate
95 //! storage before calling `release`. A fixed stack array provides a convenient
96 //! target for preserving small records without allocating heap memory.
97 //!
98 //! Copies of an owner struct share the underlying byte slice while duplicating
99 //! internal bookkeeping. Because copies are not independent owners, callers
100 //! must serialize operations and ensure that cleanup occurs exactly once.
101 //! Calling `deinit` requires that no borrow remains outstanding, transitions
102 //! the phase to teardown, and frees the slice using the same allocator passed
103 //! during initialization. The owner provides no secondary abort or partial
104 //! teardown routines.
105 //!
106 //! In the Issue tool, body storage adopts this borrow discipline. Its
107 //! `BodySource` container pairs a borrowed slice of the input region with an
108 //! optional pointer to the owner. When processing finishes or an empty body
109 //! triggers an early exit, the consumer releases the borrow before reporting
110 //! results. Command-line arguments provided directly in the process invocation
111 //! bypass the input region entirely, leaving the buffer available for file or
112 //! standard-input ingestion.
113 //!
114 //! ## Failure and recovery
115 //!
116 //! When an incoming payload exceeds the configured limit, the owner rejects the
117 //! admission. How the owner responds to this overload depends on whether it is
118 //! configured with a terminal or recoverable policy:
119 //!
120 //! - A terminal owner treats an oversized input as a permanent boundary fault.
121 //! Upon rejection, it increments a saturating 64-bit rejection counter, sets
122 //! an internal `terminal` flag, and refuses all subsequent read attempts with
123 //! `capacity_error` without incrementing the counter again.
124 //! - A recoverable owner increments the rejection counter but leaves `terminal`
125 //! false. Storage remains immediately available to accept another input
126 //! without an acknowledgement step.
127 //!
128 //! Recovery denotes the ability to reuse the owned memory buffer for a future
129 //! request: it does not imply stream rewinding, transaction rollback, or
130 //! automatic framing.
131 //!
132 //! When reading from a stream through `Reader.readSliceShort`, capacity
133 //! rejection under the standard derivation helper occurs after reading up to
134 //! `limit + 1` logical bytes into the buffer. The owner does not drain any
135 //! remaining bytes left in the underlying stream. If an external caller
136 //! attempts to read from that same stream again, the retry does not guarantee
137 //! alignment with the start of a logical record. User reader implementations
138 //! may also maintain internal buffers or perform dynamic allocations outside
139 //! the owner's knowledge. If a stream encounters an I/O failure such as
140 //! `ReadFailed`, the failure can consume source bytes and overwrite buffer
141 //! contents. In that situation, no borrow is admitted and the owner's capacity
142 //! rejection counter does not increment.
143 //!
144 //! To avoid reading unwanted bytes when an input size is known beforehand, an
145 //! application can call `preflight`. The `preflight` method accepts an expected
146 //! size as a 64-bit integer, checks that the owner is available, and verifies
147 //! that the size fits within `usize` and does not exceed the limit. If the
148 //! proposed size cannot be represented in `usize` or exceeds the limit,
149 //! `preflight` rejects the request, updates rejection accounting, and returns
150 //! `capacity_error`. A successful preflight verifies available space, but it
151 //! neither reserves storage nor forms an atomic transaction with a subsequent
152 //! read.
153 //!
154 //! Calling `status` returns a snapshot structure by value containing the
155 //! current phase, the `in_use` flag, the configured limit, the declared storage
156 //! size, the currently loaded bytes, the high-water mark of admitted bytes, the
157 //! cumulative rejection count, and the terminal flag for terminal owners. The
158 //! high-water mark records the largest admitted input, ignoring rejected
159 //! attempts. Following `deinit`, the historical counters and declared capacity
160 //! fields remain readable in the returned status snapshot, which means
161 //! `storage_bytes` reports declared storage size rather than live retained heap
162 //! memory.
163 //!
164 //! The Peek image decoding pipeline relies on a recoverable configuration. Its
165 //! loader reads image files into the input buffer, holds the borrow while
166 //! decoding pixel data into external image structures, and releases the owner
167 //! immediately after decoding. If an oversized image is rejected, the owner
168 //! remains active, enabling subsequent file reads to reuse the same memory
169 //! allocation.
170 //!
171 //! ## Whole files versus windows
172 //!
173 //! Reading files introduces distinct concerns regarding whole-file ingestion
174 //! versus positional slice inspection.
175 //!
176 //! Calling `readFile` reads an input file into the bounded buffer using the
177 //! standard library directory interface. When reading an ordinary file whose
178 //! size exceeds the limit, the reader fills the buffer prefix and the owner
179 //! rejects the operation. The acquisition specification provides a
180 //! configuration flag named `map_file_too_big`:
181 //!
182 //! - When `map_file_too_big` is enabled, an underlying `FileTooBig` error
183 //! returned by the filesystem maps directly into the owner's capacity
184 //! rejection, incrementing the rejection counter and setting the terminal
185 //! flag if configured.
186 //! - When `map_file_too_big` is disabled, `FileTooBig` propagates outward as a
187 //! filesystem error, bypassing rejection accounting and leaving the terminal
188 //! flag unset.
189 //! - Other filesystem errors, such as missing files or access faults, propagate
190 //! unchanged under either setting without modifying capacity counters.
191 //!
192 //! When inputs exceed the capacity of our buffer, reading the entire file at
193 //! once is impossible. Instead, we inspect bounded portions of the file using
194 //! `readFileWindow`.
195 //!
196 //! Calling `readFileWindow` requires that file acquisition is enabled, that
197 //! storage is available, and that the requested window length satisfies `0 <
198 //! window_bytes <= limit`. The method reads up to `window_bytes + 1` bytes at a
199 //! specified file offset, admits `min(read_count, window_bytes)`, and returns a
200 //! `FileWindow` structure containing the borrowed slice and a boolean
201 //! `complete` flag.
202 //!
203 //! If the file contains bytes beyond the requested window, the lookahead byte
204 //! is populated, `complete` is set to false, and the admitted slice contains
205 //! exactly `window_bytes`. An incomplete window read does not trigger a
206 //! capacity rejection, even when the owner is configured as terminal. If the
207 //! offset sits at end-of-file, a zero-byte read completes successfully and
208 //! still establishes an active borrow. The `complete` flag describes only the
209 //! result of this specific positional read: it does not provide an
210 //! instantaneous file-length snapshot or guarantee that the file will not grow
211 //! concurrently.
212 //!
213 //! Glom demonstrates how windowed ingestion coordinates with record framing.
214 //! Glom ingests structured transcript files using a terminal input owner with
215 //! preflight enabled. Because individual transcript records vary in length and
216 //! files can grow large, its parser reads a positional window from the file. If
217 //! `complete` is false, the window ended before the end of the file. Glom
218 //! inspects the admitted bytes for the last newline character, processes
219 //! complete lines up to that delimiter, releases the borrow, and advances its
220 //! file offset to resume reading. If a maximum-sized window contains no newline
221 //! delimiter at all, the consumer itself raises a record-framing error. Framing
222 //! logic remains the responsibility of the consumer, while the input region
223 //! guarantees only the bounded byte window.
224 //!
225 //! ## Declaration scope and interface shapes
226 //!
227 //! To integrate an input owner with verification and capacity tooling, we
228 //! encapsulate its configuration within a `Spec` structure. A specification
229 //! packages input limit and capacity types, error sets, status layout, enabled
230 //! acquisition capabilities, overload policy, and a formal capacity
231 //! `Declaration`.
232 //!
233 //! The status structure must declare exactly seven fields for recoverable
234 //! owners or eight fields for terminal owners. While the generic checker
235 //! validates the field count and types, it does not verify that custom field
236 //! mappings are distinct from one another. We must supply distinct field names
237 //! to prevent diagnostic collisions.
238 //!
239 //! The capacity `Declaration` establishes the structural contract of the owner
240 //! for this example:
241 //!
242 //! - Validation of `phase_static` requires valid seal and teardown bindings.
243 //! The tag describes a claim and does not govern actual allocation behavior
244 //! or enforce an operational lifetime. The limit source is marked as
245 //! `.caller`, indicating that limits are supplied at initialization.
246 //! - The storage section specifies covered memory, naming the single
247 //! steady-state input buffer and describing its purpose. Excluded clauses
248 //! document runtime resources that sit outside the claim, such as stream
249 //! reader handles and destination parsing structures.
250 //! - The capacity model defines an expression graph capturing the `n + 1`
251 //! derivation. An input node binds the limit field, an integer constant node
252 //! provides the literal 1, and an addition node sums them. An assertion
253 //! declares that total retained storage matches this expression.
254 //! - The overload policy is declared as `.drop`, documenting that oversized
255 //! input is rejected while storage remains available for a later attempt. The
256 //! `.drop` policy does not preserve previously released payload bytes:
257 //! subsequent reads can overwrite released bytes in the backing buffer.
258 //! - Transitive and foreign operational risks are marked as `.open`,
259 //! acknowledging that reader streams or filesystem calls can incur effects
260 //! outside the region boundaries.
261 //! - The declaration lists obligations for the capacity model and the overload
262 //! policy.
263 //!
264 //! When `OneRegion(Spec)` generates an owner, it constructs fresh bindings
265 //! linking the owner type, the specification, and selectors for `activate` and
266 //! `deinit`. It does not reuse any bindings declared on `Spec.claim`. Claim
267 //! declarations and premise labels such as `.checked_semantic_fact` provide
268 //! structural metadata for verification tools: they do not establish proven
269 //! semantic facts or whole-program safety guarantees.
270 //!
271 //! We validate this generated structure at compile time using
272 //! `alloc_phase.capacity.requireAllocatorRejectingOwnerShape(Storage)`. This
273 //! function performs structural reflection, checking that the owner provides
274 //! required lifecycle functions, exposes an exhaustion error set on receiver
275 //! methods, and presents a compatible claim.
276 //!
277 //! The following test illustrates a specification and recoverable input owner:
278 //!
279 //! ```zig
280 //! const std = @import("std");
281 //! const alloc_phase = @import("alloc_phase");
282 //!
283 //! pub const InputLimits = struct {
284 //! max_bytes: usize,
285 //! };
286 //!
287 //! pub const InputCapacity = struct {
288 //! max_bytes: usize,
289 //! storage_bytes: usize,
290 //!
291 //! pub fn derive(limits: InputLimits) alloc_phase.input.DeriveError!InputCapacity {
292 //! return alloc_phase.input.deriveCapacity(InputLimits, InputCapacity, "max_bytes", limits);
293 //! }
294 //! };
295 //!
296 //! pub const InputExhaustion = error{
297 //! InputStorageBusy,
298 //! InputCapacityExceeded,
299 //! };
300 //!
301 //! pub const InputStatus = struct {
302 //! phase: alloc_phase.capacity.Phase,
303 //! in_use: bool,
304 //! max_bytes: usize,
305 //! storage_bytes: usize,
306 //! loaded_bytes: usize,
307 //! high_water_bytes: usize,
308 //! rejected_count: u64,
309 //! };
310 //!
311 //! pub const Spec = struct {
312 //! pub const Limits = InputLimits;
313 //! pub const Capacity = InputCapacity;
314 //! pub const Exhaustion = InputExhaustion;
315 //! pub const Status = InputStatus;
316 //! pub const DeriveError = alloc_phase.input.DeriveError;
317 //! pub const acquisition: alloc_phase.input.Acquisition = .{
318 //! .reader = true,
319 //! .preflight = true,
320 //! };
321 //! pub const overload: alloc_phase.input.Overload = .recoverable;
322 //! pub const limit_field = "max_bytes";
323 //! pub const loaded_field = "loaded_bytes";
324 //! pub const high_water_field = "high_water_bytes";
325 //! pub const rejected_field = "rejected_count";
326 //! pub const in_use_error: Exhaustion = error.InputStorageBusy;
327 //! pub const capacity_error: Exhaustion = error.InputCapacityExceeded;
328 //!
329 //! pub const claim: alloc_phase.capacity.Declaration = .{
330 //! .source = .{
331 //! .id = "guide.recoverable_reader",
332 //! .kind = .phase_static,
333 //! .limit_source = .caller,
334 //! .storage = .{
335 //! .covered = &.{
336 //! .{
337 //! .id = "reusable_input_buffer",
338 //! .lifetime = .steady,
339 //! .detail = "one reusable input and lookahead byte region",
340 //! },
341 //! },
342 //! .excluded = &.{
343 //! "stream reader buffering and allocator handles",
344 //! "caller payload storage outside the borrowed window",
345 //! },
346 //! },
347 //! .capacity = .{
348 //! .inputs = &.{
349 //! alloc_phase.capacity.bindInput(InputLimits, "max_bytes", "max_bytes"),
350 //! },
351 //! .type_selectors = &.{},
352 //! .nodes = &.{
353 //! .{ .input = 0 },
354 //! .{ .constant = 1 },
355 //! .{ .add = .{ .left = 0, .right = 1 } },
356 //! },
357 //! .assertions = &.{
358 //! .{
359 //! .scope = .closure_total,
360 //! .measure = .retained,
361 //! .relation = .exact,
362 //! .expression = 2,
363 //! },
364 //! },
365 //! },
366 //! .overload = .{
367 //! .kind = .drop,
368 //! .detail = "oversized input is rejected while storage remains available for a later attempt",
369 //! },
370 //! .risks = .{
371 //! .transitive = .{
372 //! .status = .open,
373 //! .detail = "stream operations may perform external allocations",
374 //! },
375 //! .foreign = .{
376 //! .status = .open,
377 //! .detail = "kernel stream handles remain unmanaged",
378 //! },
379 //! },
380 //! .obligations = &.{
381 //! .{ .key = "input_capacity_model", .role = .capacity_model },
382 //! .{ .key = "input_overload_policy", .role = .overload },
383 //! },
384 //! },
385 //! .bindings = .{},
386 //! };
387 //! };
388 //!
389 //! pub const Storage = alloc_phase.input.OneRegion(Spec);
390 //!
391 //! comptime {
392 //! alloc_phase.capacity.requireAllocatorRejectingOwnerShape(Storage);
393 //! }
394 //!
395 //! test "recoverable input storage lifecycle, borrow discipline, and reuse" {
396 //! const allocator = std.testing.allocator;
397 //! var storage = try Storage.init(allocator, .{ .max_bytes = 5 });
398 //! defer storage.deinit(allocator);
399 //! defer if (storage.in_use) storage.release();
400 //!
401 //! storage.activate();
402 //!
403 //! var first_reader: std.Io.Reader = .fixed("hello");
404 //! const borrowed = try storage.read(&first_reader);
405 //!
406 //! try std.testing.expectEqual(@as(usize, 5), borrowed.len);
407 //! try std.testing.expectEqualStrings("hello", borrowed);
408 //! try std.testing.expectError(error.InputStorageBusy, storage.preflight(0));
409 //!
410 //! var preserved: [5]u8 = undefined;
411 //! @memcpy(&preserved, borrowed);
412 //!
413 //! storage.release();
414 //!
415 //! try std.testing.expectEqualStrings("hello", &preserved);
416 //!
417 //! const status_after_release = storage.status();
418 //! try std.testing.expect(!status_after_release.in_use);
419 //! try std.testing.expectEqual(@as(usize, 0), status_after_release.loaded_bytes);
420 //! try std.testing.expectEqual(@as(usize, 5), status_after_release.high_water_bytes);
421 //! try std.testing.expectEqual(@as(u64, 0), status_after_release.rejected_count);
422 //!
423 //! try std.testing.expectError(error.InputCapacityExceeded, storage.preflight(6));
424 //!
425 //! const status_after_reject = storage.status();
426 //! try std.testing.expectEqual(@as(u64, 1), status_after_reject.rejected_count);
427 //!
428 //! var second_reader: std.Io.Reader = .fixed("zig");
429 //! const second_borrow = try storage.read(&second_reader);
430 //!
431 //! try std.testing.expectEqualStrings("zig", second_borrow);
432 //!
433 //! const status_final = storage.status();
434 //! try std.testing.expect(status_final.in_use);
435 //! try std.testing.expectEqual(@as(usize, 3), status_final.loaded_bytes);
436 //! try std.testing.expectEqual(@as(usize, 5), status_final.high_water_bytes);
437 //!
438 //! try std.testing.expectEqualStrings("hello", &preserved);
439 //!
440 //! storage.release();
441 //! }
442 //! ```
443 //!
444 //! The source unit tests for `alloc_phase.input` assert capacity derivation
445 //! from 31 to 32 bytes, overflow detection at integer limits, initialization
446 //! failure under allocation faults, exact acceptance of fitting payloads, busy
447 //! errors during active borrows, saturating rejection counters on terminal
448 //! owners, and recoverable reuse following an oversized preflight check.
449 //! Additional property tests assert `n + 1` allocation sizing for limits up to
450 //! 4096 bytes, and consumer test suites exercise windowed reads alongside file
451 //! boundary handling.
452
453 const one = @import("one.zig");
454
455 /// Packed boolean structure that enables specific input capabilities on an
456 /// owner at compile time. All four fields default to `false`:
457 ///
458 /// * `reader`: Enables stream acquisition through `read`.
459 ///
460 /// * `file`: Enables filesystem acquisition through `readFile` and
461 /// `readFileWindow`.
462 /// * `preflight`: Enables size admission checks through `preflight`.
463 /// * `map_file_too_big`: Maps `error.FileTooBig` from an underlying `readFile`
464 /// call into a capacity rejection instead of propagating the raw I/O error.
465 ///
466 /// Because an owner must support at least one input mechanism, specification
467 /// validation requires either `reader` or `file` to be enabled. Mapping
468 /// file-size errors requires filesystem support, so `map_file_too_big` can be
469 /// enabled only when `file` is also set to `true`. Individual acquisition
470 /// methods verify their corresponding flags at compile time and raise a compile
471 /// error when invoked without the required capability enabled.
472 pub const Acquisition = one.Acquisition;
473 /// Error set returned when capacity derivation fails.
474 ///
475 /// Members:
476 ///
477 /// * `CapacityOverflow`: Adding one lookahead byte to the configured byte limit
478 /// overflowed the range of `usize`.
479 pub const DeriveError = one.DeriveError;
480 /// Constructs an allocator-backed owner type for a single reusable input buffer
481 /// based on a static specification structure.
482 ///
483 /// The `Spec` type parameter must satisfy several structural requirements:
484 ///
485 /// * `Limits`: Structure defining input limits. It must contain the field
486 /// designated by `limit_field` typed as `usize`.
487 /// * `Capacity`: Structure defining storage requirements. It must expose a
488 /// `derive(limits: Limits) DeriveError!Capacity` function, the field named by
489 /// `limit_field` typed as `usize`, and `storage_bytes` typed as `usize`.
490 /// * `DeriveError`: Error set returned by `Capacity.derive`.
491 /// * `Exhaustion`: Error set returned when storage cannot admit an input.
492 /// * `Status`: Reporting structure returned by `status`. It must be a struct
493 /// containing exactly seven fields for recoverable owners or eight fields for
494 /// terminal owners: `phase: alloc_phase.capacity.Phase`, `in_use: bool`,
495 /// `storage_bytes: usize`, the mapped limit, loaded, and high-water fields
496 /// typed as `usize`, the mapped rejection field typed as `u64`, and
497 /// conditionally `terminal: bool` when `overload` is `terminal`.
498 /// * `acquisition`: An instance of `Acquisition` specifying enabled I/O
499 /// capabilities.
500 /// * `overload`: An instance of `Overload` setting either `.terminal` or
501 /// `.recoverable` behavior.
502 /// * Field mappings: `limit_field`, `loaded_field`, `high_water_field`, and
503 /// `rejected_field` specify field names on `Capacity` or `Status`. Callers must
504 /// supply distinct names for these fields. Compile-time validation verifies
505 /// field presence and total field counts, but this validation does not prove
506 /// that mapped field names are mutually distinct.
507 /// * Error instances: `in_use_error` and `capacity_error` must both have type
508 /// `Spec.Exhaustion`.
509 /// * `claim`: A static `alloc_phase.capacity.Declaration` metadata descriptor.
510 ///
511 /// The owner asserts that `storage_bytes` strictly exceeds the configured byte
512 /// limit. While standard `deriveCapacity` derivation provides an exact `limit +
513 /// 1` layout, custom `Capacity.derive` implementations may describe larger
514 /// storage: derivation computes a `Capacity` value, while `init` allocates.
515 ///
516 /// A successful read operation returns a borrowed `[]const u8` slice pointing
517 /// directly into the owned buffer and marks the owner as in use, including when
518 /// the input is empty. Borrowers must consume or copy these bytes elsewhere
519 /// before calling `release`. Slices must not be accessed after releasing the
520 /// owner.
521 ///
522 /// A struct copy shares allocated storage but duplicates internal bookkeeping.
523 /// Copies are not independent owners: transferring exclusive ownership requires
524 /// callers to stop using the original. Callers must serialize operations and
525 /// ensure cleanup occurs exactly once.
526 ///
527 /// The owner is not thread-safe and performs no internal synchronization.
528 /// Callers accessing an owner across threads must provide external mutual
529 /// exclusion.
530 ///
531 /// Lifecycle checks across initialization, steady operation, and teardown are
532 /// enforced through debug assertions rather than explicit always-executed phase
533 /// panics.
534 pub const OneRegion = one.OneRegion;
535 /// Defines the policy applied when an input exceeds the configured capacity
536 /// limit.
537 ///
538 /// Tags:
539 ///
540 /// * `terminal`: Permanently seals the owner upon capacity rejection. Any
541 /// subsequent acquisition attempt returns the capacity error immediately
542 /// without performing I/O or incrementing rejection counters.
543 /// * `recoverable`: Preserves owner availability across rejections. Oversized
544 /// inputs increment the rejection counter but leave the underlying storage free
545 /// for subsequent attempts.
546 ///
547 /// Recovery designates the ability to reuse the allocated storage for later
548 /// inputs. It does not provide source-position rollback, record framing, or
549 /// automatic input drainage.
550 pub const Overload = one.Overload;
551 /// Derives an instance of `Capacity` from a given `Limits` structure by adding
552 /// one lookahead byte to the configured input limit.
553 ///
554 /// The input limit is retrieved from the field named by `limit_field` on
555 /// `limits`. Both the limit field on `Limits` and `Capacity` and the
556 /// `storage_bytes` field on `Capacity` must be typed as `usize`. When addition
557 /// overflows `usize`, the function returns `error.CapacityOverflow`. A limit of
558 /// zero derives a storage size of one byte.
559 ///
560 /// The returned `Capacity` structure initializes only the field named by
561 /// `limit_field` and `storage_bytes`. Any additional fields present on
562 /// `Capacity` remain undefined. Callers must keep `limit_field` distinct from
563 /// `storage_bytes` so that writing `storage_bytes` does not overwrite the limit
564 /// field.
565 pub const deriveCapacity = one.deriveCapacity;