Silk

silk/json_scanner

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc.

Strict, allocation-free JSON tokens from complete slices or successive byte chunks.

When to use

Use JsonScanner to inspect one complete JSON document without building a value tree. Use JsonScanState when bytes arrive in chunks and retain token fragments yourself.

Details

JsonScanState.step consumes at most one token per call. Spans and errors use absolute byte offsets; a step also reports the part of the current lexeme in its supplied chunk. Strings retain their source spelling and report whether they contain escapes. No operation allocates.

Gotchas

A number at a nonfinal chunk boundary needs another step to establish its delimiter. The delimiter remains unconsumed. After any error the state is terminal; create a new state. Nesting is limited to MAX_DEPTH. The scanner validates syntax, not duplicate key equality.

Examples

Scan a complete number

import silk.json_scanner {JsonScanner, JsonToken, JsonError}
import silk.result {Result}

pub fn main() -> i32 {
  let mut scanner = JsonScanner.make(b"42")
  let token = JsonScanner.next(&mut scanner)
  return match move token {
    Result<JsonToken, JsonError>.Failure {error} => 1
    Result<JsonToken, JsonError>.Success {value} => match move value {
      JsonToken.Number {span: _} => 0
      _ => 1
    }
  }
}

Import as JsonScanner with import silk.json_scanner { JsonScanner }.

Public declarations: 9.

MAX_DEPTH

pub const MAX_DEPTH: usize

The maximum number of simultaneously open JSON arrays and objects.

JsonSpan

pub struct JsonSpan

A half-open byte range in the complete JSON source.

Field offset

pub offset: usize

The absolute offset of the first byte.

Field length

pub length: usize

The number of bytes in the range.

Implementation Copy for JsonSpan

impl Copy for JsonSpan

JsonReason

pub enum JsonReason

A stable category for a JSON scanner failure.

UnexpectedByte

UnexpectedByte = 0

A byte cannot begin or continue the expected JSON construct.

UnterminatedString

UnterminatedString = 1

A quoted string ended without a closing quote.

InvalidEscape

InvalidEscape = 2

A backslash escape or surrogate pair is invalid.

InvalidUtf8

InvalidUtf8 = 3

A string contains malformed UTF-8.

InvalidNumber

InvalidNumber = 4

A number does not satisfy the JSON number grammar.

DuplicateKey

DuplicateKey = 5

An object repeats a decoded member name.

InvalidValue

InvalidValue = 6

A constructed value contains a child of the wrong container kind.

TypeMismatch

TypeMismatch = 7

A valid JSON value does not have the requested type.

NumberOutOfRange

NumberOutOfRange = 8

A JSON number cannot fit the requested numeric type.

MissingField

MissingField = 9

A required object member is absent.

UnknownField

UnknownField = 10

An object member is not part of the requested type.

UnexpectedEnd

UnexpectedEnd = 11

The final input ended before the single root value was complete.

DepthExceeded

DepthExceeded = 12

The fixed nesting stack is full.

TrailingContent

TrailingContent = 13

A second root value follows the first.

OffsetOverflow

OffsetOverflow = 14

An absolute byte offset cannot be represented as usize.

TokenTooLarge

TokenTooLarge = 15

A streaming consumer's caller-owned token buffer is too small.

JsonError

pub struct JsonError

A deterministic JSON failure with absolute input position and optional capacity details.

Field reason

pub reason: JsonReason

The stable failure category.

Field offset

pub offset: silk/option.Option<usize>

The offending byte or end position, when available.

Field required

pub required: silk/option.Option<usize>

Capacity required by a future consumer, if applicable.

Field available

pub available: silk/option.Option<usize>

Capacity available to a future consumer, if applicable.

Associated function JsonError.at

pub fn at(reason: JsonReason, offset: usize) -> JsonError

Creates an input failure at an absolute byte offset.

JsonToken

pub union JsonToken

One validated JSON token. String and number spans retain the raw source spelling.

ObjectBegin

JsonToken.ObjectBegin: JsonToken

An opening object brace.

ObjectEnd

JsonToken.ObjectEnd: JsonToken

A closing object brace.

ArrayBegin

JsonToken.ArrayBegin: JsonToken

An opening array bracket.

ArrayEnd

JsonToken.ArrayEnd: JsonToken

A closing array bracket.

KeySeparator

JsonToken.KeySeparator: JsonToken

