#[cfg(not(feature = "std"))]
use alloc::{format, vec::Vec};
use crate::error::Error;
use core::ops::Deref;
use unsigned_varint::decode;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EncodedBytes(Vec<u8>);
impl EncodedBytes {
pub fn new(bytes: &[u8]) -> Result<Self, Error> {
Self::try_from(bytes.to_vec())
}
#[inline]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
#[inline]
pub fn into_vec(self) -> Vec<u8> {
self.0
}
}
impl TryFrom<Vec<u8>> for EncodedBytes {
type Error = Error;
fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
if bytes.is_empty() {
return Err(Error::InsufficientData {
expected: 1,
actual: 0,
});
}
let remaining = match decode::u128(&bytes) {
Ok((_, remaining)) => remaining,
Err(source) => {
#[cfg(feature = "std")]
{
return Err(Error::UnsignedVarintDecode { source });
}
#[cfg(not(feature = "std"))]
{
return Err(Error::UnsignedVarintDecode {
message: format!("{:?}", source),
});
}
}
};
if !remaining.is_empty() {
return Err(Error::InvalidEncoding {
reason: format!(
"trailing bytes after valid varint: {} bytes remaining",
remaining.len()
),
});
}
Ok(EncodedBytes(bytes))
}
}
impl From<EncodedBytes> for Vec<u8> {
#[inline]
fn from(encoded: EncodedBytes) -> Self {
encoded.0
}
}
impl AsRef<[u8]> for EncodedBytes {
#[inline]
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Deref for EncodedBytes {
type Target = [u8];
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
unsafe impl Send for EncodedBytes {}
unsafe impl Sync for EncodedBytes {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_valid_single_byte() {
let bytes = vec![42];
let encoded = EncodedBytes::try_from(bytes).unwrap();
assert_eq!(encoded.as_ref(), &[42]);
assert_eq!(encoded.len(), 1);
assert!(!encoded.is_empty());
}
#[test]
fn test_valid_multi_byte() {
let bytes = vec![0x80, 0x01];
let encoded = EncodedBytes::try_from(bytes).unwrap();
assert_eq!(encoded.len(), 2);
}
#[test]
fn test_empty_bytes_rejected() {
let empty: Vec<u8> = vec![];
let result = EncodedBytes::try_from(empty);
assert!(result.is_err());
if let Err(Error::InsufficientData { expected, actual }) = result {
assert_eq!(expected, 1);
assert_eq!(actual, 0);
} else {
panic!("Expected InsufficientData error");
}
}
#[test]
fn test_truncated_varint_rejected() {
let truncated = vec![0x80];
let result = EncodedBytes::try_from(truncated);
assert!(result.is_err());
}
#[test]
fn test_trailing_bytes_rejected() {
let mut bytes = vec![42];
bytes.extend_from_slice(&[0xFF, 0xEE]);
let result = EncodedBytes::try_from(bytes);
assert!(result.is_err());
if let Err(Error::InvalidEncoding { reason }) = result {
assert!(reason.contains("trailing bytes"));
} else {
panic!("Expected InvalidEncoding error");
}
}
#[test]
fn test_into_vec() {
let original = vec![0x80, 0x01]; let encoded = EncodedBytes::try_from(original.clone()).unwrap();
let recovered: Vec<u8> = encoded.into();
assert_eq!(recovered, original);
}
#[test]
fn test_deref() {
let encoded = EncodedBytes::new(&[42]).unwrap();
assert_eq!(encoded[0], 42); }
#[test]
fn test_clone() {
let encoded = EncodedBytes::new(&[42]).unwrap();
let cloned = encoded.clone();
assert_eq!(encoded, cloned);
}
#[test]
fn test_debug() {
let encoded = EncodedBytes::new(&[42]).unwrap();
let debug_str = format!("{:?}", encoded);
assert!(debug_str.contains("EncodedBytes"));
}
#[test]
fn assert_send_sync() {
fn is_send<T: Send>() {}
fn is_sync<T: Sync>() {}
is_send::<EncodedBytes>();
is_sync::<EncodedBytes>();
}
}