blazingly-json 0.1.0

A focused, Tokio-free JSON engine for small protocol and API payloads
Documentation
use blazingly_json::value::{to_raw_value, RawValue};
use blazingly_json::Value;
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize)]
struct BorrowedEnvelope<'a> {
    #[serde(borrow)]
    payload: &'a RawValue,
}

#[derive(Serialize)]
struct BorrowedOutput<'a> {
    payload: &'a RawValue,
}

#[test]
fn borrowed_raw_value_is_zero_copy_and_preserves_formatting() {
    let input = r#"{"payload": { "nested": [1, 2, 3], "ok": true }}"#;
    let envelope: BorrowedEnvelope<'_> = blazingly_json::from_str(input).unwrap();

    assert_eq!(
        envelope.payload.get(),
        r#"{ "nested": [1, 2, 3], "ok": true }"#
    );

    let input_start = input.as_ptr() as usize;
    let input_end = input_start + input.len();
    let raw_start = envelope.payload.get().as_ptr() as usize;
    let raw_end = raw_start + envelope.payload.get().len();
    assert!(raw_start >= input_start);
    assert!(raw_end <= input_end);
}

#[test]
fn raw_value_interoperates_with_serde_json_in_both_directions() {
    let json = r#"{ "answer": 42, "items": [true, null] }"#;

    let ours_with_serde: &RawValue = serde_json::from_str(json).unwrap();
    let theirs_with_ours: &serde_json::value::RawValue = blazingly_json::from_str(json).unwrap();

    assert_eq!(ours_with_serde.get(), json);
    assert_eq!(theirs_with_ours.get(), json);
    assert_eq!(serde_json::to_string(ours_with_serde).unwrap(), json);
    assert_eq!(blazingly_json::to_string(theirs_with_ours).unwrap(), json);
}

