forte-json 0.1.0

Streaming JSON serializer for the Forte web framework
Documentation
use forte_json::to_stream;
use futures::StreamExt;
use serde::Serialize;

async fn stream_to_string<T: Serialize + ?Sized>(value: &T) -> String {
    let stream = to_stream(value);
    let chunks: Vec<_> = stream.collect().await;
    chunks
        .iter()
        .map(|b| String::from_utf8_lossy(b).to_string())
        .collect::<Vec<_>>()
        .join("")
}

#[tokio::test]
async fn test_null() {
    let value: Option<i32> = None;
    assert_eq!(stream_to_string(&value).await, "null");
}

#[tokio::test]
async fn test_bool() {
    assert_eq!(stream_to_string(&true).await, "true");
    assert_eq!(stream_to_string(&false).await, "false");
}

#[tokio::test]
async fn test_integers() {
    assert_eq!(stream_to_string(&0).await, "0");
    assert_eq!(stream_to_string(&42).await, "42");
    assert_eq!(stream_to_string(&-100).await, "-100");
    assert_eq!(stream_to_string(&i64::MAX).await, "9223372036854775807");
    assert_eq!(stream_to_string(&u64::MAX).await, "18446744073709551615");
}

#[tokio::test]
async fn test_floats() {
    assert_eq!(stream_to_string(&0.0_f64).await, "0");
    assert_eq!(stream_to_string(&1.5_f64).await, "1.5");
    assert_eq!(stream_to_string(&-2.5_f64).await, "-2.5");
}

#[tokio::test]
async fn test_string() {
    assert_eq!(stream_to_string(&"hello").await, r#""hello""#);
    assert_eq!(stream_to_string(&"").await, r#""""#);
}

#[tokio::test]
async fn test_string_escaping() {
    assert_eq!(stream_to_string(&"hello\\world").await, r#""hello\\world""#);
    assert_eq!(stream_to_string(&"quote\"test").await, r#""quote\"test""#);
}

#[tokio::test]
async fn test_array() {
    let arr: Vec<i32> = vec![1, 2, 3];
    assert_eq!(stream_to_string(&arr).await, "[1,2,3]");
}

#[tokio::test]
async fn test_empty_array() {
    let arr: Vec<i32> = vec![];
    assert_eq!(stream_to_string(&arr).await, "[]");
}

#[derive(Serialize)]
struct Point {
    x: i32,
    y: i32,
}

#[tokio::test]
async fn test_struct() {
    let point = Point { x: 10, y: 20 };
    assert_eq!(stream_to_string(&point).await, r#"{"x":10,"y":20}"#);
}

#[derive(Serialize)]
struct ComplexStruct {
    name: String,
    age: u32,
    active: bool,
}

#[tokio::test]
async fn test_complex_struct() {
    let value = ComplexStruct {
        name: "Alice".to_string(),
        age: 30,
        active: true,
    };
    let json = stream_to_string(&value).await;
    assert_eq!(json, r#"{"name":"Alice","age":30,"active":true}"#);
}

#[tokio::test]
async fn test_nested_struct() {
    let point = Point { x: 5, y: 15 };
    let json = stream_to_string(&point).await;
    assert!(json.contains("x"));
    assert!(json.contains("10") || json.contains("5"));
}

#[tokio::test]
async fn test_option_some() {
    let value: Option<i32> = Some(42);
    assert_eq!(stream_to_string(&value).await, "42");
}

#[tokio::test]
async fn test_option_none() {
    let value: Option<i32> = None;
    assert_eq!(stream_to_string(&value).await, "null");
}

#[derive(Serialize)]
struct OptionalFields {
    required: i32,
    optional: Option<String>,
}

#[tokio::test]
async fn test_struct_with_option() {
    let v1 = OptionalFields {
        required: 10,
        optional: Some("value".to_string()),
    };
    let json = stream_to_string(&v1).await;
    assert_eq!(json, r#"{"required":10,"optional":"value"}"#);

    let v2 = OptionalFields {
        required: 20,
        optional: None,
    };
    let json = stream_to_string(&v2).await;
    assert_eq!(json, r#"{"required":20,"optional":null}"#);
}

#[derive(Serialize)]
struct SnakeCaseFields {
    first_name: String,
    last_name: String,
    user_age: u32,
}

#[tokio::test]
async fn test_snake_case_to_camel_case() {
    let value = SnakeCaseFields {
        first_name: "John".to_string(),
        last_name: "Doe".to_string(),
        user_age: 25,
    };
    let json = stream_to_string(&value).await;
    assert_eq!(json, r#"{"firstName":"John","lastName":"Doe","userAge":25}"#);
}