Skip to main content

Module text

Module text 

Source
Expand description

JSON text into a Builder and back out of a Value.

The typed API never comes through here: a struct is serialized straight into the encoding and read straight back out, and text would be two conversions nobody asked for. This is for the other door. JSON.SET arrives with a bulk string that is JSON text and JSON.GET has to hand one back, so the whole JSON.* surface stands on these two functions and neither of them can be a dependency, because a JSON parser is where a compatibility claim goes to die and this one has to agree with RedisJSON down to the byte.

use yo_doc::{Builder, Value};

let mut b = Builder::new();
b.json(br#"{"name": "a wrench", "price": 12.5, "tags": ["hand", "steel"]}"#)?;
let doc = b.finish()?.to_vec();

let v = Value::new(&doc).expect("readable");
assert_eq!(v.get(b"price").unwrap().as_float(), Some(12.5));
// Key order, not the order the text had them in. See below.
assert_eq!(v.to_json()?, br#"{"name":"a wrench","tags":["hand","steel"],"price":12.5}"#);

§What the parser accepts

RFC 8259 and nothing else. No trailing commas, no comments, no unquoted keys, no single quoted strings, no leading plus, no leading zero, no bare NaN or Infinity. Every one of those is something some parser somewhere allows, and accepting one of them means a document that loads here and is refused by a real Redis, which is a divergence that nobody would think to look for. Being strict is the only setting that can be checked.

A number without a fraction or an exponent that fits in an i64 is stored as an integer and everything else is stored as a float, which is the same split RedisJSON makes and the reason 1 comes back as 1 rather than as 1.0. An integer literal too big for an i64 becomes a float, and loses precision the way it would anywhere else. So does -0, which is a number an integer cannot hold and a double can.

§Two things the writer does that are worth knowing

An object comes out in key order, which is by length first and then by bytes, so name comes before price and not after it. Members are stored sorted because that is what makes a lookup a binary search, so the order a client wrote them in is not kept anywhere and cannot be handed back. RedisJSON keeps it. That shows up on any document with more than one key and it belongs in the divergence register rather than in a footnote.

A float is printed as the shortest text that reads back as the same double, with a .0 added when it would otherwise look like an integer. Without that, a document that went out and came back would change type on every round trip, which is the sort of thing that only shows up three services downstream.

Structs§

Format
How a document is laid out when it is written as text.

Functions§

from_json
One JSON document, as the bytes it encodes to.
write_resp_float
A double, the way JSON.RESP writes one, which is not the way JSON does.