use substrate_data::binary::Writer;
use substrate_data::{Schema, Stream, Value, to_bytes};
use crate::case::Case;
pub(crate) fn cases() -> Vec<Case> {
let mut all = packed_ints();
all.extend(packed_floats());
all.extend(streams());
all
}
fn ints(items: &[i64]) -> Value {
Value::List(items.iter().map(|&n| Value::Int(n)).collect())
}
fn floats(items: &[f64]) -> Value {
Value::List(items.iter().map(|&f| Value::Float(f)).collect())
}
fn written(name: &str, description: &str, value: Value, bytes: Vec<u8>) -> Case {
let text = substrate_data::text::to_string(&value);
Case::new(name, description)
.text(&text)
.value(value)
.binary(bytes)
}
fn packed_ints() -> Vec<Case> {
let sets: [(&str, &[i64]); 4] = [
("empty", &[]),
("small", &[0, -1, 1, 63, -64]),
("varints", &[64, -65, 8192, 2_147_483_648]),
("extremes", &[i64::MIN, i64::MAX, 0]),
];
sets.iter()
.map(|&(name, items)| {
let mut w = Writer::new();
w.ints(items.iter().copied());
written(
&format!("ints_packed_{name}"),
"A list of ints packed: tag 10, a count, then a zigzag varint per item with no tag each. Decodes to the same list as tag 6 would.",
ints(items),
w.finish(),
)
})
.collect()
}
fn packed_floats() -> Vec<Case> {
let mut single = Writer::new();
single.float32(0.5);
let mut narrow = Writer::new();
narrow.floats(&[0.5, 1.5, -0.0]);
let mut wide = Writer::new();
wide.floats(&[0.1, 0.2]);
let mut mixed = Writer::new();
mixed.floats(&[0.5, 0.1]);
vec![
written(
"float32_single",
"A float that is an f32: tag 12, four bytes little-endian. Decodes to the f64 of the same value.",
Value::Float(0.5),
single.finish(),
),
written(
"floats_packed_narrow",
"A writer picks tag 14 (f32 each) when every f64 survives the round trip through f32 bit for bit; -0.0 does.",
floats(&[0.5, 1.5, -0.0]),
narrow.finish(),
),
written(
"floats_packed_wide",
"Tag 13 (f64 each) when any one does not: 0.1 is not an f32.",
floats(&[0.1, 0.2]),
wide.finish(),
),
written(
"floats_packed_mixed",
"One value that is not an f32 widens the whole list, 0.5 included.",
floats(&[0.5, 0.1]),
mixed.finish(),
),
]
.into_iter()
.chain(more_floats())
.collect()
}
fn more_floats() -> Vec<Case> {
let mut empty = Writer::new();
empty.floats(&[]);
let mut f32s = Writer::new();
f32s.floats32(&[0.5, f32::MAX]);
let mut nan = Writer::new();
nan.floats(&[f64::NAN, f64::INFINITY]);
vec![
written(
"floats_packed_empty",
"An empty list of floats picks the narrow tag 14.",
Value::List(vec![]),
empty.finish(),
),
written(
"floats32_packed",
"A list of f32s: tag 14 always, 4 bytes each.",
floats(&[0.5, f64::from(f32::MAX)]),
f32s.finish(),
),
nan_case(nan.finish()),
]
}
fn nan_case(bytes: Vec<u8>) -> Case {
Case::new(
"floats_packed_non_finite",
"Binary only (text writes null for them): a quiet NaN and infinity survive f32 bit for bit, so the narrow tag 14 is used.",
)
.value(floats(&[f64::NAN, f64::INFINITY]))
.binary(bytes)
}
#[derive(Schema, Debug)]
struct Log {
name: String,
entries: Stream<String>,
}
#[derive(Schema, Debug)]
struct Counter {
hits: Stream<u32>,
}
fn streams() -> Vec<Case> {
let entries =
|items: &[&str]| -> Stream<String> { items.iter().map(|s| (*s).to_owned()).collect() };
let empty = Log {
name: "audit".into(),
entries: entries(&[]),
};
let repeats = Log {
name: "audit".into(),
entries: entries(&["opened", "saved", "opened", "audit"]),
};
let counter = Counter {
hits: (0..6u32).map(|i| i * 1000).collect(),
};
vec![
schema_case(
"stream_empty",
"An empty stream: tag 11, a u32 byte length (here 1), then the count 0.",
&empty,
),
schema_case(
"stream_own_table",
"A stream has its own string table: `audit` is written again inside it although the document already has it, and `opened` is written once inside.",
&repeats,
),
schema_case(
"stream_ints",
"Stream items are values: six ints, each tag 3 and a zigzag varint.",
&counter,
),
]
}
fn schema_case<T: Schema>(name: &str, description: &str, x: &T) -> Case {
let bytes = to_bytes(x);
let value = substrate_data::binary::decode(&bytes).expect("the writer's own bytes");
written(name, description, value, bytes)
}