#![warn(missing_docs)]
#![deny(
unsafe_code,
trivial_casts,
trivial_numeric_casts,
unused_import_braces,
unused_qualifications
)]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(not(feature = "std"))]
extern crate alloc;
pub mod error;
pub use error::Error;
pub mod enc_into;
pub use enc_into::EncodeInto;
pub mod enc_into_buffer;
pub use enc_into_buffer::EncodeIntoBuffer;
pub mod enc_into_array;
pub use enc_into_array::EncodeIntoArray;
pub mod null;
pub use null::{Null, TryNull};
pub mod try_decode_from;
pub use try_decode_from::TryDecodeFrom;
pub mod encoded_bytes;
pub use encoded_bytes::EncodedBytes;
pub mod prelude {
pub use super::{
enc_into::*, enc_into_array::*, enc_into_buffer::*, encoded_bytes::*, null::*,
try_decode_from::*,
};
}
#[cfg(test)]
mod test {
#![allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::items_after_statements,
clippy::significant_drop_tightening,
clippy::needless_collect
)]
use super::prelude::*;
#[test]
fn test_bool() {
let tbuf = true.encode_into();
let (tval, _) = bool::try_decode_from(&tbuf).unwrap();
assert!(tval);
let fbuf = false.encode_into();
let (fval, _) = bool::try_decode_from(&fbuf).unwrap();
assert!(!fval);
}
#[test]
fn test_u8() {
let buf = 0xff_u8.encode_into();
let (num, _) = u8::try_decode_from(&buf).unwrap();
assert_eq!(0xff_u8, num);
}
#[test]
fn test_u16() {
let buf = 0xffee_u16.encode_into();
let (num, _) = u16::try_decode_from(&buf).unwrap();
assert_eq!(0xffee_u16, num);
}
#[test]
fn test_u32() {
let buf = 0xffee_ddcc_u32.encode_into();
let (num, _) = u32::try_decode_from(&buf).unwrap();
assert_eq!(0xffee_ddcc_u32, num);
}
#[test]
fn test_u64() {
let buf = 0xffee_ddcc_bbaa_9988_u64.encode_into();
let (num, _) = u64::try_decode_from(&buf).unwrap();
assert_eq!(0xffee_ddcc_bbaa_9988_u64, num);
}
#[test]
fn test_u128() {
let buf = 0xffee_ddcc_bbaa_9988_7766_5544_3322_1100_u128.encode_into();
let (num, _) = u128::try_decode_from(&buf).unwrap();
assert_eq!(0xffee_ddcc_bbaa_9988_7766_5544_3322_1100_u128, num);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_usize() {
let buf = 0xffee_ddcc_bbaa_9988_usize.encode_into();
let (num, _) = usize::try_decode_from(&buf).unwrap();
assert_eq!(0xffee_ddcc_bbaa_9988_usize, num);
}
#[cfg(target_pointer_width = "32")]
#[test]
fn test_usize() {
let buf = 0xffeeddcc_usize.encode_into();
let (num, _) = usize::try_decode_from(&buf).unwrap();
assert_eq!(0xffeeddcc_usize, num);
}
struct Foo(usize);
impl Null for Foo {
fn null() -> Self {
Self(0)
}
fn is_null(&self) -> bool {
self.0 == 0
}
}
impl TryNull for Foo {
type Error = &'static str;
fn try_null() -> Result<Self, Self::Error> {
Ok(Self(0))
}
fn is_null(&self) -> bool {
self.0 == 0
}
}
#[test]
fn test_null_value() {
let f = Foo::null();
assert!(Null::is_null(&f));
}
#[test]
fn test_try_null_value() {
let f = Foo::try_null().unwrap();
assert!(TryNull::is_null(&f));
}
#[test]
fn test_decode_empty_slice_u8() {
let empty: &[u8] = &[];
let result = u8::try_decode_from(empty);
assert!(result.is_err(), "Should fail to decode from empty slice");
}
#[test]
fn test_decode_empty_slice_u16() {
let empty: &[u8] = &[];
let result = u16::try_decode_from(empty);
assert!(result.is_err(), "Should fail to decode from empty slice");
}
#[test]
fn test_decode_empty_slice_u32() {
let empty: &[u8] = &[];
let result = u32::try_decode_from(empty);
assert!(result.is_err(), "Should fail to decode from empty slice");
}
#[test]
fn test_decode_empty_slice_u64() {
let empty: &[u8] = &[];
let result = u64::try_decode_from(empty);
assert!(result.is_err(), "Should fail to decode from empty slice");
}
#[test]
fn test_decode_empty_slice_u128() {
let empty: &[u8] = &[];
let result = u128::try_decode_from(empty);
assert!(result.is_err(), "Should fail to decode from empty slice");
}
#[test]
fn test_decode_empty_slice_bool() {
let empty: &[u8] = &[];
let result = bool::try_decode_from(empty);
assert!(result.is_err(), "Should fail to decode from empty slice");
}
#[test]
fn test_decode_truncated_varint() {
let truncated = vec![0x80]; let result = u16::try_decode_from(&truncated);
assert!(result.is_err(), "Should fail on truncated varint");
}
#[test]
fn test_decode_truncated_large_varint() {
let truncated = vec![0xFF, 0xFF]; let result = u32::try_decode_from(&truncated);
assert!(result.is_err(), "Should fail on truncated large varint");
}
#[test]
fn test_encode_decode_zero_values() {
assert_eq!(0u8.encode_into(), vec![0]);
assert_eq!(0u16.encode_into(), vec![0]);
assert_eq!(0u32.encode_into(), vec![0]);
assert_eq!(0u64.encode_into(), vec![0]);
assert_eq!(0u128.encode_into(), vec![0]);
assert_eq!(0usize.encode_into(), vec![0]);
let (val, rest) = u8::try_decode_from(&[0]).unwrap();
assert_eq!(val, 0);
assert!(rest.is_empty());
}
#[test]
fn test_encode_decode_max_u8() {
let max = u8::MAX;
let encoded = max.encode_into();
let (decoded, remaining) = u8::try_decode_from(&encoded).unwrap();
assert_eq!(decoded, max);
assert!(remaining.is_empty());
}
#[test]
fn test_encode_decode_max_u16() {
let max = u16::MAX;
let encoded = max.encode_into();
let (decoded, remaining) = u16::try_decode_from(&encoded).unwrap();
assert_eq!(decoded, max);
assert!(remaining.is_empty());
}
#[test]
fn test_encode_decode_max_u32() {
let max = u32::MAX;
let encoded = max.encode_into();
let (decoded, remaining) = u32::try_decode_from(&encoded).unwrap();
assert_eq!(decoded, max);
assert!(remaining.is_empty());
}
#[test]
fn test_encode_decode_max_u64() {
let max = u64::MAX;
let encoded = max.encode_into();
let (decoded, remaining) = u64::try_decode_from(&encoded).unwrap();
assert_eq!(decoded, max);
assert!(remaining.is_empty());
}
#[test]
fn test_encode_decode_max_u128() {
let max = u128::MAX;
let encoded = max.encode_into();
let (decoded, remaining) = u128::try_decode_from(&encoded).unwrap();
assert_eq!(decoded, max);
assert!(remaining.is_empty());
}
#[test]
fn test_varint_boundary_127() {
let val = 127u8;
let encoded = val.encode_into();
assert_eq!(encoded.len(), 1);
let (decoded, _) = u8::try_decode_from(&encoded).unwrap();
assert_eq!(decoded, val);
}
#[test]
fn test_varint_boundary_128() {
let val = 128u8;
let encoded = val.encode_into();
assert_eq!(encoded.len(), 2);
let (decoded, _) = u8::try_decode_from(&encoded).unwrap();
assert_eq!(decoded, val);
}
#[test]
fn test_bool_nonzero_as_true() {
let bytes = vec![42];
let (val, _) = bool::try_decode_from(&bytes).unwrap();
assert!(val);
}
#[test]
fn test_roundtrip_u8_range() {
for value in [0, 1, 127, 128, 255] {
let encoded = value.encode_into();
let (decoded, remaining) = u8::try_decode_from(&encoded).unwrap();
assert_eq!(decoded, value, "Round-trip failed for u8 value {value}");
assert!(remaining.is_empty());
}
}
#[test]
fn test_roundtrip_u16_range() {
for value in [0, 1, 127, 128, 255, 256, 16383, 16384, 65535] {
let encoded = value.encode_into();
let (decoded, remaining) = u16::try_decode_from(&encoded).unwrap();
assert_eq!(decoded, value, "Round-trip failed for u16 value {value}");
assert!(remaining.is_empty());
}
}
#[test]
fn test_roundtrip_u32_range() {
for value in [0, 1, 127, 128, 16384, 65536, u32::MAX] {
let encoded = value.encode_into();
let (decoded, remaining) = u32::try_decode_from(&encoded).unwrap();
assert_eq!(decoded, value, "Round-trip failed for u32 value {value}");
assert!(remaining.is_empty());
}
}
#[test]
fn test_roundtrip_u64_range() {
for value in [0, 1, 127, 128, 65536, u64::from(u32::MAX), u64::MAX] {
let encoded = value.encode_into();
let (decoded, remaining) = u64::try_decode_from(&encoded).unwrap();
assert_eq!(decoded, value, "Round-trip failed for u64 value {value}");
assert!(remaining.is_empty());
}
}
#[test]
fn test_roundtrip_bool() {
for value in [true, false] {
let encoded = value.encode_into();
let (decoded, remaining) = bool::try_decode_from(&encoded).unwrap();
assert_eq!(decoded, value, "Round-trip failed for bool {value}");
assert!(remaining.is_empty());
}
}
#[test]
fn test_sequential_decode() {
let mut buffer = Vec::new();
buffer.extend_from_slice(&42u8.encode_into());
buffer.extend_from_slice(&1000u16.encode_into());
buffer.extend_from_slice(&100_000_u32.encode_into());
let (val1, rest) = u8::try_decode_from(&buffer).unwrap();
assert_eq!(val1, 42);
let (val2, rest) = u16::try_decode_from(rest).unwrap();
assert_eq!(val2, 1000);
let (val3, rest) = u32::try_decode_from(rest).unwrap();
assert_eq!(val3, 100_000);
assert!(rest.is_empty(), "Should have consumed all bytes");
}
#[test]
fn test_remaining_bytes_returned() {
let mut buffer = Vec::new();
buffer.extend_from_slice(&42u8.encode_into());
buffer.extend_from_slice(&[0xFF, 0xEE, 0xDD]);
let (val, remaining) = u8::try_decode_from(&buffer).unwrap();
assert_eq!(val, 42);
assert_eq!(remaining, &[0xFF, 0xEE, 0xDD]);
}
#[test]
fn test_encode_length_efficiency() {
assert_eq!(0u8.encode_into().len(), 1);
assert_eq!(127u8.encode_into().len(), 1);
assert_eq!(128u8.encode_into().len(), 2);
assert_eq!(255u8.encode_into().len(), 2);
assert!(u16::MAX.encode_into().len() > 1);
assert!(u32::MAX.encode_into().len() > 2);
}
use proptest::prelude::*;
proptest! {
#[test]
fn prop_roundtrip_u8(value: u8) {
let encoded = value.encode_into();
let (decoded, remaining) = u8::try_decode_from(&encoded).unwrap();
prop_assert_eq!(decoded, value);
prop_assert!(remaining.is_empty());
}
#[test]
fn prop_roundtrip_u16(value: u16) {
let encoded = value.encode_into();
let (decoded, remaining) = u16::try_decode_from(&encoded).unwrap();
prop_assert_eq!(decoded, value);
prop_assert!(remaining.is_empty());
}
#[test]
fn prop_roundtrip_u32(value: u32) {
let encoded = value.encode_into();
let (decoded, remaining) = u32::try_decode_from(&encoded).unwrap();
prop_assert_eq!(decoded, value);
prop_assert!(remaining.is_empty());
}
#[test]
fn prop_roundtrip_u64(value: u64) {
let encoded = value.encode_into();
let (decoded, remaining) = u64::try_decode_from(&encoded).unwrap();
prop_assert_eq!(decoded, value);
prop_assert!(remaining.is_empty());
}
#[test]
fn prop_roundtrip_u128(value: u128) {
let encoded = value.encode_into();
let (decoded, remaining) = u128::try_decode_from(&encoded).unwrap();
prop_assert_eq!(decoded, value);
prop_assert!(remaining.is_empty());
}
#[test]
fn prop_roundtrip_usize(value: usize) {
let encoded = value.encode_into();
let (decoded, remaining) = usize::try_decode_from(&encoded).unwrap();
prop_assert_eq!(decoded, value);
prop_assert!(remaining.is_empty());
}
#[test]
fn prop_roundtrip_bool(value: bool) {
let encoded = value.encode_into();
let (decoded, remaining) = bool::try_decode_from(&encoded).unwrap();
prop_assert_eq!(decoded, value);
prop_assert!(remaining.is_empty());
}
#[test]
fn prop_encode_not_empty(value: u32) {
let encoded = value.encode_into();
prop_assert!(!encoded.is_empty());
}
#[test]
fn prop_encode_deterministic(value: u64) {
let encoded1 = value.encode_into();
let encoded2 = value.encode_into();
prop_assert_eq!(encoded1, encoded2);
}
#[test]
fn prop_small_values_compact(value in 0u32..128) {
let encoded = value.encode_into();
prop_assert_eq!(encoded.len(), 1, "Values under 128 should encode in 1 byte");
}
#[test]
fn prop_sequential_decode(v1: u8, v2: u16, v3: u32) {
let mut buffer = Vec::new();
buffer.extend_from_slice(&v1.encode_into());
buffer.extend_from_slice(&v2.encode_into());
buffer.extend_from_slice(&v3.encode_into());
let (d1, rest) = u8::try_decode_from(&buffer).unwrap();
prop_assert_eq!(d1, v1);
let (d2, rest) = u16::try_decode_from(rest).unwrap();
prop_assert_eq!(d2, v2);
let (d3, rest) = u32::try_decode_from(rest).unwrap();
prop_assert_eq!(d3, v3);
prop_assert!(rest.is_empty());
}
}
#[test]
fn assert_error_send_sync() {
fn is_send<T: Send>() {}
fn is_sync<T: Sync>() {}
is_send::<crate::Error>();
is_sync::<crate::Error>();
}
#[test]
fn assert_encoded_bytes_send_sync() {
fn is_send<T: Send>() {}
fn is_sync<T: Sync>() {}
is_send::<EncodedBytes>();
is_sync::<EncodedBytes>();
}
#[test]
fn test_encoded_bytes_valid() {
let bytes = vec![42];
let encoded = EncodedBytes::try_from(bytes).unwrap();
assert_eq!(encoded.as_ref(), &[42]);
}
#[test]
fn test_encoded_bytes_invalid_empty() {
let empty: Vec<u8> = vec![];
assert!(EncodedBytes::try_from(empty).is_err());
}
#[test]
fn test_encoded_bytes_invalid_truncated() {
let truncated = vec![0x80];
assert!(EncodedBytes::try_from(truncated).is_err());
}
#[test]
fn test_encoded_bytes_into_vec() {
let original = 128u8.encode_into();
let encoded = EncodedBytes::new(&original).unwrap();
let recovered: Vec<u8> = encoded.into();
assert_eq!(recovered, original);
}
#[cfg(feature = "std")]
#[test]
fn test_encoded_bytes_thread_safe() {
use std::sync::Arc;
use std::thread;
let encoded = EncodedBytes::new(&[42]).unwrap();
let shared = Arc::new(encoded);
let handles: Vec<_> = (0..4)
.map(|_| {
let data = Arc::clone(&shared);
thread::spawn(move || {
assert_eq!(&data[..], &[42]);
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
}
#[test]
fn security_test_all_continuation_bits() {
let malicious = vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
let result = u64::try_decode_from(&malicious);
assert!(
result.is_err(),
"Should reject all-continuation-bit sequence"
);
}
#[test]
fn security_test_maximum_length_varint_u64() {
let max_encoded = u64::MAX.encode_into();
assert_eq!(max_encoded.len(), 10);
let (decoded, remaining) = u64::try_decode_from(&max_encoded).unwrap();
assert_eq!(decoded, u64::MAX);
assert!(remaining.is_empty());
}
#[test]
fn security_test_maximum_length_varint_u128() {
let max_encoded = u128::MAX.encode_into();
assert_eq!(max_encoded.len(), 19);
let (decoded, remaining) = u128::try_decode_from(&max_encoded).unwrap();
assert_eq!(decoded, u128::MAX);
assert!(remaining.is_empty());
}
#[test]
fn security_test_single_byte_with_continuation() {
let malicious = vec![0x80];
assert!(u8::try_decode_from(&malicious).is_err());
assert!(u16::try_decode_from(&malicious).is_err());
assert!(u32::try_decode_from(&malicious).is_err());
assert!(u64::try_decode_from(&malicious).is_err());
}
#[test]
fn security_test_multiple_continuation_bytes_truncated() {
let malicious = vec![0xFF, 0xFF, 0xFF];
assert!(u32::try_decode_from(&malicious).is_err());
}
#[test]
fn security_test_encoded_bytes_rejects_invalid() {
assert!(EncodedBytes::try_from(vec![]).is_err());
assert!(EncodedBytes::try_from(vec![0x80]).is_err());
let mut with_trailing = vec![42];
with_trailing.extend_from_slice(&[0xFF, 0xEE]);
assert!(EncodedBytes::try_from(with_trailing).is_err());
assert!(EncodedBytes::try_from(vec![0xFF, 0xFF, 0xFF]).is_err());
}
#[test]
fn security_test_buffer_encoding_no_overflow() {
let mut buffer = Vec::new();
for i in 0u16..1000 {
i.encode_into_buffer(&mut buffer);
}
assert!(buffer.len() > 1000); assert!(buffer.len() < 3000); }
#[test]
fn security_test_array_encoding_bounds() {
let (array, len) = u128::MAX.encode_into_array();
assert!(len <= 19, "u128::MAX should not exceed 19 bytes");
let (decoded, _) = u128::try_decode_from(&array[..len]).unwrap();
assert_eq!(decoded, u128::MAX);
}
#[test]
fn security_test_bool_decode_nonzero_values() {
let nonzero_values = vec![
vec![1], vec![42], vec![127], vec![0xFF, 0x01], ];
for bytes in nonzero_values {
let (val, _) = bool::try_decode_from(&bytes).unwrap();
assert!(val, "Non-zero value {bytes:?} should decode as true");
}
let (val, _) = bool::try_decode_from(&[0]).unwrap();
assert!(!val);
}
#[test]
fn security_test_zero_length_slice_rejection() {
let empty: &[u8] = &[];
assert!(u8::try_decode_from(empty).is_err());
assert!(u16::try_decode_from(empty).is_err());
assert!(u32::try_decode_from(empty).is_err());
assert!(u64::try_decode_from(empty).is_err());
assert!(u128::try_decode_from(empty).is_err());
assert!(usize::try_decode_from(empty).is_err());
assert!(bool::try_decode_from(empty).is_err());
}
#[test]
fn security_test_repeated_decoding_no_panic() {
let malicious = vec![0xFF, 0xFF];
for _ in 0..100 {
let _ = u32::try_decode_from(&malicious);
let _ = u64::try_decode_from(&malicious);
}
}
#[test]
fn security_test_alternating_bit_patterns() {
let patterns = vec![
vec![0xAA], vec![0x55], vec![0xAA, 0x55],
vec![0x55, 0xAA],
];
for pattern in patterns {
let _ = u8::try_decode_from(&pattern);
let _ = u16::try_decode_from(&pattern);
}
}
proptest! {
#[test]
fn security_prop_decode_random_bytes(bytes in prop::collection::vec(any::<u8>(), 0..50)) {
let _ = u8::try_decode_from(&bytes);
let _ = u16::try_decode_from(&bytes);
let _ = u32::try_decode_from(&bytes);
let _ = u64::try_decode_from(&bytes);
let _ = u128::try_decode_from(&bytes);
}
#[test]
fn security_prop_encoded_bytes_validation(bytes in prop::collection::vec(any::<u8>(), 0..100)) {
let result = EncodedBytes::try_from(bytes);
if let Ok(encoded) = result {
let decode_result = u128::try_decode_from(encoded.as_ref());
prop_assert!(decode_result.is_ok(), "Validated EncodedBytes should be decodable");
}
}
#[test]
fn security_prop_buffer_encoding_no_panic(values in prop::collection::vec(any::<u32>(), 0..1000)) {
let mut buffer = Vec::new();
for value in values {
value.encode_into_buffer(&mut buffer);
}
prop_assert!(buffer.len() < 5000, "Buffer should not grow excessively");
}
#[test]
fn security_prop_array_encoding_never_panics(value: u128) {
let (_array, len) = value.encode_into_array();
prop_assert!(len > 0);
prop_assert!(len <= 19);
let (array, len) = value.encode_into_array();
let (decoded, _) = u128::try_decode_from(&array[..len]).unwrap();
prop_assert_eq!(decoded, value);
}
#[test]
fn security_prop_decode_never_returns_more_than_input(
bytes in prop::collection::vec(any::<u8>(), 1..100)
) {
if let Ok((_, remaining)) = u64::try_decode_from(&bytes) {
prop_assert!(remaining.len() <= bytes.len());
}
}
#[test]
fn security_prop_encode_size_bounded(value: u64) {
let encoded = value.encode_into();
prop_assert!(encoded.len() <= 10, "u64 varint should not exceed 10 bytes");
let (_array, len) = value.encode_into_array();
prop_assert!(len <= 10, "u64 array encoding should not exceed 10 bytes");
}
}
#[test]
fn assert_primitives_send_sync() {
fn is_send<T: Send>() {}
fn is_sync<T: Sync>() {}
is_send::<u8>();
is_sync::<u8>();
is_send::<u16>();
is_sync::<u16>();
is_send::<u32>();
is_sync::<u32>();
is_send::<u64>();
is_sync::<u64>();
is_send::<u128>();
is_sync::<u128>();
is_send::<usize>();
is_sync::<usize>();
is_send::<bool>();
is_sync::<bool>();
is_send::<Vec<u8>>();
is_sync::<Vec<u8>>();
}
#[test]
fn assert_encoded_types_send_sync() {
fn is_send<T: Send>() {}
fn is_sync<T: Sync>() {}
is_send::<EncodedBytes>();
is_sync::<EncodedBytes>();
is_send::<crate::Error>();
is_sync::<crate::Error>();
}
#[cfg(feature = "std")]
#[test]
fn concurrency_test_parallel_encode_into() {
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
let results = Arc::new(Mutex::new(Vec::new()));
let handles: Vec<_> = (0..10)
.map(|i| {
let results = Arc::clone(&results);
thread::spawn(move || {
let value = i as u32 * 100;
let encoded = value.encode_into();
results.lock().unwrap().push((value, encoded));
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
let results = results.lock().unwrap();
assert_eq!(results.len(), 10);
for (original, encoded) in results.iter() {
let (decoded, _) = u32::try_decode_from(encoded).unwrap();
assert_eq!(*original, decoded);
}
}
#[cfg(feature = "std")]
#[test]
fn concurrency_test_parallel_encode_into_buffer() {
use std::thread;
let handles: Vec<_> = (0..10)
.map(|i| {
thread::spawn(move || {
let mut buffer = Vec::new();
for j in 0u16..100 {
(i * 100 + j).encode_into_buffer(&mut buffer);
}
buffer
})
})
.collect();
for handle in handles {
let buffer = handle.join().unwrap();
assert!(buffer.len() >= 100); assert!(buffer.len() < 300); }
}
#[cfg(feature = "std")]
#[test]
fn concurrency_test_parallel_encode_into_array() {
use std::thread;
let handles: Vec<_> = (0..10)
.map(|i| {
thread::spawn(move || {
let value = i as u64 * 1000;
let (array, len) = value.encode_into_array();
(value, array, len)
})
})
.collect();
for handle in handles {
let (original, array, len) = handle.join().unwrap();
let (decoded, _) = u64::try_decode_from(&array[..len]).unwrap();
assert_eq!(original, decoded);
}
}
#[cfg(feature = "std")]
#[test]
fn concurrency_test_shared_decode_data() {
use std::sync::Arc;
use std::thread;
let mut data = Vec::new();
for i in 0u32..100 {
data.extend_from_slice(&i.encode_into());
}
let shared_data = Arc::new(data);
let handles: Vec<_> = (0..4)
.map(|_| {
let data = Arc::clone(&shared_data);
thread::spawn(move || {
let mut slice = &data[..];
let mut count = 0;
while !slice.is_empty() {
match u32::try_decode_from(slice) {
Ok((_, remaining)) => {
count += 1;
slice = remaining;
}
Err(_) => break,
}
}
count
})
})
.collect();
for handle in handles {
let count = handle.join().unwrap();
assert_eq!(count, 100, "All threads should decode 100 values");
}
}
#[cfg(feature = "std")]
#[test]
fn concurrency_test_parallel_decode_different_data() {
use std::thread;
let handles: Vec<_> = (0..10)
.map(|i| {
thread::spawn(move || {
let mut data = Vec::new();
for j in 0u16..50 {
(i * 50 + j).encode_into_buffer(&mut data);
}
let mut slice = &data[..];
let mut decoded_values = Vec::new();
while !slice.is_empty() {
match u16::try_decode_from(slice) {
Ok((value, remaining)) => {
decoded_values.push(value);
slice = remaining;
}
Err(_) => break,
}
}
decoded_values
})
})
.collect();
for (i, handle) in handles.into_iter().enumerate() {
let values = handle.join().unwrap();
assert_eq!(values.len(), 50);
assert_eq!(values[0], i as u16 * 50);
assert_eq!(values[49], i as u16 * 50 + 49);
}
}
#[cfg(feature = "std")]
#[test]
fn concurrency_test_pipeline_encode_decode() {
use std::sync::mpsc;
use std::thread;
let (tx, rx) = mpsc::channel();
let encoder = thread::spawn(move || {
for i in 0u32..1000 {
tx.send(i.encode_into()).unwrap();
}
});
let decoder = thread::spawn(move || {
let mut sum = 0u64;
for encoded in rx {
let (value, _) = u32::try_decode_from(&encoded).unwrap();
sum += u64::from(value);
}
sum
});
encoder.join().unwrap();
let sum = decoder.join().unwrap();
assert_eq!(sum, 499_500);
}
#[cfg(feature = "std")]
#[test]
fn concurrency_test_multi_producer_single_consumer() {
use std::sync::mpsc;
use std::thread;
let (tx, rx) = mpsc::channel();
let producers: Vec<_> = (0..4)
.map(|thread_id| {
let tx = tx.clone();
thread::spawn(move || {
for i in 0u16..100 {
let value = thread_id * 100 + i;
tx.send(value.encode_into()).unwrap();
}
})
})
.collect();
drop(tx);
let consumer = thread::spawn(move || {
let mut count = 0;
for encoded in rx {
let (value, _) = u16::try_decode_from(&encoded).unwrap();
assert!(value < 400);
count += 1;
}
count
});
for producer in producers {
producer.join().unwrap();
}
let total = consumer.join().unwrap();
assert_eq!(total, 400); }
#[cfg(feature = "std")]
#[test]
fn concurrency_test_stress_parallel_encoding() {
use std::thread;
let handles: Vec<_> = (0..100)
.map(|i| {
thread::spawn(move || {
let mut buffer = Vec::new();
for j in 0u8..255 {
((i * 255 + u32::from(j)) % u32::from(u16::MAX))
.encode_into_buffer(&mut buffer);
}
buffer.len()
})
})
.collect();
let mut total_bytes = 0;
for handle in handles {
total_bytes += handle.join().unwrap();
}
assert!(total_bytes >= 25500); assert!(total_bytes < 76500); }
#[cfg(feature = "std")]
#[test]
fn concurrency_test_stress_shared_read() {
use std::sync::Arc;
use std::thread;
let mut data = Vec::new();
for i in 0u32..10000 {
i.encode_into_buffer(&mut data);
}
let shared_data = Arc::new(data);
let handles: Vec<_> = (0..50)
.map(|_| {
let data = Arc::clone(&shared_data);
thread::spawn(move || {
let mut slice = &data[..];
let mut count = 0;
while !slice.is_empty() {
if let Ok((_, remaining)) = u32::try_decode_from(slice) {
count += 1;
slice = remaining;
} else {
break;
}
}
count
})
})
.collect();
for handle in handles {
let count = handle.join().unwrap();
assert_eq!(count, 10000);
}
}
#[cfg(feature = "std")]
#[test]
fn concurrency_test_work_stealing() {
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
let work_queue = Arc::new(Mutex::new((0u32..1000).collect::<Vec<_>>()));
let results = Arc::new(Mutex::new(Vec::new()));
let workers: Vec<_> = (0..4)
.map(|_| {
let queue = Arc::clone(&work_queue);
let results = Arc::clone(&results);
thread::spawn(move || {
loop {
let work_item = {
let mut queue = queue.lock().unwrap();
queue.pop()
};
match work_item {
Some(value) => {
let encoded = value.encode_into();
let (decoded, _) = u32::try_decode_from(&encoded).unwrap();
results.lock().unwrap().push(decoded);
}
None => break,
}
}
})
})
.collect();
for worker in workers {
worker.join().unwrap();
}
let results = results.lock().unwrap();
assert_eq!(results.len(), 1000);
}
}