Skip to main content

RangeFrame

Struct RangeFrame 

Source
#[non_exhaustive]
pub struct RangeFrame {
Show 13 fields pub offset: u64, pub length: u64, pub bytes: String, pub complete: bool, pub total_length: Option<u64>, pub chunk_lens: Option<Vec<u64>>, pub chunk_index: Option<u64>, pub inclusion_proof: Option<String>, pub root: Option<HexId>, pub range_proof: Option<Vec<String>>, pub first_chunk_index: Option<u64>, pub chunk_count: Option<u64>, pub chunk_lens_offset: Option<u64>,
}
Expand description

One range frame of a resource: a byte window, plus the per-resource verification metadata that makes the window independently checkable.

The metadata splits in two by whether it scales with the resource, and the split decides which frames carry it:

  • The identity set — root, total_length, chunk_count, plus chunk_index when the window begins on a chunk boundary — rides EVERY frame. It is fixed-size, so carrying it everywhere costs a bounded number of bytes, and it is what lets a client fetching in parallel from many holders reject a wrong-generation or wrong-layout source the moment a frame arrives, rather than after paying for the whole resource in bandwidth.
  • The resource-scaling set — chunk_lens and inclusion_proof — rides the first frame, or a paged prologue, once per range stream. Repeating it per frame would cost proportionally to the resource against a frame budget with no slack; a layout too large to state on one frame is paged instead, each page stamped with the chunk_lens_offset it begins at.

The window is exactly the span the caller requested — never widened.

§Construction

This type is #[non_exhaustive]: build it with data and the with_* setters rather than a struct literal. That is deliberate — the wire form grows as the protocol does, and routing construction through named setters means a future additive field is a PATCH release for every consumer instead of another semver cascade. It also makes the two frame shapes different call chains rather than one call with a pile of Nones, so a continuation frame cannot accidentally claim a layout it is not stating.

§Cross-repo contract

The wire form is byte-identical to dig_nat::mux::RangeFrame, the streaming implementation of this frame (SYSTEM.md → “Canonical DIG-node RPC interface”). Field names, encodings, and the population rule above are pinned against dig-nat’s actual output in tests/nat_wire_mirror.rs; a change to any of them lands in both crates in the same unit of work or not at all.

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§offset: u64

The window start offset (echoed).

§length: u64

This window’s byte length.

§bytes: String

This window’s ciphertext, base64.

§complete: bool

Whether this frame ends the resource.

§total_length: Option<u64>

The full resource ciphertext length. Part of the fixed-size identity set, so it rides EVERY frame.

§chunk_lens: Option<Vec<u64>>

Per-chunk ciphertext lengths of the full resource, in order — the layout a reader needs before it can decrypt (per-chunk AEAD needs the WHOLE array, and a reader rejects an array whose sum differs from total_length).

Resource-scaling, so it rides the first frame or a paged prologue, once per range stream — never repeated on continuation frames. When paged, this is one page of the array and chunk_lens_offset states the entry it begins at.

§chunk_index: Option<u64>

This frame’s first chunk index — the pre-existing alias of first_chunk_index, carrying the same value, and the name dig-nat emits.

Part of the identity set: it rides every frame whose window begins on a chunk boundary, and is OMITTED (rather than guessed) on a mid-chunk window. Being fixed-size, it is settable on its own — see with_chunk_index — precisely so a continuation frame can state it without dragging along the once-per-stream inclusion_proof.

§inclusion_proof: Option<String>

Whole-resource merkle proof against root, base64, relayed verbatim.

Resource-scaling, so it rides the first frame or the paged prologue, once per range stream. A holder MUST NOT repeat it per frame: it is bounded at 4,096 base64 bytes, which against the frame budget leaves no slack for the payload the frame exists to carry.

§root: Option<HexId>

The chain-anchored root (64-hex) this frame’s resource verified against. Part of the fixed-size identity set, so it rides EVERY frame.

NOT A TRUST ANCHOR BY ITSELF. The client resolves the resource’s root from the URN (chain-anchored) and PINS it before fetching; a peer-declared value never replaces that pinned root. What this field provides is a generation-CONSISTENCY check: a frame declaring a root other than the pinned one is REJECTED and attributed to the offending peer (NC-9 fail-closed). So a declared root can only ever cause rejection — it can never move the pinned root, and never makes an unverified frame acceptable.

§range_proof: Option<Vec<String>>

RESERVED — not currently derivable; a server MUST NOT emit it.

Per-chunk merkle inclusion proofs for the chunks a frame covers. No such proof exists in the current store format: the generation root’s merkle leaves are per-RESOURCE (a leaf is the SHA-256 of a resource’s WHOLE ciphertext), so a single chunk has no leaf to prove. A client MUST NOT require this field, and per-range verification instead uses the whole-resource inclusion_proof together with the per-frame root/chunk_lens metadata.