#[test]
fn borrowed_raw_value_serializes_verbatim_in_compact_and_pretty_output() {
    let raw: &RawValue = blazingly_json::from_str(r#"{ "x": [1, 2] }"#).unwrap();
    let output = BorrowedOutput { payload: raw };

    assert_eq!(
        blazingly_json::to_string(&output).unwrap(),
        r#"{"payload":{ "x": [1, 2] }}"#
    );
    assert_eq!(
        blazingly_json::to_string_pretty(&output).unwrap(),
        "{\n  \"payload\": { \"x\": [1, 2] }\n}"
    );

    assert_eq!(raw.to_vec(), br#"{ "x": [1, 2] }"#);
    let mut direct = Vec::new();
    raw.write_to(&mut direct).unwrap();
    assert_eq!(direct, raw.to_vec());
}

#[test]
fn boxed_raw_value_matches_serde_json_and_round_trips_allocation() {
    let mut json = String::with_capacity(64);
    json.push_str(r#"{"method":"tools/call","id":7}"#);
    json.shrink_to_fit();
    let original_pointer = json.as_ptr();

    let raw = RawValue::from_string(json).unwrap();
    assert_eq!(raw.get(), r#"{"method":"tools/call","id":7}"#);
    assert_eq!(raw.get().as_ptr(), original_pointer);

    let json = raw.into_string();
    assert_eq!(json.as_ptr(), original_pointer);
    assert_eq!(json, r#"{"method":"tools/call","id":7}"#);

    let ours: Box<RawValue> = blazingly_json::from_str("[1, 2, 3]").unwrap();
    let reference: Box<serde_json::value::RawValue> = serde_json::from_str("[1, 2, 3]").unwrap();
    assert_eq!(ours.get(), reference.get());
}

#[test]
fn from_string_matches_reference_validation_and_whitespace_behavior() {
    let cases = [
        "null",
        " true ",
        "\n{\"a\": 1, \"b\": [2, 3]}\t",
        r#""escaped\nstring""#,
        "-12.5e3",
        "",
        "null trailing",
        "{]",
    ];

    for input in cases {
        let ours = RawValue::from_string(input.to_owned());
        let reference = serde_json::value::RawValue::from_string(input.to_owned());
        assert_eq!(
            ours.as_ref().ok().map(|value| value.get()),
            reference.as_ref().ok().map(|value| value.get()),
            "input: {input:?}"
        );
        assert_eq!(ours.is_ok(), reference.is_ok(), "input: {input:?}");
    }
}

#[test]
fn constants_clone_default_and_box_conversion_match_expected_values() {
    assert_eq!(RawValue::NULL.get(), "null");
    assert_eq!(RawValue::TRUE.get(), "true");
    assert_eq!(RawValue::FALSE.get(), "false");
    assert_eq!(Box::<RawValue>::default().get(), "null");

    let raw = RawValue::from_string(r#"{"x":1}"#.to_owned()).unwrap();
    let cloned = raw.clone();
    assert_eq!(cloned.get(), raw.get());
    assert_ne!(cloned.get().as_ptr(), raw.get().as_ptr());

    let boxed_str: Box<str> = raw.into();
    assert_eq!(&*boxed_str, r#"{"x":1}"#);
}

#[test]
fn to_raw_value_and_to_value_preserve_json_semantics() {
    #[derive(Serialize)]
    struct Payload<'a> {
        method: &'a str,
        ids: [u64; 3],
    }

    let raw = to_raw_value(&Payload {
        method: "query_graph",
        ids: [1, 2, 3],
    })
    .unwrap();

    assert_eq!(raw.get(), r#"{"method":"query_graph","ids":[1,2,3]}"#);
    assert_eq!(
        blazingly_json::to_value(&raw).unwrap(),
        blazingly_json::json!({"method": "query_graph", "ids": [1, 2, 3]})
    );

    let deserialized: Value = Deserialize::deserialize(&*raw).unwrap();
    assert_eq!(
        deserialized,
        blazingly_json::json!({"method": "query_graph", "ids": [1, 2, 3]})
    );
}

#[test]
fn raw_value_rejects_invalid_json_and_trailing_data() {
    for invalid in ["", "{", "[1,]", "true false", "\"unterminated"] {
        assert!(blazingly_json::from_str::<&RawValue>(invalid).is_err());
        assert!(blazingly_json::from_str::<Box<RawValue>>(invalid).is_err());
    }

    let invalid_utf8 = [b'"', 0xff, b'"'];
    assert!(blazingly_json::from_slice::<&RawValue>(&invalid_utf8).is_err());
}

#[test]
fn raw_value_reference_has_the_same_fat_pointer_size_as_str() {
    assert_eq!(
        std::mem::size_of::<&RawValue>(),
        std::mem::size_of::<&str>()
    );
    assert_eq!(
        std::mem::align_of::<&RawValue>(),
        std::mem::align_of::<&str>()
    );
}

#[test]
fn raw_value_deserializer_preserves_typed_enum_and_tuple_entry_points() {
    #[derive(Debug, Deserialize, PartialEq)]
    enum Event {
        Ping,
        Data { id: u64 },
    }

    let event_raw: &RawValue = blazingly_json::from_str(r#"{"Data":{"id":17}}"#).unwrap();
    let event = Event::deserialize(event_raw).unwrap();
    assert_eq!(event, Event::Data { id: 17 });

    let tuple_raw: &RawValue = blazingly_json::from_str(r#"["query_graph",20]"#).unwrap();
    let tuple = <(String, u64)>::deserialize(tuple_raw).unwrap();
    assert_eq!(tuple, ("query_graph".to_owned(), 20));
}

#[test]
fn strict_raw_fast_paths_fall_back_without_changing_semantics() {
    let cases = [
        "[]",
        "[0,-0,1.25,3e8,-4.5E-2]",
        r#"[{"id":1,"ok":true,"name":"a"},{"id":2,"ok":false,"name":"b"}]"#,
        r#"[{"escaped":"line\nbreak","nested":[1,2,3]}]"#,
        r#"[ { "id": 1, "nested": { "x": true } } ]"#,
        "[01]",
        r#"[{"id":1,}]"#,
        r#"[{"unterminated":"value}]"#,
    ];

    for input in cases {
        let ours = blazingly_json::from_str::<&RawValue>(input);
        let reference = serde_json::from_str::<&serde_json::value::RawValue>(input);
        assert_eq!(ours.is_ok(), reference.is_ok(), "input: {input:?}");
        if let (Ok(ours), Ok(reference)) = (ours, reference) {
            assert_eq!(ours.get(), reference.get(), "input: {input:?}");
        }
    }
}