sark-json 0.27.0

Borrowed JSON decoding and streaming encoding for sark
Documentation
use std::num::NonZero;
pub mod common;
use o3::buffer::storage::Shared;
use sark_json::{
    parsing::{Decode, Request},
    segment,
};

use crate::common::decode::*;

fn ready<T>(progress: segment::Progress<'_, T>) -> Option<T> {
    match progress {
        segment::Progress::Pending => None,
        segment::Progress::Ready(value) => Some(value),
        segment::Progress::Failed(error) => {
            panic!("complete segmented input must decode: {error:?}")
        }
        segment::Progress::NeedInput => panic!("complete segmented input requested more data"),
    }
}

#[test]
fn generic_decode_paths() {
    let raw = br#"{"text":"a\"b","number":42}"#;
    let owned = Shared::try_copy(raw).expect("allocate bounded JSON fixture");
    let owned = <General as Decode>::decode(owned).expect("owned decode");
    assert_eq!(owned.text.as_slice(), b"a\"b");
    assert_eq!(owned.number.as_slice(), b"42");

    let source = br#"{"text":"alpha"}"#;
    let plain = <Plain as Request>::decode(source).expect("plain borrowed decode");
    assert_eq!(plain.text, b"alpha");
}

#[test]
fn field_span_ownership() {
    let one = Shared::try_copy(br#"{"text":"alpha"}"#).expect("the literal segment must allocate");
    let expected = one.as_slice()[9..].as_ptr();
    let decoded = <Plain as Decode>::decode(one).expect("the complete literal must yield a value");
    assert_eq!(decoded.text.as_slice(), b"alpha");
    assert_eq!(decoded.text.as_slice().as_ptr(), expected);

    let mut decoder = segment::Decoder::<Plain>::new(vec![
        Shared::try_copy(br#"{"text":"al"#).expect("the first literal fragment must allocate"),
        Shared::try_copy(br#"pha"}"#).expect("the second literal fragment must allocate"),
    ])
    .expect("decoder input");
    let mut turns = 0;
    let decoded = loop {
        turns += 1;
        if let Some(decoded) = ready(decoder.poll(NonZero::<usize>::MIN.saturating_add(1))) {
            break decoded;
        }
    };
    assert!(turns > 1);
    assert_eq!(decoded.text.as_slice(), b"alpha");
}

#[test]
fn escaped_owner_join() {
    let first = Shared::try_copy(b"{\"text\":\"a\\").expect("allocate first JSON fragment");
    let second = Shared::try_copy(b"\"b\",\"number\":42}").expect("allocate second JSON fragment");
    let mut decoder =
        segment::Decoder::<General>::new(vec![first, second]).expect("admit segmented JSON input");
    let decoded = loop {
        if let Some(decoded) = ready(decoder.poll(NonZero::<usize>::MIN)) {
            break decoded;
        }
    };

    assert_eq!(decoded.text.as_slice(), b"a\"b");
    assert_eq!(decoded.number.as_slice(), b"42");
}

#[test]
fn skips_discarded_values_before_end() {
    for prefix in IGNORED_VALUES {
        let selected = Shared::try_copy(SELECTED_PREFIX).expect("selected owner");
        let ptr = selected.as_slice()[9..].as_ptr();
        let mut ignored = Vec::with_capacity(32 * 1024);
        ignored.extend_from_slice(prefix);
        ignored.resize(32 * 1024, b'x');
        let ignored = Shared::try_from(&mut ignored).expect("ignored owner");
        let skipped = ignored.as_slice().len();
        let mut decoder = segment::Decoder::<Selective>::try_stream().expect("decoder");
        for owner in [selected, ignored] {
            let segment::Transfer::Accepted(state) = decoder.push(owner.into()) else {
                panic!("input owner rejected");
            };
            decoder = state;
        }
        let mut turns = 0;
        let mut released = 0;
        let mut chunks = 0;
        loop {
            turns += 1;
            let progress = decoder.poll(NonZero::<usize>::MIN.saturating_add(1023));
            released += decoder.take_bytes();
            chunks += decoder.take_chunks().into_raw();
            match progress {
                segment::Progress::Pending => {}
                segment::Progress::NeedInput => break,
                _ => panic!("unfinished value must request input"),
            }
        }
        assert_eq!(released, skipped);
        assert_eq!(chunks, 1);
        assert_eq!(decoder.take_bytes(), 0);
        assert_eq!(decoder.take_chunks().into_raw(), 0);
        assert!(turns >= 32);
        let end = Shared::try_copy(VALUE_END).expect("closing owner");
        let segment::Transfer::Accepted(state) = decoder.push(end.into()) else {
            panic!("closing owner rejected");
        };
        let mut decoder = state.close();
        let decoded = loop {
            if let Some(decoded) = ready(decoder.poll(NonZero::<usize>::MIN.saturating_add(1023))) {
                break decoded;
            }
        };
        assert_eq!(decoded.text.as_slice(), b"alpha");
        assert_eq!(decoded.text.as_slice().as_ptr(), ptr);
    }
}