A colon between an object key and value.

ValueSeparator

JsonToken.ValueSeparator: JsonToken

A comma between array elements or object members.

String

JsonToken.String { span: JsonSpan, escaped: bool }: JsonToken

A quoted, UTF-8-valid string, including its source quotes in span.

Field span

pub span: JsonSpan

The raw quoted source range.

Field escaped

pub escaped: bool

Whether a backslash escape occurred.

Number

JsonToken.Number { span: JsonSpan }: JsonToken

A valid number lexeme, without numeric conversion.

Field span

pub span: JsonSpan

The raw source range.

True

JsonToken.True: JsonToken

The literal true.

False

JsonToken.False: JsonToken

The literal false.

Null

JsonToken.Null: JsonToken

The literal null.

EndOfInput

JsonToken.EndOfInput: JsonToken

The complete root value and trailing whitespace have ended.

Implementation Copy for JsonToken

impl Copy for JsonToken

JsonScanEvent

pub union JsonScanEvent

The outcome of one resumable scan step.

Token

JsonScanEvent.Token { token: JsonToken }: JsonScanEvent

A complete token was emitted.

Field token

pub token: JsonToken

The token, whose source offsets are absolute.

NeedMore

JsonScanEvent.NeedMore: JsonScanEvent

All supplied bytes were consumed; another chunk is needed.

EndOfInput

JsonScanEvent.EndOfInput: JsonScanEvent

The complete document has ended.

JsonScanStep

pub struct JsonScanStep

One step's byte accounting and event.

Field consumed

pub consumed: usize

Number of bytes consumed from this call's chunk.

Field fragment

pub fragment: JsonSpan

Range of this lexeme's bytes within this call's chunk, possibly empty.

Field event

pub event: JsonScanEvent

The token, need-more request, or final end event.

JsonScanState

pub struct JsonScanState

Owned lexical and container state shared by slice and streaming scanners.

Details

It retains no chunk view. Feed each unconsumed suffix back into step until it reports NeedMore or EndOfInput; after NeedMore, supply the next chunk.

Associated function JsonScanState.make

pub fn make() -> JsonScanState

Creates an empty, allocation-free state for exactly one root JSON value.

Method JsonScanState.step

pub fn step<'life0, 'life1>(self: &'life0 mut silk/json_scanner.JsonScanState, chunk: &'life1 [u8], final: bool) -> silk/result.Result<silk/json_scanner.JsonScanStep, silk/json_scanner.JsonError>

Consumes a chunk up to one token, need-more boundary, or document end.

Details

Reuse the unconsumed suffix after Token. final remains true for every suffix of the final chunk, including an empty one. No input slice survives this call.

Gotchas

NeedMore consumes the entire chunk. A number at a nonfinal boundary remains pending; its lookahead delimiter is left for the following call. Errors make this state terminal.

JsonScanner

pub struct JsonScanner<'input>

A slice-backed convenience adapter over the resumable scanner.

Associated function JsonScanner.make

pub fn make<'input>(input: &'input [u8]) -> silk/json_scanner.JsonScanner<'input>

Borrows a complete input slice and starts a single-document scan.

Method JsonScanner.next

pub fn next<'input, 'life1>(self: &'life1 mut silk/json_scanner.JsonScanner<'input>) -> silk/result.Result<silk/json_scanner.JsonToken, silk/json_scanner.JsonError>

Returns the next token or sticky EndOfInput after trailing whitespace.

Method JsonScanner.peek

pub fn peek<'input, 'life1>(self: &'life1 mut silk/json_scanner.JsonScanner<'input>) -> silk/result.Result<silk/json_scanner.JsonToken, silk/json_scanner.JsonError>

Returns the next token without consuming it.

Method JsonScanner.offset

pub fn offset<'input, 'life1>(self: &'life1 silk/json_scanner.JsonScanner<'input>) -> usize

Returns the absolute byte offset of the last token returned by next or peek.

Method JsonScanner.length

pub fn length<'input, 'life1>(self: &'life1 silk/json_scanner.JsonScanner<'input>) -> usize

Returns the length of the complete input slice.

Method JsonScanner.slice

pub fn slice<'input, 'life1>(self: &'life1 silk/json_scanner.JsonScanner<'input>, span: JsonSpan) -> &'input [u8]

Borrows the raw bytes denoted by a token span from this scanner's complete input.

On this page