Live data from Hacker News

Parsing JSON in 500 lines of Rust

krish.gg

1–10 of 59 posts

Re: Parsing JSON in 500 lines of Rust

#3

    match object(src) {
        Ok(res) => return Ok(res),
        Err(JSONParseError::NotFound) => {} // if not found, that ok
        Err(e) => return Err(e),
    }
You probably have realized that this is really tedious, and this is where macros would really shine:

    macro_rules! try_parse_as {
        ($f:expr) => (
            match $f(src) {
                Ok(res) => return Ok(res),
                Err(JSONParseError::NotFound) => {} // if not found, that ok
                Err(e) => return Err(e),
            }
        );
    }

    try_parse_as!(object);
    try_parse_as!(array);
    // ...
It is also possible to avoid macros by translating `Result` into `Result, JSONParseError>` (where `Ok(None)` indicates `Err(JSONParseError::NotFound)`), which allows for shorthands like `if let Ok(res) = translate(object())? { ... }`.

Also, even though you chose to represent numbers as f64, a correct parsing algorithm is surprisingly tricky. Fortunately `f64::parse` accepts a strict superset of JSON number grammar, so you can instead count the number of characters making the number up and feed it into the Rust standard library.

Re: Parsing JSON in 500 lines of Rust

#10
I once (maybe a long time ago?) made a parser for JSON by:

1. Reading the entire file into RAM.

2. Providing a `const char *get_value(const char *jstring, const char *path, ...)` function with a NULL-terminated parameter list that would return the position of the value of the key at the specified path.

3. Providing a `copy_value(const char *position)` function to copy the value at the specified position.

Slow? Yup!

But, it was easy and safe[1] and used absolutely minimal RAM![2]. The recursive nature of the JSON tree also allowed the caller to use a returned value from `get_value` as the `jstring` argument in further calls to `get_value`.

I might still have a fork of it lying around somewhere.

[1] "Safe" meaning "Caller had to check for NULL return values, and ensure that NULL terminated the parameter list".

[2] GCC with `-O2` and above does proper TCO, eliminating unbounded stack growth.

Post reply on HN