sark 0.12.0

Simple Asynchronous Rust webKit - Server
Documentation
use http::StatusCode;
use o3::buffer::{Bytes, Retained, Shared};
use sark::json::JsonEncode;
use sark::service::RouteSpec;

#[sark_gen::json(encode)]
struct Item {
    id: u64,
    name: String,
    score: f64,
}

#[sark_gen::json(encode)]
struct Output {
    ok: bool,
    delta: i64,
    #[field(seq, nested)]
    items: Vec<Item>,
}

#[sark_gen::json(encode)]
struct OwnedText {
    shared: Shared,
    retained: Bytes<Retained>,
}

#[sark_gen::json(encode)]
struct OptionalOutput {
    count: Option<u64>,
    delta: Option<i64>,
    score: Option<f64>,
    ok: Option<bool>,
    name: Option<String>,
    shared: Option<Shared>,
    retained: Option<Bytes<Retained>>,
    #[field(raw)]
    raw: Option<Shared>,
    #[field(plain)]
    plain: Option<Shared>,
}

#[sark_gen::request]
struct OwnedRequest {}

#[sark_gen::response(json)]
struct OwnedReply {
    status: StatusCode,
    body: OwnedText,
}

#[sark_gen::handler]
async fn owned_json(_request: OwnedRequest, _state: &()) -> OwnedReply {
    let shared = Shared::from_static(b"shared");
    OwnedReply {
        status: StatusCode::OK,
        body: OwnedText {
            shared: shared.clone(),
            retained: Bytes::<Retained>::from(shared),
        },
    }
}

#[test]
fn encode_only_supports_owned_output_shapes() {
    let output = Output {
        ok: true,
        delta: -7,
        items: vec![Item {
            id: 3,
            name: String::from("a\"b"),
            score: 1.25,
        }],
    };
    let encoded = output.encode_json();
    assert_eq!(
        encoded.as_slice(),
        br#"{"ok":true,"delta":-7,"items":[{"id":3,"name":"a\"b","score":1.25}]}"#
    );
    assert_eq!(encoded.len(), output.json_len());
}

#[test]
fn encode_only_maps_nonfinite_numbers_to_null() {
    let output = Item {
        id: 0,
        name: String::new(),
        score: f64::INFINITY,
    };
    let encoded = output.encode_json();
    assert_eq!(encoded.as_slice(), br#"{"id":0,"name":"","score":null}"#);
    assert_eq!(encoded.len(), output.json_len());
}

#[test]
fn shared_and_retained_bytes_form_owned_async_json() {
    fn require_route<T: RouteSpec>() {}
    require_route::<owned_json>();

    let shared = Shared::from_static(b"a\"b");
    let output = OwnedText {
        shared: shared.clone(),
        retained: Bytes::<Retained>::from(shared),
    };
    assert_eq!(
        output.encode_json().as_slice(),
        br#"{"shared":"a\"b","retained":"a\"b"}"#
    );
}

#[test]
fn optional_fields_share_the_scalar_encoding_plan() {
    let shared = Shared::from_static(b"a\"b");
    let present = OptionalOutput {
        count: Some(7),
        delta: Some(-3),
        score: Some(1.25),
        ok: Some(true),
        name: Some(String::from("x\"y")),
        shared: Some(shared.clone()),
        retained: Some(Bytes::<Retained>::from(shared)),
        raw: Some(Shared::from_static(b"17")),
        plain: Some(Shared::from_static(b"plain")),
    };
    let encoded = present.encode_json();
    assert_eq!(
        encoded.as_slice(),
        br#"{"count":7,"delta":-3,"score":1.25,"ok":true,"name":"x\"y","shared":"a\"b","retained":"a\"b","raw":17,"plain":"plain"}"#
    );
    assert_eq!(encoded.len(), present.json_len());

    let absent = OptionalOutput {
        count: None,
        delta: None,
        score: None,
        ok: None,
        name: None,
        shared: None,
        retained: None,
        raw: None,
        plain: None,
    };
    let encoded = absent.encode_json();
    assert_eq!(
        encoded.as_slice(),
        br#"{"count":null,"delta":null,"score":null,"ok":null,"name":null,"shared":null,"retained":null,"raw":null,"plain":null}"#
    );
    assert_eq!(encoded.len(), absent.json_len());
}