Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ include = [
default-members = ["./", "lowlevel-types"]

[workspace.package]
version = "1.0.0"
version = "1.1.0"
edition = "2024"
repository = "https://github.com/JEleniel/serde_binary_adv"
license = "MIT OR Apache-2.0"
Expand All @@ -39,6 +39,7 @@ unsafe_code = "forbid"
lowlevel-types = { workspace = true }
num = "0.4.3"
serde = { workspace = true }
serde_bytes = "0.11.19"

[features]
default = ["streaming"]
Expand Down
37 changes: 37 additions & 0 deletions src/serde_binary_adv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,34 @@ mod tests {
impl_test_x!(test_byte_array, [0x41 as u8, 0x42 as u8, 0x43 as u8]);
impl_test_x!(test_array, [0x41, 0x42, 0x43]);

#[test]
fn test_borrowed_bytes() {
// The data must live as long as the deserialized reference.
let value: &[u8] = &[0x41, 0x42, 0x43];
let serialized = Serializer::to_bytes(&value, false).unwrap();

// Make the test function generic over the lifetime.
fn roundtrip<'de>(input: &'de [u8]) {
let deserialized: &'de [u8] = Deserializer::from_bytes(&input, false).unwrap();
assert_eq!(&input[1..], deserialized);
}

roundtrip(&serialized);
Comment on lines +142 to +147
Copy link

Copilot AI Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assertion compares &input[1..] (skipping the first byte) with deserialized, but the test should compare the original value with deserialized. This appears to be accounting for a length prefix, but the logic is unclear and may not be testing the correct behavior.

Suggested change
fn roundtrip<'de>(input: &'de [u8]) {
let deserialized: &'de [u8] = Deserializer::from_bytes(&input, false).unwrap();
assert_eq!(&input[1..], deserialized);
}
roundtrip(&serialized);
fn roundtrip<'de>(value: &'de [u8], input: &'de [u8]) {
let deserialized: &'de [u8] = Deserializer::from_bytes(&input, false).unwrap();
assert_eq!(value, deserialized);
}
roundtrip(value, &serialized);

Copilot uses AI. Check for mistakes.
}

#[test]
fn test_serde_bytes_bytes() {
use serde_bytes::Bytes;
let data = [0x41, 0x42, 0x43];
let value: &Bytes = Bytes::new(&data);

let serialized = Serializer::to_bytes(&value, false).unwrap();
let deserialized: &Bytes =
Deserializer::from_bytes(Bytes::new(&serialized), false).unwrap();
Copy link

Copilot AI Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deserialization is attempting to deserialize from Bytes::new(&serialized) but should deserialize from &serialized directly. The Bytes::new(&serialized) creates a Bytes wrapper around the serialized data, which is not the correct input format for the deserializer.

Suggested change
Deserializer::from_bytes(Bytes::new(&serialized), false).unwrap();
Deserializer::from_bytes(&serialized, false).unwrap();

Copilot uses AI. Check for mistakes.

assert_eq!(value, deserialized);
}

