use structio::{
ErrorCode, Options, SkipNull, beve, from_beve, from_str, json, to_beve, to_beve_with,
to_string, to_string_with,
};
#[derive(Debug, Default, PartialEq)]
struct Handle(u32);
impl json::Write for Handle {
fn write<O: Options>(&self, w: &mut json::Writer<'_, O>) {
json::Write::write(&self.0, w);
}
}
impl<'de> json::Read<'de> for Handle {
fn read<O: Options>(&mut self, p: &mut json::Parser<'de, O>) -> Result<(), ErrorCode> {
p.skip_value()
}
}
impl beve::Write for Handle {
fn write<O: Options>(&self, w: &mut beve::Writer<'_, O>) {
beve::Write::write(&self.0, w);
}
}
impl<'de> beve::Read<'de> for Handle {
fn read<O: Options>(&mut self, r: &mut beve::Reader<'de, O>) -> Result<(), ErrorCode> {
r.skip_value()
}
}
#[derive(Debug, Default, PartialEq)]
struct Meter {
handle: Handle,
reading: f64,
label: String,
}
structio::object!(Meter {
handle,
reading,
label,
});
#[test]
fn a_skipping_read_still_writes_the_real_value() {
let meter = Meter {
handle: Handle(7),
reading: 1.5,
label: "inlet".to_string(),
};
assert_eq!(
to_string(&meter),
r#"{"handle":7,"reading":1.5,"label":"inlet"}"#
);
}
#[test]
fn a_skipping_read_leaves_the_field_alone_and_the_cursor_right() {
let back: Meter = from_str(r#"{"handle":7,"reading":1.5,"label":"inlet"}"#).unwrap();
assert_eq!(
back,
Meter {
handle: Handle::default(),
reading: 1.5,
label: "inlet".to_string(),
}
);
}
#[test]
fn the_skip_covers_a_composite_the_document_put_there() {
let back: Meter =
from_str(r#"{"handle":{"table":2,"slot":7},"reading":1.5,"label":"inlet"}"#).unwrap();
assert_eq!(back.reading, 1.5);
assert_eq!(back.label, "inlet");
}
#[test]
fn the_beve_half_behaves_the_same() {
let meter = Meter {
handle: Handle(7),
reading: 1.5,
label: "inlet".to_string(),
};
let bytes = to_beve(&meter);
let back: Meter = from_beve(&bytes).unwrap();
assert_eq!(
back,
Meter {
handle: Handle::default(),
reading: 1.5,
label: "inlet".to_string(),
}
);
}
struct AsHandle;
impl json::WriteAs<Handle> for AsHandle {
fn write<O: Options>(value: &Handle, w: &mut json::Writer<'_, O>) {
json::Write::write(&value.0, w);
}
}
impl<'de> json::ReadAs<'de, Handle> for AsHandle {
fn read<O: Options>(
_value: &mut Handle,
p: &mut json::Parser<'de, O>,
) -> Result<(), ErrorCode> {
p.skip_value()
}
}
impl beve::WriteAs<Handle> for AsHandle {
fn write<O: Options>(value: &Handle, w: &mut beve::Writer<'_, O>) {
beve::Write::write(&value.0, w);
}
}
impl<'de> beve::ReadAs<'de, Handle> for AsHandle {
fn read<O: Options>(
_value: &mut Handle,
r: &mut beve::Reader<'de, O>,
) -> Result<(), ErrorCode> {
r.skip_value()
}
}
#[derive(Debug, Default, PartialEq)]
struct Gauge {
handle: Handle,
reading: f64,
}
structio::object!(Gauge {
handle as AsHandle,
reading,
});
#[test]
fn an_adapter_carries_the_same_pair() {
let gauge = Gauge {
handle: Handle(7),
reading: 1.5,
};
assert_eq!(to_string(&gauge), r#"{"handle":7,"reading":1.5}"#);
let back: Gauge = from_str(r#"{"handle":7,"reading":1.5}"#).unwrap();
assert_eq!(
back,
Gauge {
handle: Handle::default(),
reading: 1.5,
}
);
let bytes = to_beve(&gauge);
let back: Gauge = from_beve(&bytes).unwrap();
assert_eq!(
back,
Gauge {
handle: Handle::default(),
reading: 1.5,
}
);
}
#[derive(Debug, Default, PartialEq)]
struct Token(u32);
impl<'de> json::Read<'de> for Token {
fn read<O: Options>(&mut self, p: &mut json::Parser<'de, O>) -> Result<(), ErrorCode> {
json::Read::read(&mut self.0, p)
}
}
impl json::Write for Token {
fn write<O: Options>(&self, w: &mut json::Writer<'_, O>) {
w.write_null();
}
fn is_null(&self) -> bool {
true
}
}
impl<'de> beve::Read<'de> for Token {
fn read<O: Options>(&mut self, r: &mut beve::Reader<'de, O>) -> Result<(), ErrorCode> {
beve::Read::read(&mut self.0, r)
}
}
impl beve::Write for Token {
fn write<O: Options>(&self, w: &mut beve::Writer<'_, O>) {
w.write_null();
}
fn is_null(&self) -> bool {
true
}
}
#[derive(Debug, Default, PartialEq)]
struct Session {
token: Token,
user: String,
}
structio::object!(Session { token, user });
#[test]
fn a_null_writing_stub_still_reads_for_real() {
let session: Session = from_str(r#"{"token":9,"user":"ada"}"#).unwrap();
assert_eq!(
session,
Session {
token: Token(9),
user: "ada".to_string(),
}
);
}
#[test]
fn the_default_policy_writes_the_null_rather_than_nothing() {
let session = Session {
token: Token(9),
user: "ada".to_string(),
};
assert_eq!(to_string(&session), r#"{"token":null,"user":"ada"}"#);
}
#[test]
fn skip_null_drops_the_member_key_and_all() {
let session = Session {
token: Token(9),
user: "ada".to_string(),
};
assert_eq!(to_string_with::<SkipNull, _>(&session), r#"{"user":"ada"}"#);
let back: Session = from_str(&to_string_with::<SkipNull, _>(&session)).unwrap();
assert_eq!(
back,
Session {
token: Token::default(),
user: "ada".to_string(),
}
);
}
#[test]
fn the_beve_half_agrees_with_its_member_count() {
let session = Session {
token: Token(9),
user: "ada".to_string(),
};
let all = to_beve(&session);
let dropped = to_beve_with::<SkipNull, _>(&session);
assert!(dropped.len() < all.len());
let back: Session = from_beve(&dropped).unwrap();
assert_eq!(
back,
Session {
token: Token::default(),
user: "ada".to_string(),
}
);
}
#[test]
fn the_null_a_keeping_policy_writes_is_not_read_back_by_this_type() {
let session = Session {
token: Token(9),
user: "ada".to_string(),
};
let text = to_string(&session);
assert_eq!(
from_str::<Session>(&text).unwrap_err().code,
ErrorCode::ExpectedNumber
);
let bytes = to_beve(&session);
assert_eq!(
from_beve::<Session>(&bytes).unwrap_err().code,
ErrorCode::ExpectedNumber
);
}