use json/parser.{parse}
use json/render.{render}
use json/value.{error_text}
fn reformat(text: String) -> String =
match parse(text) {
Ok(j) -> render(j)
Err(e) -> error_text(e)
}
Contract#
- A number with no
.,eorEis aJInt, so ids, money in minor units and epoch milliseconds above 2^53 are not rounded; any other number is aJNum. An integer wider than 64 bits is aNumberRangeerror that carries the literal; itsmessagequotes only the first 64 characters of it. - Objects keep insertion order.
renderwrites compact output. parsenever panics. AJsonErrorhas akindto branch on (Syntax,Truncated,Trailing,Depth,NumberRange), a code-pointoffsetand amessage; nesting deeper thanMAX_DEPTH(512) is aDeptherror.json/lexeris public because the parser imports it; callers do not need it.
Changes between versions: CHANGELOG.md.
API#
json/lexer
lexer.peek
fn peek(src: String, i: Cursor) -> Int
The code point at i, or -1 at the end of the document.
An Int and not a Char: the end-of-input answer is a sentinel, and a
sentinel that is not a character cannot live in a type whose every value is
one (spec §4.8). So this scanner compares code points, and spells the
constants it compares against as char.code('x') -- the character is what
is readable, the Int is what is being compared.
lexer.offset
fn offset(src: String, i: Cursor) -> Int
The code-point offset of i in src, as JsonError.offset reports it.
O(n) in the offset: meant for the failure path, not for every token.
lexer.err_at
fn err_at(src: String, i: Cursor, msg: String) -> JsonError
A JsonError at i carrying msg, of kind Truncated when i is at
the end of src and Syntax otherwise. err_kind is the same with the
kind stated.
lexer.err_kind
fn err_kind(src: String, i: Cursor, kind: JsonErrorKind, msg: String) -> JsonError
An error of a stated kind at i.
lexer.is_digit
fn is_digit(c: Int) -> Bool
Whether the code point c is an ASCII digit 0-9; -1 (the end of
the document, as peek reports it) is not.
lexer.skip_ws
fn skip_ws(src: String, i: Cursor) -> Cursor
The first cursor at or after i that is not JSON whitespace (space, tab,
line feed, carriage return). At the end of the document it is the end.
lexer.scan_string
fn scan_string(src: String, start: Cursor) -> Result[(String, Cursor), JsonError]
The JSON string literal whose opening quote is at start, escapes
decoded, with the cursor just past its closing quote; an Err for an
unterminated literal, a raw control character, or a malformed escape.
lexer.scan_number
fn scan_number(src: String, start: Cursor) -> Result[(String, Cursor), JsonError]
The JSON number literal starting at start, as its source text, with
the cursor just past it; an Err when the text breaks the JSON number
grammar. The text and not a value, so the caller picks a lossless
conversion (Int or Float).
json/parser
parser.MAX_DEPTH
const MAX_DEPTH: Int
How deeply arrays and objects may nest before parse gives up. Deeper input
is a plain error, not a blown stack.
parser.parse
fn parse(input: String) -> Result[Json, JsonError]
Parse one complete JSON document (RFC 8259). Err is a value.JsonError:
the kind of failure, the code-point offset it was noticed at, and a sentence;
value.error_text renders the last two as the one-line message this used to
return in place of the whole thing. Anything but whitespace after the value is
an error. Never panics. An integer literal becomes JInt, any other number
JNum. Integers must fit Int; fraction/exponent literals use IEEE-754
binary64 ties-to-even rounding, accept finite underflow as signed zero, and
reject overflow when the result is non-finite.
json/render
render.render
fn render(j: Json) -> String
Serialize a Json value to compact JSON text — no spaces, object keys in the
Map's insertion order. Total, and the output is always legal JSON: every code
point below U+0020 is escaped and a non-finite JNum renders as null.
json/value
本模块登记的 impl(全程序可见,不必 use):Show[Json]、Show[JsonErrorKind]、Show[JsonError]
Json
type Json = JNull | JBool(value: Bool) | JNum(value: Float) | JInt(value: Int) | JStr(value: String) | JArr(items: List[Json]) | JObj(entries: Map[String, Json])
The JSON data model (RFC 8259): null, booleans, numbers, strings, arrays and
objects, which preserve insertion order via the builtin Map. A number is
JInt when its literal carries no '.', 'e' or 'E', and JNum otherwise.
JsonErrorKind
type JsonErrorKind = Syntax | Truncated | Trailing | Depth | NumberRange(literal: String)
Why a parse failed, in the terms a caller can act on: input that ran out,
a value followed by more input, nesting past MAX_DEPTH, a number outside
Dawn's model (carrying its literal), or a plain syntax error.
JsonError
type JsonError = { kind: JsonErrorKind, offset: Int, message: String }
What parse returns on failure: the kind, the code-point offset it was
noticed at, and the sentence a human reads. error_text renders the last two
in the shape the old String error had.
value.error_text
fn error_text(e: JsonError) -> String
A JsonError as the one-line message the String error used to be:
"unexpected character at offset 6". The migration from that error type is
this call.