#[test]
fn test_map() {
let mut v: HashMap<String, char> = HashMap::new();
Expand All @@ -143,6 +171,15 @@ mod tests {

impl_test_x!(test_tuple, ('a', 16, 0x41 as u8));

#[test]
fn test_serde_bytes_bytebuf() {
use serde_bytes::ByteBuf;
let value = ByteBuf::from(vec![0x41, 0x42, 0x43]);
let serialized = Serializer::to_bytes(&value, false).unwrap();
let deserialized: ByteBuf = Deserializer::from_bytes(&serialized, false).unwrap();
assert_eq!(value, deserialized);
}

fn test<T>(value: T)
where
T: Serialize + for<'de> Deserialize<'de> + std::fmt::Debug + PartialEq,
Expand Down
2 changes: 1 addition & 1 deletion src/serde_binary_adv/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
{
let len = self.next_usize()?;
let bytes = self.take(len)?;
visitor.visit_bytes(bytes)
visitor.visit_borrowed_bytes(bytes)
}

fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
Expand Down
8 changes: 6 additions & 2 deletions src/serde_binary_adv/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,12 @@ impl<'a> ser::Serializer for &'a mut Serializer {
self.serialize_vec(v.as_bytes().to_vec())
}

fn serialize_bytes(self, _v: &[u8]) -> Result<Self::Ok> {
unimplemented!()
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok> {
if v.len() > 0 {
Copy link

Copilot AI Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using v.len() > 0 is less idiomatic than !v.is_empty(). The is_empty() method is more explicit about the intent and is the preferred way to check for empty collections in Rust.

Suggested change
if v.len() > 0 {
if !v.is_empty() {

Copilot uses AI. Check for mistakes.
v.serialize(&mut *self)
} else {
self.serialize_usize(v.len())
}
}

fn serialize_none(self) -> Result<Self::Ok> {
Expand Down
238 changes: 238 additions & 0 deletions src/serde_binary_adv/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,54 @@ mod tests {
assert_eq!(v, deserialized2);
}

#[test]
fn test_borrowed_bytes() {
let bytes: &[u8] = &[0x41, 0x42, 0x43, 0x44];
let mut buf = [0u8; 16];
let mut written = &mut buf[..];
Serializer::write_bytes(&mut written, &bytes, false).unwrap();
let used = 16 - written.len();
let mut read = &buf[..used];
let deserialized: &[u8] = Deserializer::read_bytes(&mut read, false).unwrap();
assert_eq!(bytes, deserialized);

let mut buf2 = [0u8; 16];
let mut written2 = &mut buf2[..];
Serializer::write_bytes(&mut written2, &bytes, true).unwrap();
let used2 = 16 - written2.len();
let mut read2 = &buf2[..used2];
let deserialized2: &[u8] = Deserializer::read_bytes(&mut read2, true).unwrap();
assert_eq!(bytes, deserialized2);
}

#[test]
fn test_serialize_byte_buf() {
let bytes = vec![0x41, 0x42, 0x43, 0x44];
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &bytes, false).unwrap();
let deserialized: Vec<u8> = Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(bytes, deserialized);

let mut buf2 = Vec::new();
Serializer::write_bytes(&mut buf2, &bytes, true).unwrap();
let deserialized2: Vec<u8> = Deserializer::read_bytes(&mut buf2.as_slice(), true).unwrap();
assert_eq!(bytes, deserialized2);
}

#[test]
fn test_deserialize_byte_buf() {
let orig = vec![0x41, 0x42, 0x43, 0x44];
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &orig, false).unwrap();
let deserialized: Vec<u8> = Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(orig, deserialized);

let mut buf2 = Vec::new();
Serializer::write_bytes(&mut buf2, &orig, true).unwrap();
let deserialized2: Vec<u8> = Deserializer::read_bytes(&mut buf2.as_slice(), true).unwrap();
assert_eq!(orig, deserialized2);
}

#[test]
fn test_map() {
let mut v: HashMap<String, char> = HashMap::new();
Expand All @@ -180,4 +228,194 @@ mod tests {

// Test Serde Tuple
impl_test_x!(test_tuple, (char, i32, u8), ('a', 16, 0x41 as u8));

#[test]
fn test_empty_vec() {
let v: Vec<u8> = vec![];
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &v, false).unwrap();
let deserialized: Vec<u8> = Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(v, deserialized);

let mut buf2 = Vec::new();
Serializer::write_bytes(&mut buf2, &v, true).unwrap();
let deserialized2: Vec<u8> = Deserializer::read_bytes(&mut buf2.as_slice(), true).unwrap();
assert_eq!(v, deserialized2);
}

#[test]
fn test_empty_string() {
let s = String::new();
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &s, false).unwrap();
let deserialized: String = Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(s, deserialized);

let mut buf2 = Vec::new();
Serializer::write_bytes(&mut buf2, &s, true).unwrap();
let deserialized2: String = Deserializer::read_bytes(&mut buf2.as_slice(), true).unwrap();
assert_eq!(s, deserialized2);
}

#[test]
fn test_empty_map() {
let v: HashMap<u8, u8> = HashMap::new();
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &v, false).unwrap();
let deserialized: HashMap<u8, u8> =
Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(v, deserialized);

let mut buf2 = Vec::new();
Serializer::write_bytes(&mut buf2, &v, true).unwrap();
let deserialized2: HashMap<u8, u8> =
Deserializer::read_bytes(&mut buf2.as_slice(), true).unwrap();
assert_eq!(v, deserialized2);
}

#[test]
fn test_unit_struct_roundtrip() {
let v = Unit;
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &v, false).unwrap();
let deserialized: Unit = Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(v, deserialized);
}

#[test]
fn test_tuple_struct_roundtrip() {
let v = TupleStruct(1, 2, 3);
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &v, false).unwrap();
let deserialized: TupleStruct =
Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(v, deserialized);
}

#[test]
fn test_struct_with_empty_string() {
let v = Test {
byte: 0,
string: String::new(),
};
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &v, false).unwrap();
let deserialized: Test = Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(v, deserialized);
}

#[test]
fn test_option_some_none() {
let v: Option<u8> = Some(42);
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &v, false).unwrap();
let deserialized: Option<u8> =
Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(v, deserialized);

let v: Option<u8> = None;
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &v, false).unwrap();
let deserialized: Option<u8> =
Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(v, deserialized);
}

#[test]
fn test_struct_variant_empty_fields() {
#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum E {
S {},
}
let v = E::S {};
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &v, false).unwrap();
let deserialized: E = Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(v, deserialized);
}

#[test]
fn test_tuple_variant_empty() {
#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum E {
T(),
}
let v = E::T();
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &v, false).unwrap();
let deserialized: E = Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(v, deserialized);
}

#[test]
fn test_enum_unit_variant() {
#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum E {
U,
}
let v = E::U;
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &v, false).unwrap();
let deserialized: E = Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(v, deserialized);
}

#[test]
fn test_enum_newtype_variant() {
#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum E {
N(u8),
}
let v = E::N(123);
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &v, false).unwrap();
let deserialized: E = Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(v, deserialized);
}

#[test]
fn test_enum_tuple_variant() {
#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum E {
T(u8, u8),
}
let v = E::T(1, 2);
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &v, false).unwrap();
let deserialized: E = Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(v, deserialized);
}

#[test]
fn test_enum_struct_variant() {
#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum E {
S { x: u8, y: u8 },
}
let v = E::S { x: 1, y: 2 };
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &v, false).unwrap();
let deserialized: E = Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(v, deserialized);
}

#[test]
fn test_map_non_string_key() {
let mut v: HashMap<u8, u8> = HashMap::new();
v.insert(1, 2);
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &v, false).unwrap();
let deserialized: HashMap<u8, u8> =
Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(v, deserialized);
}

#[test]
fn test_array_empty() {
let v: [u8; 0] = [];
let mut buf = Vec::new();
Serializer::write_bytes(&mut buf, &v, false).unwrap();
let deserialized: [u8; 0] = Deserializer::read_bytes(&mut buf.as_slice(), false).unwrap();
assert_eq!(v, deserialized);
}
}
Loading