use crate::wire::encode::{WireEncode, WireEncodingKind};
use crate::wire::temporal::{DurationWireValue, EpochTimestampWireValue};
#[cfg(feature = "chrono")]
use chrono::{DateTime, Utc};
use std::{
collections::{BTreeMap, HashMap},
hash::Hash,
mem::{ManuallyDrop, MaybeUninit},
time::{Duration, SystemTime},
};
#[cfg(feature = "uuid")]
use uuid::Uuid;
#[cfg(feature = "url")]
use url::Url;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InvalidWireValue {
Bool,
OptionTag,
ResultTag,
EnumTag,
TemporalNanoseconds,
Url,
DateTimeUtc,
CustomConversion,
DuplicateMapKey,
}
impl std::fmt::Display for InvalidWireValue {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Bool => write!(formatter, "Bool"),
Self::OptionTag => write!(formatter, "OptionTag"),
Self::ResultTag => write!(formatter, "ResultTag"),
Self::EnumTag => write!(formatter, "EnumTag"),
Self::TemporalNanoseconds => write!(formatter, "TemporalNanoseconds"),
Self::Url => write!(formatter, "Url"),
Self::DateTimeUtc => write!(formatter, "DateTimeUtc"),
Self::CustomConversion => write!(formatter, "CustomConversion"),
Self::DuplicateMapKey => write!(formatter, "DuplicateMapKey"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DecodeError {
BufferTooSmall,
InvalidValue(InvalidWireValue),
}
impl std::fmt::Display for DecodeError {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::BufferTooSmall => write!(formatter, "BufferTooSmall"),
Self::InvalidValue(invalid_value) => write!(formatter, "InvalidValue({invalid_value})"),
}
}
}
pub type DecodeResult<T> = Result<(T, usize), DecodeError>;
pub trait WireDecode: Sized {
fn decode_from(buf: &[u8]) -> DecodeResult<Self>;
}
struct WireReader<'buffer> {
buffer: &'buffer [u8],
offset: usize,
}
impl<'buffer> WireReader<'buffer> {
#[inline]
fn new(buffer: &'buffer [u8]) -> Self {
Self { buffer, offset: 0 }
}
#[inline]
fn read_array<const N: usize>(&mut self) -> Result<[u8; N], DecodeError> {
self.read_exact(N)?
.try_into()
.map_err(|_| DecodeError::BufferTooSmall)
}
#[inline]
fn read_byte(&mut self) -> Result<u8, DecodeError> {
Ok(self.read_exact(1)?[0])
}
#[inline]
fn read_exact(&mut self, byte_count: usize) -> Result<&'buffer [u8], DecodeError> {
let start = self.offset;
let end = start + byte_count;
let bytes = self
.buffer
.get(start..end)
.ok_or(DecodeError::BufferTooSmall)?;
self.offset = end;
Ok(bytes)
}
#[inline]
fn read_value<T: WireDecode>(&mut self) -> Result<T, DecodeError> {
let (value, used) = T::decode_from(
self.buffer
.get(self.offset..)
.ok_or(DecodeError::BufferTooSmall)?,
)?;
self.offset += used;
Ok(value)
}
#[inline]
fn read_length_prefixed_bytes(&mut self) -> Result<&'buffer [u8], DecodeError> {
let byte_count = self.read_value::<u32>()? as usize;
self.read_exact(byte_count)
}
#[inline]
fn finish<T>(self, value: T) -> DecodeResult<T> {
Ok((value, self.offset))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum BoolWireValue {
False,
True,
}
impl TryFrom<u8> for BoolWireValue {
type Error = DecodeError;
fn try_from(tag: u8) -> Result<Self, Self::Error> {
match tag {
0 => Ok(Self::False),
1 => Ok(Self::True),
_ => Err(DecodeError::InvalidValue(InvalidWireValue::Bool)),
}
}
}
impl BoolWireValue {
fn into_bool(self) -> bool {
matches!(self, Self::True)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum OptionWireTag {
None,
Some,
}
impl TryFrom<u8> for OptionWireTag {
type Error = DecodeError;
fn try_from(tag: u8) -> Result<Self, Self::Error> {
match tag {
0 => Ok(Self::None),
1 => Ok(Self::Some),
_ => Err(DecodeError::InvalidValue(InvalidWireValue::OptionTag)),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ResultWireTag {
Ok,
Err,
}
impl TryFrom<u8> for ResultWireTag {
type Error = DecodeError;
fn try_from(tag: u8) -> Result<Self, Self::Error> {
match tag {
0 => Ok(Self::Ok),
1 => Ok(Self::Err),
_ => Err(DecodeError::InvalidValue(InvalidWireValue::ResultTag)),
}
}
}
macro_rules! impl_wire_decode_primitive {
($($ty:ty),*) => {
$(
impl WireDecode for $ty {
#[inline]
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
let bytes = reader.read_array::<{ core::mem::size_of::<$ty>() }>()?;
reader.finish(<$ty>::from_le_bytes(bytes))
}
}
)*
};
}
impl_wire_decode_primitive!(i8, i16, i32, i64, u8, u16, u32, u64, f32, f64);
impl WireDecode for bool {
#[inline]
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
let value = BoolWireValue::try_from(reader.read_byte()?)?.into_bool();
reader.finish(value)
}
}
impl WireDecode for isize {
#[inline]
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
let value = i64::from_le_bytes(reader.read_array::<8>()?) as isize;
reader.finish(value)
}
}
impl WireDecode for usize {
#[inline]
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
let value = u64::from_le_bytes(reader.read_array::<8>()?) as usize;
reader.finish(value)
}
}
impl WireDecode for String {
#[inline]
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
let string_bytes = reader.read_length_prefixed_bytes()?;
let string = unsafe { core::str::from_utf8_unchecked(string_bytes) }.to_owned();
reader.finish(string)
}
}
impl WireDecode for Duration {
#[inline]
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
let wire_value = DurationWireValue {
seconds: reader.read_value::<u64>()?,
nanos: reader.read_value::<u32>()?,
};
let duration = wire_value.into_duration().ok_or(DecodeError::InvalidValue(
InvalidWireValue::TemporalNanoseconds,
))?;
reader.finish(duration)
}
}
impl WireDecode for SystemTime {
#[inline]
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
let wire_value = EpochTimestampWireValue {
seconds: reader.read_value::<i64>()?,
nanos: reader.read_value::<u32>()?,
};
let system_time = wire_value
.into_system_time()
.ok_or(DecodeError::InvalidValue(
InvalidWireValue::TemporalNanoseconds,
))?;
reader.finish(system_time)
}
}
#[cfg(feature = "uuid")]
impl WireDecode for Uuid {
#[inline]
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
let hi = reader.read_value::<u64>()?;
let lo = reader.read_value::<u64>()?;
let mut bytes = [0u8; 16];
bytes[..8].copy_from_slice(&hi.to_be_bytes());
bytes[8..].copy_from_slice(&lo.to_be_bytes());
reader.finish(Uuid::from_bytes(bytes))
}
}
#[cfg(feature = "url")]
impl WireDecode for Url {
#[inline]
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
let string = reader.read_value::<String>()?;
let url =
Url::parse(&string).map_err(|_| DecodeError::InvalidValue(InvalidWireValue::Url))?;
reader.finish(url)
}
}
#[cfg(feature = "chrono")]
impl WireDecode for DateTime<Utc> {
#[inline]
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
let wire_value = EpochTimestampWireValue {
seconds: reader.read_value::<i64>()?,
nanos: reader.read_value::<u32>()?,
};
let date_time = wire_value
.into_date_time_utc()
.ok_or(DecodeError::InvalidValue(InvalidWireValue::DateTimeUtc))?;
reader.finish(date_time)
}
}
impl WireDecode for () {
#[inline]
fn decode_from(_buf: &[u8]) -> DecodeResult<Self> {
Ok(((), 0))
}
}
impl<T: WireDecode> WireDecode for Option<T> {
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
match OptionWireTag::try_from(reader.read_byte()?)? {
OptionWireTag::None => reader.finish(None),
OptionWireTag::Some => {
let value = reader.read_value::<T>()?;
reader.finish(Some(value))
}
}
}
}
impl<T: WireDecode, E: WireDecode> WireDecode for Result<T, E> {
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
match ResultWireTag::try_from(reader.read_byte()?)? {
ResultWireTag::Ok => {
let value = reader.read_value::<T>()?;
reader.finish(Ok(value))
}
ResultWireTag::Err => {
let value = reader.read_value::<E>()?;
reader.finish(Err(value))
}
}
}
}
impl<T: WireDecode> WireDecode for Box<T> {
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let (value, consumed) = T::decode_from(buf)?;
Ok((Box::new(value), consumed))
}
}
impl<T: WireDecode + WireEncode> WireDecode for Vec<T> {
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
let count = reader.read_value::<u32>()? as usize;
if count == 0 {
return reader.finish(Vec::new());
}
match T::ENCODING_KIND {
WireEncodingKind::Blittable => {
let element_size = core::mem::size_of::<T>();
let data_size = count * element_size;
let element_bytes = reader.read_exact(data_size)?;
let mut result = Vec::<MaybeUninit<T>>::with_capacity(count);
unsafe {
result.set_len(count);
core::ptr::copy_nonoverlapping(
element_bytes.as_ptr(),
result.as_mut_ptr() as *mut u8,
data_size,
);
let result = ManuallyDrop::new(result);
let initialized_values =
Vec::from_raw_parts(result.as_ptr() as *mut T, count, result.capacity());
return reader.finish(initialized_values);
}
}
WireEncodingKind::General => {}
}
let values = (0..count).try_fold(Vec::with_capacity(count), |mut values, _| {
values.push(reader.read_value::<T>()?);
Ok(values)
})?;
reader.finish(values)
}
}
impl<K, V> WireDecode for HashMap<K, V>
where
K: Eq + Hash + WireDecode,
V: WireDecode,
{
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
let count = reader.read_value::<u32>()? as usize;
let values = (0..count).try_fold(HashMap::with_capacity(count), |mut values, _| {
let key = reader.read_value::<K>()?;
let value = reader.read_value::<V>()?;
if values.insert(key, value).is_some() {
return Err(DecodeError::InvalidValue(InvalidWireValue::DuplicateMapKey));
}
Ok::<_, DecodeError>(values)
})?;
reader.finish(values)
}
}
impl<K, V> WireDecode for BTreeMap<K, V>
where
K: Ord + WireDecode,
V: WireDecode,
{
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
let count = reader.read_value::<u32>()? as usize;
let values = (0..count).try_fold(BTreeMap::new(), |mut values, _| {
let key = reader.read_value::<K>()?;
let value = reader.read_value::<V>()?;
if values.insert(key, value).is_some() {
return Err(DecodeError::InvalidValue(InvalidWireValue::DuplicateMapKey));
}
Ok::<_, DecodeError>(values)
})?;
reader.finish(values)
}
}
macro_rules! impl_wire_tuple_decode {
($($name:ident),+ $(,)?) => {
impl<$($name: WireDecode),+> WireDecode for ($($name,)+) {
fn decode_from(buf: &[u8]) -> DecodeResult<Self> {
let mut reader = WireReader::new(buf);
let value = ($(
reader.read_value::<$name>()?,
)+);
reader.finish(value)
}
}
};
}
impl_wire_tuple_decode!(A);
impl_wire_tuple_decode!(A, B);
impl_wire_tuple_decode!(A, B, C);
impl_wire_tuple_decode!(A, B, C, D);
impl_wire_tuple_decode!(A, B, C, D, E);
impl_wire_tuple_decode!(A, B, C, D, E, F);
impl_wire_tuple_decode!(A, B, C, D, E, F, G);
impl_wire_tuple_decode!(A, B, C, D, E, F, G, H);
impl_wire_tuple_decode!(A, B, C, D, E, F, G, H, I);
impl_wire_tuple_decode!(A, B, C, D, E, F, G, H, I, J);
impl_wire_tuple_decode!(A, B, C, D, E, F, G, H, I, J, K);
impl_wire_tuple_decode!(A, B, C, D, E, F, G, H, I, J, K, L);
#[cfg(test)]
mod tests {
use super::*;
use crate::wire::encode::WireEncode;
#[test]
fn decode_primitives() {
let mut buf = [0u8; 8];
42i32.encode_to(&mut buf);
let (value, size) = i32::decode_from(&buf).unwrap();
assert_eq!(value, 42);
assert_eq!(size, 4);
3.5f64.encode_to(&mut buf);
let (value, size) = f64::decode_from(&buf).unwrap();
assert!((value - 3.5).abs() < f64::EPSILON);
assert_eq!(size, 8);
true.encode_to(&mut buf);
let (value, size) = bool::decode_from(&buf).unwrap();
assert!(value);
assert_eq!(size, 1);
}
#[test]
fn decode_string() {
let mut buf = [0u8; 32];
let original = "hello".to_string();
original.encode_to(&mut buf);
let (decoded, size) = String::decode_from(&buf).unwrap();
assert_eq!(decoded, "hello");
assert_eq!(size, 9);
}
#[test]
fn decode_option() {
let mut buf = [0u8; 16];
Some(42i32).encode_to(&mut buf);
let (decoded, size) = Option::<i32>::decode_from(&buf).unwrap();
assert_eq!(decoded, Some(42));
assert_eq!(size, 5);
None::<i32>.encode_to(&mut buf);
let (decoded, size) = Option::<i32>::decode_from(&buf).unwrap();
assert_eq!(decoded, None);
assert_eq!(size, 1);
}
#[test]
fn decode_vec_fixed() {
let mut buf = [0u8; 32];
let original = vec![1i32, 2, 3];
original.encode_to(&mut buf);
let (decoded, size) = Vec::<i32>::decode_from(&buf).unwrap();
assert_eq!(decoded, vec![1, 2, 3]);
assert_eq!(size, 16);
}
#[test]
fn decode_vec_variable() {
let mut buf = [0u8; 64];
let original = vec!["hi".to_string(), "there".to_string()];
let written = original.encode_to(&mut buf);
let (decoded, size) = Vec::<String>::decode_from(&buf).unwrap();
assert_eq!(decoded, vec!["hi".to_string(), "there".to_string()]);
assert_eq!(size, written);
}
#[test]
fn decode_tuple() {
let mut buf = [0u8; 64];
let original = (7u32, "seven".to_string());
let written = original.encode_to(&mut buf);
let (decoded, size) = <(u32, String)>::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
assert_eq!(size, written);
}
#[test]
fn decode_hash_map() {
let mut buf = [0u8; 128];
let original = HashMap::from([(String::from("one"), 1u32), (String::from("two"), 2u32)]);
let written = original.encode_to(&mut buf);
let (decoded, size) = HashMap::<String, u32>::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
assert_eq!(size, written);
}
#[test]
fn decode_btree_map() {
let mut buf = [0u8; 128];
let original = BTreeMap::from([(String::from("one"), 1u32), (String::from("two"), 2u32)]);
let written = original.encode_to(&mut buf);
let (decoded, size) = BTreeMap::<String, u32>::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
assert_eq!(size, written);
}
#[test]
fn decode_hash_map_rejects_duplicate_keys() {
let mut buffer = [0u8; 128];
let size = duplicate_key_map_buffer(&mut buffer);
let error =
HashMap::<String, u32>::decode_from(&buffer[..size]).expect_err("duplicate key");
assert_eq!(
error,
DecodeError::InvalidValue(InvalidWireValue::DuplicateMapKey)
);
}
#[test]
fn decode_btree_map_rejects_duplicate_keys() {
let mut buffer = [0u8; 128];
let size = duplicate_key_map_buffer(&mut buffer);
let error =
BTreeMap::<String, u32>::decode_from(&buffer[..size]).expect_err("duplicate key");
assert_eq!(
error,
DecodeError::InvalidValue(InvalidWireValue::DuplicateMapKey)
);
}
#[test]
fn roundtrip_complex() {
let mut buf = [0u8; 128];
let original: Vec<Option<String>> =
vec![Some("hello".to_string()), None, Some("world".to_string())];
let written = original.encode_to(&mut buf);
let (decoded, size) = Vec::<Option<String>>::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
assert_eq!(size, written);
}
fn duplicate_key_map_buffer(buffer: &mut [u8]) -> usize {
let mut offset = 0;
buffer[..4].copy_from_slice(&2u32.to_le_bytes());
offset += 4;
offset += String::from("one").encode_to(&mut buffer[offset..]);
offset += 1u32.encode_to(&mut buffer[offset..]);
offset += String::from("one").encode_to(&mut buffer[offset..]);
offset += 2u32.encode_to(&mut buffer[offset..]);
offset
}
mod unit_type {
use super::*;
#[test]
fn unit_decode_from_empty_buffer() {
let buf: [u8; 0] = [];
let (value, consumed) = <()>::decode_from(&buf).unwrap();
assert_eq!(value, ());
assert_eq!(consumed, 0);
}
#[test]
fn unit_decode_from_nonempty_buffer() {
let buf = [0xFF; 8];
let (value, consumed) = <()>::decode_from(&buf).unwrap();
assert_eq!(value, ());
assert_eq!(consumed, 0);
}
#[test]
fn unit_roundtrip() {
let original = ();
let mut buf = [0u8; 4];
let written = original.encode_to(&mut buf);
assert_eq!(written, 0);
let (_decoded, consumed) = <()>::decode_from(&buf).unwrap();
assert_eq!(consumed, 0);
}
#[test]
fn result_ok_unit_roundtrip() {
let original: Result<(), i32> = Ok(());
let mut buf = [0u8; 16];
let written = original.encode_to(&mut buf);
let (decoded, consumed) = Result::<(), i32>::decode_from(&buf).unwrap();
assert_eq!(decoded, Ok(()));
assert_eq!(consumed, written);
}
#[test]
fn result_err_with_unit_ok_roundtrip() {
let original: Result<(), i32> = Err(99);
let mut buf = [0u8; 16];
let written = original.encode_to(&mut buf);
let (decoded, consumed) = Result::<(), i32>::decode_from(&buf).unwrap();
assert_eq!(decoded, Err(99));
assert_eq!(consumed, written);
}
#[test]
fn option_some_unit_roundtrip() {
let original: Option<()> = Some(());
let mut buf = [0u8; 4];
let written = original.encode_to(&mut buf);
let (decoded, consumed) = Option::<()>::decode_from(&buf).unwrap();
assert_eq!(decoded, Some(()));
assert_eq!(consumed, written);
}
}
mod box_type {
use super::*;
#[test]
fn box_i32_roundtrip() {
let original = Box::new(42i32);
let mut buf = [0u8; 4];
original.encode_to(&mut buf);
let (decoded, consumed) = Box::<i32>::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
assert_eq!(consumed, 4);
}
#[test]
fn box_string_roundtrip() {
let original = Box::new("hello".to_string());
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, consumed) = Box::<String>::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
assert_eq!(consumed, 9);
}
#[test]
fn box_decode_matches_bare_decode() {
let mut buf = [0u8; 4];
42i32.encode_to(&mut buf);
let (bare, bare_consumed) = i32::decode_from(&buf).unwrap();
let (boxed, box_consumed) = Box::<i32>::decode_from(&buf).unwrap();
assert_eq!(*boxed, bare);
assert_eq!(box_consumed, bare_consumed);
}
#[test]
fn box_vec_roundtrip() {
let original = Box::new(vec![1i32, 2, 3]);
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, consumed) = Box::<Vec<i32>>::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
assert_eq!(consumed, 16);
}
#[test]
fn nested_box_roundtrip() {
let original = Box::new(Box::new(42i32));
let mut buf = [0u8; 4];
original.encode_to(&mut buf);
let (decoded, consumed) = Box::<Box<i32>>::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
assert_eq!(consumed, 4);
}
#[test]
fn option_box_roundtrip() {
let original: Option<Box<i32>> = Some(Box::new(99));
let mut buf = [0u8; 16];
let written = original.encode_to(&mut buf);
let (decoded, consumed) = Option::<Box<i32>>::decode_from(&buf).unwrap();
assert_eq!(decoded, Some(Box::new(99)));
assert_eq!(consumed, written);
}
}
mod large_payload_roundtrip {
use super::*;
#[test]
fn string_1mb_roundtrip() {
let original: String = "x".repeat(1024 * 1024);
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = String::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn string_10mb_roundtrip() {
let original: String = "y".repeat(10 * 1024 * 1024);
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = String::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn vec_100k_i32_roundtrip() {
let original: Vec<i32> = (0..100_000).collect();
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = Vec::<i32>::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn vec_1m_i32_roundtrip() {
let original: Vec<i32> = (0..1_000_000).collect();
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = Vec::<i32>::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn vec_10k_strings_roundtrip() {
let original: Vec<String> = (0..10_000).map(|i| format!("item_{}", i)).collect();
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = Vec::<String>::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn nested_vecs_roundtrip() {
let original: Vec<Vec<i32>> = (0..100).map(|_| (0..1000).collect()).collect();
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = Vec::<Vec<i32>>::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
}
mod unicode_roundtrip {
use super::*;
#[test]
fn emoji_roundtrip() {
let original = "Hello 👋 World 🌍 🎉".to_string();
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = String::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn cjk_roundtrip() {
let original = "你好世界 こんにちは 안녕하세요".to_string();
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = String::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn arabic_roundtrip() {
let original = "مرحبا بالعالم".to_string();
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = String::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn mixed_scripts_roundtrip() {
let original = "Hello 你好 مرحبا Привет 🎉".to_string();
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = String::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn combining_characters_roundtrip() {
let original = "café naïve résumé".to_string();
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = String::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn zero_width_joiner_emoji_roundtrip() {
let original = "👨👩👧👦 👨💻 🏳️🌈".to_string();
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = String::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn empty_string_roundtrip() {
let original = String::new();
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = String::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn null_byte_roundtrip() {
let original = "hello\0world\0test".to_string();
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = String::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn whitespace_variants_roundtrip() {
let original = "tab\there\nnewline\rcarriage\u{00A0}nbsp".to_string();
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = String::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
#[test]
fn vec_of_unicode_strings_roundtrip() {
let original: Vec<String> = vec![
"Hello".to_string(),
"你好".to_string(),
"مرحبا".to_string(),
"👋🌍".to_string(),
];
let mut buf = vec![0u8; original.wire_size()];
original.encode_to(&mut buf);
let (decoded, _) = Vec::<String>::decode_from(&buf).unwrap();
assert_eq!(decoded, original);
}
}
mod decode_errors {
use super::*;
#[test]
fn string_buffer_too_small_for_length() {
let buf = [0u8; 2];
let result = String::decode_from(&buf);
assert!(matches!(result, Err(DecodeError::BufferTooSmall)));
}
#[test]
fn string_buffer_too_small_for_content() {
let mut buf = [0u8; 8];
buf[..4].copy_from_slice(&100u32.to_le_bytes());
let result = String::decode_from(&buf);
assert!(matches!(result, Err(DecodeError::BufferTooSmall)));
}
#[test]
fn vec_buffer_too_small_for_count() {
let buf = [0u8; 2];
let result = Vec::<i32>::decode_from(&buf);
assert!(matches!(result, Err(DecodeError::BufferTooSmall)));
}
#[test]
fn vec_buffer_too_small_for_elements() {
let mut buf = [0u8; 8];
buf[..4].copy_from_slice(&100u32.to_le_bytes());
let result = Vec::<i32>::decode_from(&buf);
assert!(matches!(result, Err(DecodeError::BufferTooSmall)));
}
#[test]
fn empty_buffer() {
let buf: [u8; 0] = [];
assert!(matches!(
String::decode_from(&buf),
Err(DecodeError::BufferTooSmall)
));
assert!(matches!(
Vec::<i32>::decode_from(&buf),
Err(DecodeError::BufferTooSmall)
));
assert!(matches!(
i32::decode_from(&buf),
Err(DecodeError::BufferTooSmall)
));
}
}
}