parse_that 0.1.0

Zero-copy parser combinator library for Rust
Documentation
use crate::parse::*;

use super::utils::{escaped_span, number_span};

use pprint::Pretty;

use crate::parse::ParserSpan;

use std::collections::HashMap;

#[derive(Pretty, Debug, Clone, PartialEq)]
pub enum JsonValue<'a> {
    #[pprint(rename = "null")]
    Null,
    Bool(bool),
    Number(f64),
    String(&'a str),
    Array(Vec<JsonValue<'a>>),
    Object(HashMap<&'a str, JsonValue<'a>>),
}

pub fn json_value<'a>() -> Parser<'a, JsonValue<'a>> {
    let string_char = || {
        let not_quote = take_while_span(|c| c != '"' && c != '\\');

        let string = (not_quote | escaped_span())
            .many_span(..)
            .wrap_span(string_span("\""), string_span("\""));

        string.map(|s| s.as_str())
    };

    let json_null = string_span("null").map(|_| JsonValue::Null);
    let json_bool = string_span("true").map(|_| JsonValue::Bool(true))
        | string_span("false").map(|_| JsonValue::Bool(false));

    let json_number = || {
        number_span()
            .map(|s| s.as_str().parse().unwrap_or(f64::NAN))
            .map(JsonValue::Number)
    };

    let json_string = || string_char().map(JsonValue::String);

    let json_array = lazy(|| {
        let comma = string_span(",").trim_whitespace();

        json_value()
            .sep_by(comma, ..)
            .or_else(std::vec::Vec::new)
            .trim_whitespace()
            .wrap(string_span("["), string_span("]"))
            .map(JsonValue::Array)
    });

    let json_object = lazy(move || {
        let colon = string_span(":").trim_whitespace();
        let comma = string_span(",").trim_whitespace();

        let key_value = string_char().skip(colon).then(json_value());

        key_value
            .sep_by(comma, ..)
            .or_else(std::vec::Vec::new)
            .trim_whitespace()
            .wrap(string_span("{"), string_span("}"))
            .map(|pairs| JsonValue::Object(pairs.into_iter().collect()))
    });

    json_object | json_array | json_string() | json_number() | json_bool | json_null
}

pub fn json_parser<'a>() -> Parser<'a, JsonValue<'a>> {
    json_value().trim_whitespace()
}