Parse an Object Map from JSON

The syntax for an object map is extremely similar to the JSON representation of a object hash, with the exception of null values which can technically be mapped to ().

A valid JSON string does not start with a hash character # while a Rhai object map does – that’s the major difference!

Use the Engine::parse_json method to parse a piece of JSON into an object map. The JSON text must represent a single object hash (i.e. must be wrapped within “{ .. }“) otherwise it returns a syntax error.


#![allow(unused)]
fn main() {
// JSON string - notice that JSON property names are always quoted
//               notice also that comments are acceptable within the JSON string
let json = r#"{
                "a": 1,                 // <- this is an integer number
                "b": true,
                "c": 123.0,             // <- this is a floating-point number
                "$d e f!": "hello",     // <- any text can be a property name
                "^^^!!!": [1,42,"999"], // <- value can be array or another hash
                "z": null               // <- JSON 'null' value
              }
"#;

// Parse the JSON expression as an object map
// Set the second boolean parameter to true in order to map 'null' to '()'
let map = engine.parse_json(json, true)?;

map.len() == 6;       // 'map' contains all properties in the JSON string

// Put the object map into a 'Scope'
let mut scope = Scope::new();
scope.push("map", map);

let result = engine.eval_with_scope::<INT>(r#"map["^^^!!!"].len()"#)?;

result == 3;          // the object map is successfully used in the script
}

Representation of Numbers

JSON numbers are all floating-point while Rhai supports integers (INT) and floating-point (FLOAT) if the no_float feature is not used.

Most common generators of JSON data distinguish between integer and floating-point values by always serializing a floating-point number with a decimal point (i.e. 123.0 instead of 123 which is assumed to be an integer).

This style can be used successfully with Rhai object maps.

Parse JSON with Sub-Objects

Engine::parse_json depends on the fact that the object map literal syntax in Rhai is almost the same as a JSON object. However, it is almost because the syntax for a sub-object in JSON (i.e. “{ ... }“) is different from a Rhai object map literal (i.e. “#{ ... }“).

When Engine::parse_json encounters JSON with sub-objects, it fails with a syntax error.

If it is certain that no text string in the JSON will ever contain the character ‘{‘, then it is possible to parse it by first replacing all occupance of ‘{‘ with “#{“.

A JSON object hash starting with #{ is handled transparently by Engine::parse_json.


#![allow(unused)]
fn main() {
// JSON with sub-object 'b'.
let json = r#"{"a":1, "b":{"x":true, "y":false}}"#;

// Our JSON text does not contain the '{' character, so off we go!
let new_json = json.replace("{", "#{");

// The leading '{' will also be replaced to '#{', but 'parse_json' handles this just fine.
let map = engine.parse_json(&new_json, false)?;

map.len() == 2;       // 'map' contains two properties: 'a' and 'b'
}

Use serde to Serialize/Deserialize to/from JSON

Remember, Engine::parse_json is nothing more than a cheap alternative to true JSON parsing.

If correctness is needed, or for more configuration possibilities, turn on the serde feature to pull in the serde crate which enables serialization and deserialization to/from multiple formats, including JSON.

Beware, though... the serde crate is quite heavy.

See Serialization/Deserialization of Dynamic with serde for more details.