Making it derivable requires a per-resource chunk-level commitment in the store format first (tracked as dig_ecosystem#1601). The field is kept in the wire type, unused, so populating it later is additive (§5.1); each entry would be an opaque base64 proof blob, since this pure level-00 wire type MUST NOT depend on the merkle primitive.

§first_chunk_index: Option<u64>

The chunk index of the first chunk in this frame (0-based, into the resource’s chunk sequence described by chunk_lens).

Present only when the frame’s window begins EXACTLY on a chunk boundary; a mid-chunk window omits it rather than assert an index the caller’s own alignment check would contradict. The served window is exactly the requested span — a server MUST NOT widen a range to a chunk boundary — so a frame is chunk-aligned only when the caller asked for an aligned span.

§chunk_count: Option<u64>

The resource’s TOTAL chunk count — how many entries the fully reassembled chunk_lens array has.

Fixed-size, so it belongs to the identity set and rides EVERY frame. Together with root and total_length it is what lets a reader detect a wrong-generation or wrong-layout holder on the first frame it receives. It is also how a reader sizes the array it is paging in, and therefore how it knows a paged prologue is complete: the prologue ends when the reader holds chunk_count entries, which no single page can tell it.

§chunk_lens_offset: Option<u64>

The index into the resource’s chunk_lens array at which THIS frame’s page begins — how a paged prologue is located and reassembled.

A resource whose layout exceeds the per-frame entry cap cannot state it on one frame, so the sender pages it: successive frames each carry up to that many entries, stamped with the offset they start at. A reader places each page at its offset and holds the whole array once it has chunk_count entries.

Absent means “this frame’s chunk_lens, if any, begins at entry 0” — the single-frame layout, which is the shape every pre-0.6.0 producer emits. So an older frame decodes with exactly its original meaning (§5.1).

Implementations§

Source§

impl RangeFrame

Source

pub fn data(offset: u64, length: u64, bytes: impl Into<String>) -> Self

A data frame: length bytes of base64 ciphertext at offset, carrying no metadata — the bare shape every continuation frame starts from.

length is stated rather than derived because bytes is already base64 on this type, and recovering the raw window length from it would need a base64 codec this pure level-00 wire crate deliberately does not depend on. A serve path passes the length it served.

Source

pub fn with_complete(self, complete: bool) -> Self

Mark this as the final frame of the range.

Source

pub fn with_identity( self, root: impl Into<HexId>, total_length: u64, chunk_count: u64, ) -> Self

The fixed-size identity set every frame of a range carries: the generation root (64-hex) the range is served from, the resource’s ciphertext total_length, and its chunk_count.

These three are what let a reader reject a wrong-generation or wrong-layout holder the moment a frame arrives — which the resource-scaling metadata never could, since it arrives once. Call this on every frame.

Source

pub fn with_chunk_index(self, chunk_index: u64) -> Self

State chunk_index — the chunk this frame’s window begins on — for a chunk-aligned window.

Separate from with_inclusion_proof on purpose: the index is fixed-size identity metadata that rides every aligned frame, while the proof is once-per-stream, so binding them together would force a producer to either repeat a proof it MUST NOT repeat or bypass this API. Omit the call entirely for a mid-chunk window.

Source

pub fn with_first_chunk_index(self, first_chunk_index: u64) -> Self

Additionally state first_chunk_index, this crate’s v0.4.0 alias of chunk_index.

Both names carry the same value. dig-nat emits only chunk_index, so with_chunk_index alone is the interoperable choice; a producer serving readers that expect the newer name states both.

Source

pub fn with_chunk_lens_page( self, chunk_lens_offset: u64, chunk_lens: Vec<u64>, ) -> Self

One page of the resource’s chunk_lens array, beginning at entry chunk_lens_offset.

Call it once with offset 0 for a layout that fits a single frame, or once per page of a paged prologue. A page is only ever useful as part of a complete set: chunk_lens is a decrypt input, and a reader needs all chunk_count entries before it can decrypt anything.

Source

pub fn with_inclusion_proof(self, inclusion_proof: impl Into<String>) -> Self

The whole-resource merkle inclusion proof against root (base64, relayed verbatim).

Resource-scaling: state it on the first frame or the prologue, once per range stream, never per frame.

Source

pub fn with_range_proof(self, range_proof: Vec<String>) -> Self

State the RESERVED range_proof field.

A server MUST NOT emit it — no per-chunk proof is derivable from the current store format (see the field’s own documentation). The setter exists so the shape stays constructible for the conformance vectors that pin it, and so no field of this #[non_exhaustive] type is unreachable; it is not a serve-path call.

Trait Implementations§

Source§

impl Clone for RangeFrame

Source§

fn clone(&self) -> RangeFrame

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for RangeFrame

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for RangeFrame

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl PartialEq for RangeFrame

Source§

fn eq(&self, other: &RangeFrame) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for RangeFrame

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for RangeFrame

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.