use std::collections::BTreeMap;
use beve::{Complex, EnumEncoding, Error, SerializerOptions, TypedSlice};
use half::{bf16, f16};
use serde::ser::{SerializeMap, SerializeSeq};
use serde::{Deserialize, Serialize, Serializer};
fn assert_size_eq<T: Serialize>(value: &T) {
let mut buf = Vec::new();
beve::to_writer_streaming(&mut buf, value).expect("streaming serialize should succeed");
let measured = beve::serialized_size(value).expect("serialized_size should succeed");
assert_eq!(
measured,
buf.len() as u64,
"serialized_size ({measured}) disagreed with streamed length ({})",
buf.len()
);
}
fn assert_size_eq_opts<T: Serialize>(value: &T, opts: SerializerOptions) {
let mut buf = Vec::new();
beve::to_writer_streaming_with_options(&mut buf, value, opts)
.expect("streaming serialize should succeed");
let measured =
beve::serialized_size_with_options(value, opts).expect("serialized_size should succeed");
assert_eq!(measured, buf.len() as u64);
}
#[test]
fn scalars() {
assert_size_eq(&true);
assert_size_eq(&false);
assert_size_eq(&0u8);
assert_size_eq(&255u8);
assert_size_eq(&-1i8);
assert_size_eq(&12345u16);
assert_size_eq(&-12345i16);
assert_size_eq(&123_456_789u32);
assert_size_eq(&-123_456_789i32);
assert_size_eq(&123_456_789_012_345u64);
assert_size_eq(&-123i64);
assert_size_eq(&u128::MAX);
assert_size_eq(&i128::MIN);
assert_size_eq(&12.625f32);
assert_size_eq(&98.5f64);
assert_size_eq(&'A');
assert_size_eq(&'€'); assert_size_eq(&()); }
#[test]
fn strings() {
assert_size_eq(&String::new());
assert_size_eq(&"hello".to_string());
assert_size_eq(&"héllo wörld — 日本語 🎉".to_string()); assert_size_eq(&"x".repeat(63));
assert_size_eq(&"y".repeat(64));
assert_size_eq(&"z".repeat(16_383));
assert_size_eq(&"w".repeat(16_384));
}
#[test]
fn numeric_typed_arrays() {
assert_size_eq(&Vec::<u8>::new());
assert_size_eq(&vec![1u8, 2, 3]);
assert_size_eq(&Vec::<i8>::new());
assert_size_eq(&vec![-1i8, 2, -3]);
assert_size_eq(&Vec::<u16>::new());
assert_size_eq(&vec![1u16, 65535]);
assert_size_eq(&Vec::<i16>::new());
assert_size_eq(&vec![-1i16, 2]);
assert_size_eq(&Vec::<u32>::new());
assert_size_eq(&vec![1u32, 2, 3, 4]);
assert_size_eq(&Vec::<i32>::new());
assert_size_eq(&vec![-1i32, 2, -3]);
assert_size_eq(&Vec::<u64>::new());
assert_size_eq(&vec![1u64, 2]);
assert_size_eq(&Vec::<i64>::new());
assert_size_eq(&vec![-1i64, 2]);
assert_size_eq(&Vec::<u128>::new());
assert_size_eq(&vec![1u128, u128::MAX]);
assert_size_eq(&Vec::<i128>::new());
assert_size_eq(&vec![i128::MIN, 0, i128::MAX]);
assert_size_eq(&Vec::<f32>::new());
assert_size_eq(&vec![1.0f32, -2.5, 3.25]);
assert_size_eq(&Vec::<f64>::new());
assert_size_eq(&vec![1.0f64, -2.5, 3.25]);
}
#[test]
fn bool_arrays_bit_packed() {
assert_size_eq(&Vec::<bool>::new());
assert_size_eq(&vec![true]);
assert_size_eq(&vec![true, false, true, true, false, false, true, false]);
assert_size_eq(&vec![true; 9]);
assert_size_eq(&vec![false; 100]);
}
#[test]
fn string_arrays() {
assert_size_eq(&Vec::<String>::new());
assert_size_eq(&vec!["a".to_string(), "bb".to_string(), "ccc".to_string()]);
assert_size_eq(&vec!["日本語".to_string(), String::new()]);
}
#[derive(Serialize)]
struct TupleStruct(i32, String, Vec<f64>);
#[test]
fn tuples_and_heterogeneous() {
assert_size_eq(&(1i32, "two".to_string(), 3.0f64));
assert_size_eq(&(true, ()));
assert_size_eq(&TupleStruct(7, "k".to_string(), vec![1.0, 2.0]));
assert_size_eq(&vec![vec![1i32, 2], vec![3, 4, 5]]);
assert_size_eq(&(
"label".to_string(),
Inner {
a: 1.0,
b: "z".into(),
},
));
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
struct Inner {
a: f64,
b: String,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
struct Outer {
id: u32,
inner: Inner,
tags: Vec<String>,
values: Vec<f64>,
maybe: Option<i32>,
nope: Option<i32>,
}
fn sample_outer() -> Outer {
Outer {
id: 9,
inner: Inner {
a: 0.0,
b: "nested".into(),
},
tags: vec!["x".into(), "yy".into()],
values: vec![1.5, -2.5, 3.5],
maybe: Some(5),
nope: None,
}
}
#[test]
fn structs_and_options() {
assert_size_eq(&Inner {
a: 1.5,
b: "hi".into(),
});
assert_size_eq(&sample_outer());
assert_size_eq(&Some(42i32));
assert_size_eq(&Option::<i32>::None);
assert_size_eq(&Some("str".to_string()));
}
#[test]
fn maps() {
let empty: BTreeMap<String, i32> = BTreeMap::new();
assert_size_eq(&empty);
let mut string_keyed: BTreeMap<String, i32> = BTreeMap::new();
string_keyed.insert("alpha".into(), 1);
string_keyed.insert("beta".into(), 2);
string_keyed.insert("日本語".into(), 3);
assert_size_eq(&string_keyed);
let mut signed_keyed: BTreeMap<i32, String> = BTreeMap::new();
signed_keyed.insert(-1, "neg".into());
signed_keyed.insert(2, "two".into());
assert_size_eq(&signed_keyed);
let mut unsigned_keyed: BTreeMap<u64, f64> = BTreeMap::new();
unsigned_keyed.insert(10, 1.0);
unsigned_keyed.insert(20, 2.0);
assert_size_eq(&unsigned_keyed);
}
#[derive(Serialize)]
enum E {
Unit,
Newtype(i32),
Tuple(i32, String),
Struct { x: f64, y: f64 },
}
#[test]
fn enum_variants_default() {
let variants = [
E::Unit,
E::Newtype(7),
E::Tuple(1, "a".into()),
E::Struct { x: 1.0, y: 2.0 },
];
for v in &variants {
assert_size_eq(v);
}
}
#[test]
fn enum_variants_options_parity() {
let number = SerializerOptions {
enum_encoding: EnumEncoding::Number,
};
let string = SerializerOptions {
enum_encoding: EnumEncoding::String,
};
let variants = [
E::Unit,
E::Newtype(7),
E::Tuple(1, "a".into()),
E::Struct { x: 1.0, y: 2.0 },
];
for v in &variants {
assert_size_eq_opts(v, number);
assert_size_eq_opts(v, string);
}
}
#[test]
fn half_floats_and_complex() {
assert_size_eq(&bf16::from_f32(1.5));
assert_size_eq(&f16::from_f32(2.5));
assert_size_eq(&Complex {
re: 1.0f64,
im: -2.0f64,
});
assert_size_eq(&Complex {
re: 3.0f32,
im: 4.0f32,
});
assert_size_eq(&vec![
Complex {
re: 1.0f64,
im: 2.0,
},
Complex { re: 3.0, im: 4.0 },
]);
assert_size_eq(&vec![
Complex {
re: 0.5f32,
im: -0.5,
},
Complex { re: 1.5, im: 2.5 },
]);
}
#[test]
fn typed_slice_bodies() {
let f64s = vec![1.0f64, 2.0, 3.0, 4.0];
assert_size_eq(&TypedSlice(&f64s));
let empty: Vec<f64> = Vec::new();
assert_size_eq(&TypedSlice(&empty));
let u32s = vec![10u32, 20, 30];
assert_size_eq(&TypedSlice(&u32s));
let mut buf = Vec::new();
beve::to_writer_typed_slice(&mut buf, &f64s).unwrap();
let measured = beve::serialized_size(&TypedSlice(&f64s)).unwrap();
assert_eq!(measured, buf.len() as u64);
assert_eq!(measured, beve::typed_slice_size(&f64s));
}
#[test]
fn size_prefix_boundaries() {
for n in [0usize, 1, 63, 64, 16_383, 16_384] {
let arr: Vec<u16> = vec![7u16; n];
assert_size_eq(&arr);
let s = "a".repeat(n);
assert_size_eq(&s);
}
}
struct Blob(Vec<u8>);
impl Serialize for Blob {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_bytes(&self.0)
}
}
#[test]
fn bytes_path_matches_vec_path() {
let raw: Vec<u8> = (0..200u32).map(|x| x as u8).collect();
let as_vec = raw.clone();
let as_bytes = Blob(raw);
assert_size_eq(&as_vec);
assert_size_eq(&as_bytes);
let vec_size = beve::serialized_size(&as_vec).unwrap();
let bytes_size = beve::serialized_size(&as_bytes).unwrap();
assert_eq!(vec_size, bytes_size);
}
struct UnknownLenSeq(Vec<i32>);
impl Serialize for UnknownLenSeq {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut seq = serializer.serialize_seq(None)?;
for x in &self.0 {
seq.serialize_element(x)?;
}
seq.end()
}
}
struct UnknownLenMap(Vec<(String, i32)>);
impl Serialize for UnknownLenMap {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
for (k, v) in &self.0 {
map.serialize_entry(k, v)?;
}
map.end()
}
}
#[test]
fn rejection_parity_unknown_len_seq() {
let value = UnknownLenSeq(vec![1, 2, 3]);
let mut buf = Vec::new();
let stream_err = beve::to_writer_streaming(&mut buf, &value).unwrap_err();
let size_err = beve::serialized_size(&value).unwrap_err();
assert!(
matches!(stream_err, Error::Unsupported(_)),
"streaming should reject unknown-length seq, got {stream_err:?}"
);
assert!(
matches!(size_err, Error::Unsupported(_)),
"serialized_size should reject unknown-length seq, got {size_err:?}"
);
}
#[test]
fn rejection_parity_unknown_len_map() {
let value = UnknownLenMap(vec![("a".into(), 1), ("b".into(), 2)]);
let mut buf = Vec::new();
let stream_err = beve::to_writer_streaming(&mut buf, &value).unwrap_err();
let size_err = beve::serialized_size(&value).unwrap_err();
assert!(
matches!(stream_err, Error::Unsupported(_)),
"streaming should reject unknown-length map, got {stream_err:?}"
);
assert!(
matches!(size_err, Error::Unsupported(_)),
"serialized_size should reject unknown-length map, got {size_err:?}"
);
}
#[test]
fn framing_body_length_is_exact_and_round_trips() {
let value = sample_outer();
let body_len = beve::serialized_size(&value).unwrap();
let mut frame = Vec::new();
frame.extend_from_slice(&body_len.to_le_bytes()); let header_len = frame.len();
beve::to_writer_streaming(&mut frame, &value).unwrap();
let written_body = (frame.len() - header_len) as u64;
assert_eq!(
written_body, body_len,
"streamed body length must equal the advertised serialized_size"
);
let decoded: Outer = beve::from_slice(&frame[header_len..]).unwrap();
assert_eq!(decoded, value);
}