Независимая реализация RFC 8259. Покрывает все типы значений JSON, включая полную обработку escape-последовательностей (суррогатные пары, \uXXXX). По замыслу не поддерживает комментарии, висячие запятые и строки в одинарных кавычках. Свойство round-trip: Json.parse(v.into()) == v для любого корректного JsonValue.
ro v = Json.parse("{\"name\": \"alice\", \"age\": 30}")
match v.as_object() {
Some(m) => {
assert(m.get("name") == Some(Str("alice")))
assert(m.get("age") == Some(Num(30.0)))
}
None => assert(false)
}
Типы
JsonValue
стабильно с 0.1export type JsonValue
| Null
| Bool(bool)
| Num(f64)
| Str(str)
| Array([]JsonValue)
| Object(HashMap[str, JsonValue])
Рекурсивный тип-сумма для произвольных документов JSON. Поддерживается структурное равенство — v1 == v2 работает для глубокого сравнения, включая вложенные массивы и объекты.
ParseJsonError
стабильно с 0.1export type ParseJsonError
| UnexpectedChar { line int; col int; found char }
| UnexpectedEof { line int; col int }
| InvalidEscape { line int; col int; seq str }
| InvalidUnicode { line int; col int; hex str }
| InvalidNumber { line int; col int; text str }
| DuplicateKey { line int; col int; key str }
| TrailingContent { line int; col int }
Все варианты несут 1-based line и col для диагностических сообщений.
Разбор
Json.parse
стабильно с 0.1fn Json.parse(s str) Fail[ParseJsonError] -> JsonValue
Разбирает строку JSON. Бросает Fail[ParseJsonError] при любой лексической или синтаксической ошибке. Используйте блок with Fail[ParseJsonError] для обработки ошибок.
Примеры
ro arr = Json.parse("[1, 2, 3]")
assert(arr.is_array())
ro obj = Json.parse("{\"x\": true}")
match obj.as_object() {
Some(m) => assert(m.get("x") == Some(Bool(true)))
None => assert(false)
}
Конструкторы
Удобные статические конструкторы для программного построения JsonValue:
fn JsonValue.null() -> Self // Null
fn JsonValue.bool(b bool) -> Self // Bool(b)
fn JsonValue.num(n f64) -> Self // Num(n)
fn JsonValue.str(s str) -> Self // Str(s)
fn JsonValue.array(items []JsonValue) -> Self // Array(items)
fn JsonValue.object(fields HashMap[str, JsonValue]) -> Self // Object(fields)
Аксессоры
fn JsonValue @as_bool() -> Option[bool]
fn JsonValue @as_num() -> Option[f64]
fn JsonValue @as_str() -> Option[str]
fn JsonValue @as_array() -> Option[[]JsonValue]
fn JsonValue @as_object() -> Option[HashMap[str, JsonValue]]
Каждый метод возвращает None, если вариант не совпадает. Комбинируйте с match или if Some:
ro v = Json.parse("42")
assert(v.as_num() == Some(42.0))
assert(v.as_str() == None)
Проверки типа
fn JsonValue @is_null() -> bool
fn JsonValue @is_bool() -> bool
fn JsonValue @is_num() -> bool
fn JsonValue @is_str() -> bool
fn JsonValue @is_array() -> bool
fn JsonValue @is_object() -> bool
Сериализация
into — компактно
стабильно с 0.1fn JsonValue @into() -> str
Сериализует в компактный JSON (одна строка, без лишних пробелов). Это реализация D73 Into[str]. Round-trip: Json.parse(v.into()) == v.
Примеры
ro v = Array([Num(1.0), Str("a")])
ro s str = v.into()
assert(s == "[1,\"a\"]")
pretty
стабильно с 0.1fn pretty(v JsonValue) -> str
Печатает с отступом в 2 пробела. Не входит в Into[str] — вызывайте явно, когда нужен человекочитаемый вывод (логи, отладка). Для компактного канонического вывода используйте into().
Примеры
mut m = HashMap[str, JsonValue].new()
m.insert("name", Str("alice"))
ro s = pretty(Object(m))
assert(s.contains("\n")) // multi-line