Решение на Network Packets от Ангел Беширов

Обратно към всички решения

Към профила на Ангел Беширов

Резултати

  • 19 точки от тестове
  • 1 бонус точка
  • 20 точки общо
  • 14 успешни тест(а)
  • 1 неуспешни тест(а)

Код

use std::fmt;
#[derive(Debug)]
pub enum PacketError {
InvalidPacket,
InvalidChecksum,
UnknownProtocolVersion,
CorruptedMessage,
}
impl fmt::Display for PacketError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
PacketError::InvalidPacket => write!(f, "The packet is invalid!"),
PacketError::InvalidChecksum => write!(f, "The checksum is invalid!"),
PacketError::UnknownProtocolVersion => write!(f, "The protocol version is invalid, currently only 1 is supported!"),
PacketError::CorruptedMessage => write!(f, "The reassembled message is not valid UTF-8!"),
}
}
}
impl std::error::Error for PacketError {}
#[derive(PartialEq, Debug)]
pub struct Packet {
size: u8,
payload: Vec<u8>,
checksum: u32,
}
impl Packet {
pub fn from_source(source: &[u8], size: u8) -> (Self, &[u8]) {
if size <= 0 || source.len() == 0 {
panic!("Packet with size less than or equal to zero can not be created!");
}
let real_size: u8 = {
if source.len() < size as usize {
source.len() as u8
} else {
size
}
};

Няма нужда да използваш различно име -- можеше да е let size = { и този size да скрие оригиналната стойност. По този начин се подсигуряваш, че всякаква употреба на size надолу е правилния размер. Иначе има шанса някой да меши real_size и size и потенциално да допусне тънък бъг.

let payload: Vec<u8> = source[0..real_size as usize].to_vec();
let remaining: &[u8] = &source[real_size as usize..source.len()];
let checksum: u32 = payload.iter().map(|&byte| byte as u32).sum();
(Packet {
size: real_size,
payload: payload,
checksum: checksum,
},
remaining)
}
pub fn payload(&self) -> &[u8] {
&self.payload
}
pub fn serialize(&self) -> Vec<u8> {
let mut vec: Vec<u8> = Vec::new();
vec.push(1);
vec.push(self.size);
vec.extend_from_slice(&self.payload);
vec.extend_from_slice(&self.checksum.to_be_bytes());
vec
}
pub fn deserialize(bytes: &[u8]) -> Result<(Packet, &[u8]), PacketError> {
if bytes.len() == 0 {
panic!("Can not deserialize empty bytes slice");
}
if bytes[0] != 1 {
return Err(PacketError::UnknownProtocolVersion);
}
if bytes.len() <= 6 || bytes.len() < (bytes[1] + 6) as usize || bytes[1] == 0 {
return Err(PacketError::InvalidPacket);
}
let size: usize = bytes[1] as usize;
let vec: Vec<u8> = bytes[2..(size + 2)].to_vec();
let checksum_validate: u32 = bytes[2..(size + 2)].iter().map(|&byte| byte as u32).sum();
let received_checksum: u32 = u32::from_be_bytes([bytes[size + 2], bytes[size + 3], bytes[size + 4], bytes[size + 5]]);
if checksum_validate != received_checksum {
return Err(PacketError::InvalidChecksum);
}
Ok(
(Packet {
size: size as u8,
payload: vec,
checksum: received_checksum,
}, &bytes[(size + 6)..bytes.len()])
)
}
}
pub struct PacketSerializer {
data: Vec<u8>,
packet_size: u8,
}
impl Iterator for PacketSerializer {
type Item = Packet;
fn next(&mut self) -> Option<Self::Item> {
if self.data.len() == 0 {
return None;
}
let cloned: Vec<u8> = self.data.clone();
let tuple: (Packet, &[u8]) = Packet::from_source(&cloned, self.packet_size);

Вместо да вземаш tuple и после да достъпваш елементите с tuple.1 и tuple.0 (които не са много ясни имена), можеше да дефинираш две променливи с присвояването:

let (packet, remainder) = Packet::from_source(&cloned, self.packet_size);
self.data = remainder.to_vec();
Some(packet)

Освен това не мисля, че е нужно да клонираш self.data -- Packet::from_source си очаква reference, взема назаем стойността на self.data. Мисля, че можеше да подадеш директно &self.data и щеше да сработи.

self.data = tuple.1.to_vec();
Some(tuple.0)
}
}
pub trait Packetable: Sized {
fn to_packets(&self, packet_size: u8) -> PacketSerializer;
fn to_packet_data(&self, packet_size: u8) -> Vec<u8>;
fn from_packet_data(packet_data: &[u8]) -> Result<Self, PacketError>;
}
impl Packetable for String {
fn to_packets(&self, packet_size: u8) -> PacketSerializer {
let bytes: &[u8] = self.as_bytes();
let size: u8 = {
if bytes.len() <= packet_size as usize {
bytes.len() as u8
} else {
packet_size
}
};
// Will return PacketSerializer with size 0, but will
// panic when next is called.
PacketSerializer {
data: bytes.to_vec(),
packet_size: size,
}
}
fn to_packet_data(&self, packet_size: u8) -> Vec<u8> {
let mut data: Vec<u8> = Vec::new();
for packet in self.to_packets(packet_size) {
data.extend(packet.serialize());
}
data
}
fn from_packet_data(packet_data: &[u8]) -> Result<Self, PacketError> {
let mut deserialized: Vec<u8> = Vec::new();
let mut tuple: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(packet_data);
let mut next_data: &[u8] = match tuple {
Err(x) => return Err(x),
Ok(y) => {
deserialized.extend(y.0.payload);
y.1
},
};

Тук и по-долу можеше да използваш оператора ? за да избегнеш Err(x) => return Err(x):

let tuple: (Packet, &[u8]) = Packet::deserialize(packet_data)?;
deserialized.extend(tuple.0.payload);
let mut next_data = tuple.1;

И както казах по-горе, можеше и да pattern-match-неш компонентите на tuple.

while next_data.len() > 0 {
tuple = Packet::deserialize(next_data);
match tuple {
Err(x) => return Err(x),
Ok(y) => {
deserialized.extend(y.0.payload);
next_data = y.1;
},
};
}
match String::from_utf8(deserialized) {
Err(_) => Err(PacketError::CorruptedMessage),
Ok(x) => Ok(x),
}
}
}
#[test]
fn test_serialization_basic_small_size() {
let string_value = String::from("aba");
let source: &[u8] = string_value.as_bytes();
let tuple: (Packet, &[u8]) = Packet::from_source(source, 1);
assert_eq!(tuple.0.payload(), [97]);
assert_eq!(tuple.1, [98, 97]);
}
#[test]
fn test_serialization_basic_larger_size() {
let string_value = String::from("aba");
let source: &[u8] = string_value.as_bytes();
let tuple: (Packet, &[u8]) = Packet::from_source(source, 122);
assert_eq!(tuple.0.payload(), [97, 98, 97]);
assert_eq!(tuple.1, []);
}
#[test]
#[should_panic]
fn test_serialization_empty() {
let _tuple: (Packet, &[u8]) = Packet::from_source(&[], 1);
}
#[test]
fn test_serialization_iterations() {
let string_value = String::from("баба");
let source: &[u8] = string_value.as_bytes();
let tuple: (Packet, &[u8]) = Packet::from_source(source, 3);
assert_eq!(tuple.0.payload(), [208, 177, 208]);
assert_eq!(tuple.1, [176, 208, 177, 208, 176]);
let tuple: (Packet, &[u8]) = Packet::from_source(tuple.1, 3);
assert_eq!(tuple.0.payload(), [176, 208, 177]);
assert_eq!(tuple.1, [208, 176]);
let tuple: (Packet, &[u8]) = Packet::from_source(tuple.1, 3);
assert_eq!(tuple.0.payload(), [208, 176]);
assert_eq!(tuple.1, []);
}
// serialize method
#[test]
fn test_serialize() {
let string_value = String::from("баба");
let source: &[u8] = string_value.as_bytes();
let tuple: (Packet, &[u8]) = Packet::from_source(source, 3);
assert_eq!(tuple.0.payload(), [208, 177, 208]);
assert_eq!(tuple.1, [176, 208, 177, 208, 176]);
let vec: Vec<u8> = tuple.0.serialize();
assert_eq!(vec, [1, 3, 208, 177, 208, 0, 0, 2, 81]);
}
// deserialize
#[test]
#[should_panic]
fn test_empty_slice_deserialization() {
let _res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[]);
}
#[test]
fn test_complete_deserialization() {
let res: (Packet, &[u8]) = Packet::deserialize(&[1, 3, 208, 177, 208, 0, 0, 2, 81]).unwrap();
assert_eq!(res.0.payload(), [208, 177, 208]);
assert_eq!(res.1, []);
}
#[test]
fn test_incomplete_deserialization() {
let res: (Packet, &[u8]) = Packet::deserialize(&[1, 3, 208, 177, 208, 0, 0, 2, 81, 1, 1, 21, 0, 0, 0, 21]).unwrap();
assert_eq!(res.0.payload(), [208, 177, 208]);
assert_eq!(res.1, [1, 1, 21, 0, 0, 0, 21]);
}
#[test]
fn test_deserialize_unknown_version_error() {
let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[2, 3, 208, 177, 208, 0, 0, 2, 81, 1, 1, 21, 0, 0, 0, 21]);
if let Err(PacketError::UnknownProtocolVersion) = res {
assert!(true);
} else {
assert!(false, "Unknown protocol version expected");
}
}

Едно помощно средство, което аз написах за тестовете:

macro_rules! assert_match {
    ($expr:expr, $pat:pat) => {
        if let $pat = $expr {
            // all good
        } else {
            assert!(false, "Expression {:?} does not match the pattern {:?}", $expr, stringify!($pat));
        }
    }
}

По този начин, можеш да напишеш този тест по-просто така:

assert_match!(Packet::deserialize(&data), Err(PacketError::UnknownProtocolVersion));

И ако теста не проработи, ще получиш по-ясна грешка.

#[test]
fn test_deserialize_invalid_checksum() {
let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 3, 208, 177, 208, 0, 0, 3, 81, 1, 1, 21, 0, 0, 0, 21]);
if let Err(PacketError::InvalidChecksum) = res {
assert!(true);
} else {
assert!(false, "Invalid checksum expected");
}
}
#[test]
fn test_deserialize_packet_with_size_0() {
let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 0, 208, 177, 208, 0, 0, 1, 81, 1, 1, 21, 0, 0, 0, 21]);
if let Err(PacketError::InvalidPacket) = res {
assert!(true);
} else {
assert!(false, "Invalid packet expected");
}
}
#[test]
fn test_deserialize_missing_checksum() {
let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 13, 208, 177, 208, 0, 0, 1, 81, 1, 1, 21, 0, 0, 0, 21]);
if let Err(PacketError::InvalidPacket) = res {
assert!(true);
} else {
assert!(false, "Invalid packet expected");
}
}
#[test]
fn test_deserialize_overflow_size() {
let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 20, 208, 177, 208, 0, 0, 1, 81, 1, 1, 21, 0, 0, 0, 21]);
if let Err(PacketError::InvalidPacket) = res {
assert!(true);
} else {
assert!(false, "Invalid packet expected");
}
}
#[test]
fn test_deserialize_invalid_checksum_because_of_wrong_size() {
let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 4, 208, 177, 208, 0, 0, 2, 81, 1, 1, 21, 0, 0, 0, 21]);
if let Err(PacketError::InvalidChecksum) = res {
assert!(true);
} else {
assert!(false, "Invalid checksum expected");
}
}
#[test]
fn test_deserialize_too_small_slices() {
// let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[]); should panic
let res1: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1]);
let res2: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 1]);
let res3: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 1, 1]);
let res4: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 1, 1, 0]);
let res5: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 1, 1, 0, 1]);
let res6: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 0, 0, 0, 0, 0]); // the biggest invalid small slice
if let Err(PacketError::InvalidPacket) = res1 {
assert!(true);
} else {
assert!(false, "Invalid packet expected");
}
if let Err(PacketError::InvalidPacket) = res2 {
assert!(true);
} else {
assert!(false, "Invalid packet expected");
}
if let Err(PacketError::InvalidPacket) = res3 {
assert!(true);
} else {
assert!(false, "Invalid packet expected");
}
if let Err(PacketError::InvalidPacket) = res4 {
assert!(true);
} else {
assert!(false, "Invalid packet expected");
}
if let Err(PacketError::InvalidPacket) = res5 {
assert!(true);
} else {
assert!(false, "Invalid packet expected");
}
if let Err(PacketError::InvalidPacket) = res6 {
assert!(true);
} else {
assert!(false, "Invalid packet expected");
}
}
#[test]
fn test_deserialize_the_smallest_packet() {
let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 1, 1, 0, 0, 0, 1]);
assert_eq!(res.is_err(), false);
let res = res.unwrap();
assert_eq!(res.0.payload(), [1]);
assert_eq!(res.1, []);
}
#[test]
fn test_next_on_empty_iterator() {
assert_eq!(String::new().to_packets(10).next(), None);
}
// test packetable
#[test]
fn test_basic_packets() {
let source = b"hello";
let (packet, remainder) = Packet::from_source(source, 100);
assert_eq!(packet.payload().len(), source.len());
assert_eq!(remainder, b"");
assert!(packet.serialize().len() > 0);
if let Err(_) = Packet::deserialize(&packet.serialize()) {
assert!(false, "Couldn't deserialize packet data");
}
}
#[test]
fn test_basic_iteration() {
let source = String::from("hello");
let packets = source.to_packets(100).collect::<Vec<Packet>>();
assert!(packets.len() > 0);
let data = source.to_packet_data(100);
assert!(data.len() > 0);
if let Err(_) = String::from_packet_data(&data) {
assert!(false, "Couldn't deserialize packet data");
}
}
#[test]
fn test_basic_multiple_packets() {
let source = String::from("hello");
let packets = source.to_packets(1).collect::<Vec<Packet>>();
assert!(packets.len() == 5);
let data = source.to_packet_data(1);
assert!(data.len() == 35); // each packet is 1 1 x b3 b2 b1 b0 -> 7, 7*5 = 35
if let Err(_) = String::from_packet_data(&data) {
assert!(false, "Couldn't deserialize packet data");
}
if let Ok(x) = String::from_packet_data(&data) {
assert_eq!(x, source);
}
}
#[test]
fn test_basic_multibyte() {
let source = String::from("баба");
let packets = source.to_packets(2).collect::<Vec<Packet>>();
assert!(packets.len() == 4);
let data = source.to_packet_data(2);
assert_eq!(32, data.len()); // 1 2 x y b3 b2 b1 b0 -> 4*8 = 32
let res = String::from_packet_data(&data);
if let Err(_) = res {
assert!(false, "Couldn't deserialize serialized packet data");
}
if let Ok(x) = res {
assert_eq!(x, source);
}
}
#[test]
fn test_basic_packets_bigger_size() {
let source = String::from("hello");
let packets = source.to_packets(12).collect::<Vec<Packet>>();
assert!(packets.len() == 1);
let data = source.to_packet_data(12);
assert!(data.len() == 11); // 1 5 x y z t s b3 b2 b1 b0
if let Err(_) = String::from_packet_data(&data) {
assert!(false, "Couldn't deserialize serialized packet data");
}
if let Ok(x) = String::from_packet_data(&data) {
assert_eq!(x, source);
}
}
#[test]
fn test_empty_string() {
let source = String::from("");
let packets = source.to_packets(10).collect::<Vec<Packet>>();
assert_eq!(0, packets.len());
let data = source.to_packet_data(12);
assert_eq!(0, data.len());
}
// deserialize
#[test]
#[should_panic]
fn test_empty_string_deserialize() {
let source = String::from("");
let packets = source.to_packets(10).collect::<Vec<Packet>>();
assert_eq!(0, packets.len());
let data = source.to_packet_data(12);
assert_eq!(0, data.len());
let _res = String::from_packet_data(&data); // data is empty
}
#[test]
fn test_basic_multibyte_2() {
let source = String::from("АСДФГ");
let packets = source.to_packets(10).collect::<Vec<Packet>>();
assert_eq!(1, packets.len());
let data = source.to_packet_data(10);
assert!(data.len() == 16);
if let Err(_) = String::from_packet_data(&data) {
assert!(false, "Couldn't deserialize serialized packet data");
}
if let Ok(x) = String::from_packet_data(&data) {
assert_eq!(x, source);
}
}
#[test]
fn test_complex_mutlibyte() {
let source = String::from("АСАддассАСдHHHHHjsjasdасАсдАсдасдСДФГАСʥʥАдассАСдасАдасАсдАсдасдСДФГ");
let packets = source.to_packets(10).collect::<Vec<Packet>>();
assert!(packets.len() > 10);
let data = source.to_packet_data(10);
assert!(data.len() > 50);
if let Err(_) = String::from_packet_data(&data) {
assert!(false, "Couldn't deserialize serialized packet data");
}
if let Ok(x) = String::from_packet_data(&data) {
assert_eq!(x, source);
}
}
// test error propagation
#[test]
fn test_deserialize_unknown_version_string() {
let deserialized = String::from_packet_data(&[12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11]);
if let Err(PacketError::UnknownProtocolVersion) = deserialized {
assert!(true);
} else {
assert!(false, "Unknown protocol version error expected");
}
}
#[test]
fn test_deserialize_basic_packet() {
let deserialized = String::from_packet_data(&[1, 2, 1, 3, 0, 0, 0, 4]);
if let Ok(_x) = deserialized {
assert!(true);
} else {
assert!(false, "Couldn't deserialize serialized packet data");
}
}
#[test]
fn test_deserialize_invalid_packet() {
let deserialized = String::from_packet_data(&[1, 2, 1, 3, 0, 0, 0]);
if let Err(PacketError::InvalidPacket) = deserialized {
assert!(true);
} else {
assert!(false, "Invalid packet error expected!");
}
}
#[test]
fn test_corrupted_message_invalid_sparkle() {
let deserialized = String::from_packet_data(&[1, 4, 0, 159, 146, 150, 0, 0, 0b00000001, 0b11000111]); // 455
if let Err(PacketError::CorruptedMessage) = deserialized {
assert!(true);
} else {
assert!(false, "Corrupted message error expected!");
}
}
#[test]
fn test_sparkle() {
let deserialized = String::from_packet_data(&[1, 4, 240, 159, 146, 150, 0, 0, 0b00000010, 0b10110111]); // 695 checksum
if let Ok(x) = deserialized {
assert_eq!("💖", x);
} else {
assert!(false, "Couldn't deserialize data");
}
}
#[test]
fn test_invalid_checksum() {
let deserialized = String::from_packet_data(&[1, 4, 240, 159, 146, 150, 0, 0, 0b00010010, 0b10110111]);
if let Err(PacketError::InvalidChecksum) = deserialized {
assert!(true);
} else {
assert!(false, "Invalid checksum error expected");
}
}
#[test]
fn test_empty_string_for_to_packet_data() {
let empty_vector: Vec<u8> = vec![];
assert_eq!(empty_vector, String::new().to_packet_data(10));
}
#[test]
#[should_panic]
fn test_size_zero_for_to_packet_data() {
String::from("asd").to_packet_data(0);
}
#[test]
fn test_large_multibyte_string() {
let str = String::from("ʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥ");
let packets = str.to_packets(10).collect::<Vec<Packet>>();
assert!(packets.len() > 22);
let data = str.to_packet_data(10);
assert!(data.len() > 50);
if let Err(_) = String::from_packet_data(&data) {
assert!(false, "Couldn't deserialize serialized packet data");
}
if let Ok(x) = String::from_packet_data(&data) {
assert_eq!(x, str);
}
}

Лог от изпълнението

Compiling solution v0.1.0 (/tmp/d20200111-2173579-ofw977/solution)
    Finished test [unoptimized + debuginfo] target(s) in 5.02s
     Running target/debug/deps/solution-a73e64ec87929bd0

running 35 tests
test test_basic_iteration ... ok
test test_basic_multibyte ... ok
test test_basic_multibyte_2 ... ok
test test_basic_multiple_packets ... ok
test test_basic_packets ... ok
test test_basic_packets_bigger_size ... ok
test test_complete_deserialization ... ok
test test_complex_mutlibyte ... ok
test test_corrupted_message_invalid_sparkle ... ok
test test_deserialize_basic_packet ... ok
test test_deserialize_invalid_checksum ... ok
test test_deserialize_invalid_checksum_because_of_wrong_size ... ok
test test_deserialize_invalid_packet ... ok
test test_deserialize_missing_checksum ... ok
test test_deserialize_overflow_size ... ok
test test_deserialize_packet_with_size_0 ... ok
test test_deserialize_the_smallest_packet ... ok
test test_deserialize_too_small_slices ... ok
test test_deserialize_unknown_version_error ... ok
test test_deserialize_unknown_version_string ... ok
test test_empty_slice_deserialization ... ok
test test_empty_string ... ok
test test_empty_string_deserialize ... ok
test test_empty_string_for_to_packet_data ... ok
test test_incomplete_deserialization ... ok
test test_invalid_checksum ... ok
test test_large_multibyte_string ... ok
test test_next_on_empty_iterator ... ok
test test_serialization_basic_larger_size ... ok
test test_serialization_basic_small_size ... ok
test test_serialization_empty ... ok
test test_serialization_iterations ... ok
test test_serialize ... ok
test test_size_zero_for_to_packet_data ... ok
test test_sparkle ... ok

test result: ok. 35 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target/debug/deps/solution_test-38971695424b36d5

running 15 tests
test solution_test::test_construct_packet_from_unicode ... ok
test solution_test::test_construct_packet_no_remainder ... ok
test solution_test::test_construct_packet_with_remainder ... ok
test solution_test::test_construct_packet_with_remainder_cyrillic ... ok
test solution_test::test_consuming_packets ... ok
test solution_test::test_deserialize_invalid_packet ... ok
test solution_test::test_deserialize_packet ... ok
test solution_test::test_deserialize_unicode_packet ... ok
test solution_test::test_full_roundtrip ... ok
test solution_test::test_full_roundtrip_for_zero_size_string ... thread '<unnamed>' panicked at 'Can not deserialize empty bytes slice', src/lib.rs:74:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
FAILED
test solution_test::test_invalid_packet_combination ... ok
test solution_test::test_iterating_packets ... ok
test solution_test::test_iterating_packets_for_zero_size_string ... ok
test solution_test::test_serialize_packet ... ok
test solution_test::test_zero_size ... ok

failures:

---- solution_test::test_full_roundtrip_for_zero_size_string stdout ----
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:378:21


failures:
    solution_test::test_full_roundtrip_for_zero_size_string

test result: FAILED. 14 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out

error: test failed, to rerun pass '--test solution_test'

История (4 версии и 6 коментара)

Ангел качи първо решение на 03.12.2019 00:23 (преди почти 6 години)

Ангел качи решение на 03.12.2019 02:28 (преди почти 6 години)

use std::fmt;
#[derive(Debug)]
pub enum PacketError {
InvalidPacket,
InvalidChecksum,
UnknownProtocolVersion,
CorruptedMessage,
}
impl fmt::Display for PacketError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
PacketError::InvalidPacket => write!(f, "The packet is invalid!"),
PacketError::InvalidChecksum => write!(f, "The checksum is invalid!"),
- PacketError::UnknownProtocolVersion => write!(f, "The protocol version is invalid!"),
+ PacketError::UnknownProtocolVersion => write!(f, "The protocol version is invalid, currently only 1 is supported!"),
PacketError::CorruptedMessage => write!(f, "The reassembled message is not valid UTF-8!"),
}
}
}
impl std::error::Error for PacketError {}
#[derive(PartialEq, Debug)]
pub struct Packet {
size: u8,
- payload: std::vec::Vec<u8>,
+ payload: Vec<u8>,
checksum: u32,
}
impl Packet {
pub fn from_source(source: &[u8], size: u8) -> (Self, &[u8]) {
- if size <= 0 {
- panic!("Size can not be less than or equal to 0!");
+ if size <= 0 || source.len() == 0 {
+ panic!("Packet with size less than or equal to zero can not be created!");
}
let real_size: u8 = {
if source.len() < size as usize {
source.len() as u8
} else {
size
}
};
let payload: Vec<u8> = source[0..real_size as usize].to_vec();
let remaining: &[u8] = &source[real_size as usize..source.len()];
let checksum: u32 = payload.iter().map(|&byte| byte as u32).sum();
(Packet {
size: real_size,
payload: payload,
checksum: checksum,
},
remaining)
}
pub fn payload(&self) -> &[u8] {
&self.payload
}
pub fn serialize(&self) -> Vec<u8> {
let mut vec: Vec<u8> = Vec::new();
vec.push(1);
vec.push(self.size);
vec.extend_from_slice(&self.payload);
vec.extend_from_slice(&self.checksum.to_be_bytes());
+
vec
}
pub fn deserialize(bytes: &[u8]) -> Result<(Packet, &[u8]), PacketError> {
if bytes.len() == 0 {
panic!("Can not deserialize empty bytes slice");
}
if bytes[0] != 1 {
return Err(PacketError::UnknownProtocolVersion);
}
- if bytes.len() < 6 || bytes.len() < (bytes[1] + 6) as usize || bytes[1] == 0 {
+ if bytes.len() <= 6 || bytes.len() < (bytes[1] + 6) as usize || bytes[1] == 0 {
return Err(PacketError::InvalidPacket);
}
let size: usize = bytes[1] as usize;
let vec: Vec<u8> = bytes[2..(size + 2)].to_vec();
let checksum_validate: u32 = bytes[2..(size + 2)].iter().map(|&byte| byte as u32).sum();
let received_checksum: u32 = u32::from_be_bytes([bytes[size + 2], bytes[size + 3], bytes[size + 4], bytes[size + 5]]);
if checksum_validate != received_checksum {
return Err(PacketError::InvalidChecksum);
}
- Ok((Packet {
- size: size as u8,
- payload: vec,
- checksum: received_checksum,
- }, &bytes[(size + 6)..bytes.len()]))
+ Ok(
+ (Packet {
+ size: size as u8,
+ payload: vec,
+ checksum: received_checksum,
+ }, &bytes[(size + 6)..bytes.len()])
+ )
}
}
pub struct PacketSerializer {
- data: std::vec::Vec<u8>,
+ data: Vec<u8>,
packet_size: u8,
}
impl Iterator for PacketSerializer {
type Item = Packet;
fn next(&mut self) -> Option<Self::Item> {
if self.data.len() == 0 {
return None;
}
- let cloned: std::vec::Vec<u8> = self.data.clone();
+ let cloned: Vec<u8> = self.data.clone();
let tuple: (Packet, &[u8]) = Packet::from_source(&cloned, self.packet_size);
self.data = tuple.1.to_vec();
Some(tuple.0)
}
}
pub trait Packetable: Sized {
fn to_packets(&self, packet_size: u8) -> PacketSerializer;
fn to_packet_data(&self, packet_size: u8) -> Vec<u8>;
fn from_packet_data(packet_data: &[u8]) -> Result<Self, PacketError>;
}
impl Packetable for String {
fn to_packets(&self, packet_size: u8) -> PacketSerializer {
let bytes: &[u8] = self.as_bytes();
let size: u8 = {
if bytes.len() <= packet_size as usize {
bytes.len() as u8
} else {
packet_size
}
};
+ // Will return PacketSerializer with size 0, but will
+ // panic when next is called.
PacketSerializer {
data: bytes.to_vec(),
packet_size: size,
}
}
fn to_packet_data(&self, packet_size: u8) -> Vec<u8> {
- let mut data: std::vec::Vec<u8> = Vec::new();
+ let mut data: Vec<u8> = Vec::new();
for packet in self.to_packets(packet_size) {
data.extend(packet.serialize());
}
data
}
fn from_packet_data(packet_data: &[u8]) -> Result<Self, PacketError> {
- let mut deserialized: std::vec::Vec<u8> = Vec::new();
+ let mut deserialized: Vec<u8> = Vec::new();
let mut tuple: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(packet_data);
let mut next_data: &[u8] = match tuple {
Err(x) => return Err(x),
Ok(y) => {
deserialized.extend(y.0.payload);
y.1
},
};
while next_data.len() > 0 {
tuple = Packet::deserialize(next_data);
match tuple {
Err(x) => return Err(x),
Ok(y) => {
deserialized.extend(y.0.payload);
next_data = y.1;
},
};
}
match String::from_utf8(deserialized) {
Err(_) => Err(PacketError::CorruptedMessage),
Ok(x) => Ok(x),
}
}
}

Ангел качи решение на 03.12.2019 02:30 (преди почти 6 години)

use std::fmt;
#[derive(Debug)]
pub enum PacketError {
InvalidPacket,
InvalidChecksum,
UnknownProtocolVersion,
CorruptedMessage,
}
impl fmt::Display for PacketError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
PacketError::InvalidPacket => write!(f, "The packet is invalid!"),
PacketError::InvalidChecksum => write!(f, "The checksum is invalid!"),
PacketError::UnknownProtocolVersion => write!(f, "The protocol version is invalid, currently only 1 is supported!"),
PacketError::CorruptedMessage => write!(f, "The reassembled message is not valid UTF-8!"),
}
}
}
impl std::error::Error for PacketError {}
#[derive(PartialEq, Debug)]
pub struct Packet {
size: u8,
payload: Vec<u8>,
checksum: u32,
}
impl Packet {
pub fn from_source(source: &[u8], size: u8) -> (Self, &[u8]) {
if size <= 0 || source.len() == 0 {
panic!("Packet with size less than or equal to zero can not be created!");
}
let real_size: u8 = {
if source.len() < size as usize {
source.len() as u8
} else {
size
}
};
let payload: Vec<u8> = source[0..real_size as usize].to_vec();
let remaining: &[u8] = &source[real_size as usize..source.len()];
let checksum: u32 = payload.iter().map(|&byte| byte as u32).sum();
(Packet {
size: real_size,
payload: payload,
checksum: checksum,
},
remaining)
}
pub fn payload(&self) -> &[u8] {
&self.payload
}
pub fn serialize(&self) -> Vec<u8> {
let mut vec: Vec<u8> = Vec::new();
vec.push(1);
vec.push(self.size);
vec.extend_from_slice(&self.payload);
vec.extend_from_slice(&self.checksum.to_be_bytes());
vec
}
pub fn deserialize(bytes: &[u8]) -> Result<(Packet, &[u8]), PacketError> {
if bytes.len() == 0 {
panic!("Can not deserialize empty bytes slice");
}
if bytes[0] != 1 {
return Err(PacketError::UnknownProtocolVersion);
}
if bytes.len() <= 6 || bytes.len() < (bytes[1] + 6) as usize || bytes[1] == 0 {
return Err(PacketError::InvalidPacket);
}
let size: usize = bytes[1] as usize;
let vec: Vec<u8> = bytes[2..(size + 2)].to_vec();
let checksum_validate: u32 = bytes[2..(size + 2)].iter().map(|&byte| byte as u32).sum();
let received_checksum: u32 = u32::from_be_bytes([bytes[size + 2], bytes[size + 3], bytes[size + 4], bytes[size + 5]]);
if checksum_validate != received_checksum {
return Err(PacketError::InvalidChecksum);
}
Ok(
- (Packet {
- size: size as u8,
- payload: vec,
- checksum: received_checksum,
- }, &bytes[(size + 6)..bytes.len()])
- )
+ (Packet {
+ size: size as u8,
+ payload: vec,
+ checksum: received_checksum,
+ }, &bytes[(size + 6)..bytes.len()])
+ )
}
}
pub struct PacketSerializer {
data: Vec<u8>,
packet_size: u8,
}
impl Iterator for PacketSerializer {
type Item = Packet;
fn next(&mut self) -> Option<Self::Item> {
if self.data.len() == 0 {
return None;
}
let cloned: Vec<u8> = self.data.clone();
let tuple: (Packet, &[u8]) = Packet::from_source(&cloned, self.packet_size);
self.data = tuple.1.to_vec();
Some(tuple.0)
}
}
pub trait Packetable: Sized {
fn to_packets(&self, packet_size: u8) -> PacketSerializer;
fn to_packet_data(&self, packet_size: u8) -> Vec<u8>;
fn from_packet_data(packet_data: &[u8]) -> Result<Self, PacketError>;
}
impl Packetable for String {
fn to_packets(&self, packet_size: u8) -> PacketSerializer {
let bytes: &[u8] = self.as_bytes();
let size: u8 = {
if bytes.len() <= packet_size as usize {
bytes.len() as u8
} else {
packet_size
}
};
- // Will return PacketSerializer with size 0, but will
- // panic when next is called.
+ // Will return PacketSerializer with size 0, but will
+ // panic when next is called.
PacketSerializer {
data: bytes.to_vec(),
packet_size: size,
}
}
fn to_packet_data(&self, packet_size: u8) -> Vec<u8> {
let mut data: Vec<u8> = Vec::new();
for packet in self.to_packets(packet_size) {
data.extend(packet.serialize());
}
data
}
fn from_packet_data(packet_data: &[u8]) -> Result<Self, PacketError> {
let mut deserialized: Vec<u8> = Vec::new();
let mut tuple: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(packet_data);
let mut next_data: &[u8] = match tuple {
Err(x) => return Err(x),
Ok(y) => {
deserialized.extend(y.0.payload);
y.1
},
};
while next_data.len() > 0 {
tuple = Packet::deserialize(next_data);
match tuple {
Err(x) => return Err(x),
Ok(y) => {
deserialized.extend(y.0.payload);
next_data = y.1;
},
};
}
match String::from_utf8(deserialized) {
Err(_) => Err(PacketError::CorruptedMessage),
Ok(x) => Ok(x),
}
}
}

Ангел качи решение на 03.12.2019 12:46 (преди почти 6 години)

use std::fmt;
#[derive(Debug)]
pub enum PacketError {
InvalidPacket,
InvalidChecksum,
UnknownProtocolVersion,
CorruptedMessage,
}
impl fmt::Display for PacketError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
PacketError::InvalidPacket => write!(f, "The packet is invalid!"),
PacketError::InvalidChecksum => write!(f, "The checksum is invalid!"),
PacketError::UnknownProtocolVersion => write!(f, "The protocol version is invalid, currently only 1 is supported!"),
PacketError::CorruptedMessage => write!(f, "The reassembled message is not valid UTF-8!"),
}
}
}
impl std::error::Error for PacketError {}
#[derive(PartialEq, Debug)]
pub struct Packet {
size: u8,
payload: Vec<u8>,
checksum: u32,
}
impl Packet {
pub fn from_source(source: &[u8], size: u8) -> (Self, &[u8]) {
if size <= 0 || source.len() == 0 {
panic!("Packet with size less than or equal to zero can not be created!");
}
let real_size: u8 = {
if source.len() < size as usize {
source.len() as u8
} else {
size
}
};

Няма нужда да използваш различно име -- можеше да е let size = { и този size да скрие оригиналната стойност. По този начин се подсигуряваш, че всякаква употреба на size надолу е правилния размер. Иначе има шанса някой да меши real_size и size и потенциално да допусне тънък бъг.

let payload: Vec<u8> = source[0..real_size as usize].to_vec();
let remaining: &[u8] = &source[real_size as usize..source.len()];
let checksum: u32 = payload.iter().map(|&byte| byte as u32).sum();
(Packet {
size: real_size,
payload: payload,
checksum: checksum,
},
remaining)
}
pub fn payload(&self) -> &[u8] {
&self.payload
}
pub fn serialize(&self) -> Vec<u8> {
let mut vec: Vec<u8> = Vec::new();
vec.push(1);
vec.push(self.size);
vec.extend_from_slice(&self.payload);
vec.extend_from_slice(&self.checksum.to_be_bytes());
vec
}
pub fn deserialize(bytes: &[u8]) -> Result<(Packet, &[u8]), PacketError> {
if bytes.len() == 0 {
panic!("Can not deserialize empty bytes slice");
}
if bytes[0] != 1 {
return Err(PacketError::UnknownProtocolVersion);
}
if bytes.len() <= 6 || bytes.len() < (bytes[1] + 6) as usize || bytes[1] == 0 {
return Err(PacketError::InvalidPacket);
}
let size: usize = bytes[1] as usize;
let vec: Vec<u8> = bytes[2..(size + 2)].to_vec();
let checksum_validate: u32 = bytes[2..(size + 2)].iter().map(|&byte| byte as u32).sum();
let received_checksum: u32 = u32::from_be_bytes([bytes[size + 2], bytes[size + 3], bytes[size + 4], bytes[size + 5]]);
if checksum_validate != received_checksum {
return Err(PacketError::InvalidChecksum);
}
Ok(
(Packet {
size: size as u8,
payload: vec,
checksum: received_checksum,
}, &bytes[(size + 6)..bytes.len()])
)
}
}
pub struct PacketSerializer {
data: Vec<u8>,
packet_size: u8,
}
impl Iterator for PacketSerializer {
type Item = Packet;
fn next(&mut self) -> Option<Self::Item> {
if self.data.len() == 0 {
return None;
}
let cloned: Vec<u8> = self.data.clone();
let tuple: (Packet, &[u8]) = Packet::from_source(&cloned, self.packet_size);

Вместо да вземаш tuple и после да достъпваш елементите с tuple.1 и tuple.0 (които не са много ясни имена), можеше да дефинираш две променливи с присвояването:

let (packet, remainder) = Packet::from_source(&cloned, self.packet_size);
self.data = remainder.to_vec();
Some(packet)

Освен това не мисля, че е нужно да клонираш self.data -- Packet::from_source си очаква reference, взема назаем стойността на self.data. Мисля, че можеше да подадеш директно &self.data и щеше да сработи.

self.data = tuple.1.to_vec();
Some(tuple.0)
}
}
pub trait Packetable: Sized {
fn to_packets(&self, packet_size: u8) -> PacketSerializer;
fn to_packet_data(&self, packet_size: u8) -> Vec<u8>;
fn from_packet_data(packet_data: &[u8]) -> Result<Self, PacketError>;
}
impl Packetable for String {
fn to_packets(&self, packet_size: u8) -> PacketSerializer {
let bytes: &[u8] = self.as_bytes();
let size: u8 = {
if bytes.len() <= packet_size as usize {
bytes.len() as u8
} else {
packet_size
}
};
// Will return PacketSerializer with size 0, but will
// panic when next is called.
PacketSerializer {
data: bytes.to_vec(),
packet_size: size,
}
}
fn to_packet_data(&self, packet_size: u8) -> Vec<u8> {
let mut data: Vec<u8> = Vec::new();
for packet in self.to_packets(packet_size) {
data.extend(packet.serialize());
}
data
}
fn from_packet_data(packet_data: &[u8]) -> Result<Self, PacketError> {
let mut deserialized: Vec<u8> = Vec::new();
let mut tuple: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(packet_data);
let mut next_data: &[u8] = match tuple {
Err(x) => return Err(x),
Ok(y) => {
deserialized.extend(y.0.payload);
y.1
},
};

Тук и по-долу можеше да използваш оператора ? за да избегнеш Err(x) => return Err(x):

let tuple: (Packet, &[u8]) = Packet::deserialize(packet_data)?;
deserialized.extend(tuple.0.payload);
let mut next_data = tuple.1;

И както казах по-горе, можеше и да pattern-match-неш компонентите на tuple.

while next_data.len() > 0 {
tuple = Packet::deserialize(next_data);
match tuple {
Err(x) => return Err(x),
Ok(y) => {
deserialized.extend(y.0.payload);
next_data = y.1;
},
};
}
match String::from_utf8(deserialized) {
Err(_) => Err(PacketError::CorruptedMessage),
Ok(x) => Ok(x),
}
}
+}
+
+#[test]
+fn test_serialization_basic_small_size() {
+ let string_value = String::from("aba");
+ let source: &[u8] = string_value.as_bytes();
+ let tuple: (Packet, &[u8]) = Packet::from_source(source, 1);
+ assert_eq!(tuple.0.payload(), [97]);
+ assert_eq!(tuple.1, [98, 97]);
+}
+
+#[test]
+fn test_serialization_basic_larger_size() {
+ let string_value = String::from("aba");
+ let source: &[u8] = string_value.as_bytes();
+ let tuple: (Packet, &[u8]) = Packet::from_source(source, 122);
+ assert_eq!(tuple.0.payload(), [97, 98, 97]);
+ assert_eq!(tuple.1, []);
+}
+
+
+#[test]
+#[should_panic]
+fn test_serialization_empty() {
+ let _tuple: (Packet, &[u8]) = Packet::from_source(&[], 1);
+}
+
+#[test]
+fn test_serialization_iterations() {
+ let string_value = String::from("баба");
+ let source: &[u8] = string_value.as_bytes();
+ let tuple: (Packet, &[u8]) = Packet::from_source(source, 3);
+ assert_eq!(tuple.0.payload(), [208, 177, 208]);
+ assert_eq!(tuple.1, [176, 208, 177, 208, 176]);
+ let tuple: (Packet, &[u8]) = Packet::from_source(tuple.1, 3);
+ assert_eq!(tuple.0.payload(), [176, 208, 177]);
+ assert_eq!(tuple.1, [208, 176]);
+
+ let tuple: (Packet, &[u8]) = Packet::from_source(tuple.1, 3);
+ assert_eq!(tuple.0.payload(), [208, 176]);
+ assert_eq!(tuple.1, []);
+}
+
+// serialize method
+#[test]
+fn test_serialize() {
+ let string_value = String::from("баба");
+ let source: &[u8] = string_value.as_bytes();
+ let tuple: (Packet, &[u8]) = Packet::from_source(source, 3);
+ assert_eq!(tuple.0.payload(), [208, 177, 208]);
+ assert_eq!(tuple.1, [176, 208, 177, 208, 176]);
+
+ let vec: Vec<u8> = tuple.0.serialize();
+ assert_eq!(vec, [1, 3, 208, 177, 208, 0, 0, 2, 81]);
+}
+
+// deserialize
+#[test]
+#[should_panic]
+fn test_empty_slice_deserialization() {
+ let _res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[]);
+}
+
+#[test]
+fn test_complete_deserialization() {
+ let res: (Packet, &[u8]) = Packet::deserialize(&[1, 3, 208, 177, 208, 0, 0, 2, 81]).unwrap();
+ assert_eq!(res.0.payload(), [208, 177, 208]);
+ assert_eq!(res.1, []);
+}
+
+#[test]
+fn test_incomplete_deserialization() {
+ let res: (Packet, &[u8]) = Packet::deserialize(&[1, 3, 208, 177, 208, 0, 0, 2, 81, 1, 1, 21, 0, 0, 0, 21]).unwrap();
+ assert_eq!(res.0.payload(), [208, 177, 208]);
+ assert_eq!(res.1, [1, 1, 21, 0, 0, 0, 21]);
+}
+
+#[test]
+fn test_deserialize_unknown_version_error() {
+ let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[2, 3, 208, 177, 208, 0, 0, 2, 81, 1, 1, 21, 0, 0, 0, 21]);
+
+ if let Err(PacketError::UnknownProtocolVersion) = res {
+ assert!(true);
+ } else {
+ assert!(false, "Unknown protocol version expected");
+ }
+}

Едно помощно средство, което аз написах за тестовете:

macro_rules! assert_match {
    ($expr:expr, $pat:pat) => {
        if let $pat = $expr {
            // all good
        } else {
            assert!(false, "Expression {:?} does not match the pattern {:?}", $expr, stringify!($pat));
        }
    }
}

По този начин, можеш да напишеш този тест по-просто така:

assert_match!(Packet::deserialize(&data), Err(PacketError::UnknownProtocolVersion));

И ако теста не проработи, ще получиш по-ясна грешка.

+
+#[test]
+fn test_deserialize_invalid_checksum() {
+ let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 3, 208, 177, 208, 0, 0, 3, 81, 1, 1, 21, 0, 0, 0, 21]);
+
+ if let Err(PacketError::InvalidChecksum) = res {
+ assert!(true);
+ } else {
+ assert!(false, "Invalid checksum expected");
+ }
+}
+
+#[test]
+fn test_deserialize_packet_with_size_0() {
+ let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 0, 208, 177, 208, 0, 0, 1, 81, 1, 1, 21, 0, 0, 0, 21]);
+
+ if let Err(PacketError::InvalidPacket) = res {
+ assert!(true);
+ } else {
+ assert!(false, "Invalid packet expected");
+ }
+}
+
+#[test]
+fn test_deserialize_missing_checksum() {
+ let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 13, 208, 177, 208, 0, 0, 1, 81, 1, 1, 21, 0, 0, 0, 21]);
+
+ if let Err(PacketError::InvalidPacket) = res {
+ assert!(true);
+ } else {
+ assert!(false, "Invalid packet expected");
+ }
+}
+
+#[test]
+fn test_deserialize_overflow_size() {
+ let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 20, 208, 177, 208, 0, 0, 1, 81, 1, 1, 21, 0, 0, 0, 21]);
+
+ if let Err(PacketError::InvalidPacket) = res {
+ assert!(true);
+ } else {
+ assert!(false, "Invalid packet expected");
+ }
+}
+
+#[test]
+fn test_deserialize_invalid_checksum_because_of_wrong_size() {
+ let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 4, 208, 177, 208, 0, 0, 2, 81, 1, 1, 21, 0, 0, 0, 21]);
+
+ if let Err(PacketError::InvalidChecksum) = res {
+ assert!(true);
+ } else {
+ assert!(false, "Invalid checksum expected");
+ }
+}
+
+#[test]
+fn test_deserialize_too_small_slices() {
+ // let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[]); should panic
+ let res1: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1]);
+ let res2: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 1]);
+ let res3: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 1, 1]);
+ let res4: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 1, 1, 0]);
+ let res5: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 1, 1, 0, 1]);
+ let res6: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 0, 0, 0, 0, 0]); // the biggest invalid small slice
+
+ if let Err(PacketError::InvalidPacket) = res1 {
+ assert!(true);
+ } else {
+ assert!(false, "Invalid packet expected");
+ }
+
+ if let Err(PacketError::InvalidPacket) = res2 {
+ assert!(true);
+ } else {
+ assert!(false, "Invalid packet expected");
+ }
+
+ if let Err(PacketError::InvalidPacket) = res3 {
+ assert!(true);
+ } else {
+ assert!(false, "Invalid packet expected");
+ }
+
+ if let Err(PacketError::InvalidPacket) = res4 {
+ assert!(true);
+ } else {
+ assert!(false, "Invalid packet expected");
+ }
+
+ if let Err(PacketError::InvalidPacket) = res5 {
+ assert!(true);
+ } else {
+ assert!(false, "Invalid packet expected");
+ }
+
+ if let Err(PacketError::InvalidPacket) = res6 {
+ assert!(true);
+ } else {
+ assert!(false, "Invalid packet expected");
+ }
+}
+
+#[test]
+fn test_deserialize_the_smallest_packet() {
+ let res: Result<(Packet, &[u8]), PacketError> = Packet::deserialize(&[1, 1, 1, 0, 0, 0, 1]);
+ assert_eq!(res.is_err(), false);
+ let res = res.unwrap();
+ assert_eq!(res.0.payload(), [1]);
+ assert_eq!(res.1, []);
+}
+
+#[test]
+fn test_next_on_empty_iterator() {
+ assert_eq!(String::new().to_packets(10).next(), None);
+}
+
+
+// test packetable
+#[test]
+fn test_basic_packets() {
+ let source = b"hello";
+ let (packet, remainder) = Packet::from_source(source, 100);
+
+ assert_eq!(packet.payload().len(), source.len());
+ assert_eq!(remainder, b"");
+ assert!(packet.serialize().len() > 0);
+
+ if let Err(_) = Packet::deserialize(&packet.serialize()) {
+ assert!(false, "Couldn't deserialize packet data");
+ }
+}
+
+#[test]
+fn test_basic_iteration() {
+ let source = String::from("hello");
+ let packets = source.to_packets(100).collect::<Vec<Packet>>();
+ assert!(packets.len() > 0);
+
+ let data = source.to_packet_data(100);
+ assert!(data.len() > 0);
+
+ if let Err(_) = String::from_packet_data(&data) {
+ assert!(false, "Couldn't deserialize packet data");
+ }
+}
+
+#[test]
+fn test_basic_multiple_packets() {
+ let source = String::from("hello");
+ let packets = source.to_packets(1).collect::<Vec<Packet>>();
+ assert!(packets.len() == 5);
+
+ let data = source.to_packet_data(1);
+ assert!(data.len() == 35); // each packet is 1 1 x b3 b2 b1 b0 -> 7, 7*5 = 35
+
+ if let Err(_) = String::from_packet_data(&data) {
+ assert!(false, "Couldn't deserialize packet data");
+ }
+
+ if let Ok(x) = String::from_packet_data(&data) {
+ assert_eq!(x, source);
+ }
+}
+
+#[test]
+fn test_basic_multibyte() {
+ let source = String::from("баба");
+ let packets = source.to_packets(2).collect::<Vec<Packet>>();
+ assert!(packets.len() == 4);
+
+ let data = source.to_packet_data(2);
+ assert_eq!(32, data.len()); // 1 2 x y b3 b2 b1 b0 -> 4*8 = 32
+
+ let res = String::from_packet_data(&data);
+
+ if let Err(_) = res {
+ assert!(false, "Couldn't deserialize serialized packet data");
+ }
+
+ if let Ok(x) = res {
+ assert_eq!(x, source);
+ }
+}
+
+#[test]
+fn test_basic_packets_bigger_size() {
+ let source = String::from("hello");
+ let packets = source.to_packets(12).collect::<Vec<Packet>>();
+ assert!(packets.len() == 1);
+
+ let data = source.to_packet_data(12);
+ assert!(data.len() == 11); // 1 5 x y z t s b3 b2 b1 b0
+
+ if let Err(_) = String::from_packet_data(&data) {
+ assert!(false, "Couldn't deserialize serialized packet data");
+ }
+
+ if let Ok(x) = String::from_packet_data(&data) {
+ assert_eq!(x, source);
+ }
+}
+
+#[test]
+fn test_empty_string() {
+ let source = String::from("");
+ let packets = source.to_packets(10).collect::<Vec<Packet>>();
+ assert_eq!(0, packets.len());
+
+ let data = source.to_packet_data(12);
+ assert_eq!(0, data.len());
+}
+
+// deserialize
+#[test]
+#[should_panic]
+fn test_empty_string_deserialize() {
+ let source = String::from("");
+ let packets = source.to_packets(10).collect::<Vec<Packet>>();
+ assert_eq!(0, packets.len());
+
+ let data = source.to_packet_data(12);
+ assert_eq!(0, data.len());
+
+ let _res = String::from_packet_data(&data); // data is empty
+}
+
+#[test]
+fn test_basic_multibyte_2() {
+ let source = String::from("АСДФГ");
+ let packets = source.to_packets(10).collect::<Vec<Packet>>();
+ assert_eq!(1, packets.len());
+
+ let data = source.to_packet_data(10);
+ assert!(data.len() == 16);
+
+ if let Err(_) = String::from_packet_data(&data) {
+ assert!(false, "Couldn't deserialize serialized packet data");
+ }
+
+ if let Ok(x) = String::from_packet_data(&data) {
+ assert_eq!(x, source);
+ }
+}
+
+#[test]
+fn test_complex_mutlibyte() {
+ let source = String::from("АСАддассАСдHHHHHjsjasdасАсдАсдасдСДФГАСʥʥАдассАСдасАдасАсдАсдасдСДФГ");
+ let packets = source.to_packets(10).collect::<Vec<Packet>>();
+ assert!(packets.len() > 10);
+
+ let data = source.to_packet_data(10);
+ assert!(data.len() > 50);
+
+ if let Err(_) = String::from_packet_data(&data) {
+ assert!(false, "Couldn't deserialize serialized packet data");
+ }
+
+ if let Ok(x) = String::from_packet_data(&data) {
+ assert_eq!(x, source);
+ }
+}
+
+// test error propagation
+#[test]
+fn test_deserialize_unknown_version_string() {
+
+ let deserialized = String::from_packet_data(&[12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11]);
+
+ if let Err(PacketError::UnknownProtocolVersion) = deserialized {
+ assert!(true);
+ } else {
+ assert!(false, "Unknown protocol version error expected");
+ }
+}
+
+#[test]
+fn test_deserialize_basic_packet() {
+
+ let deserialized = String::from_packet_data(&[1, 2, 1, 3, 0, 0, 0, 4]);
+
+ if let Ok(_x) = deserialized {
+ assert!(true);
+ } else {
+ assert!(false, "Couldn't deserialize serialized packet data");
+ }
+}
+
+#[test]
+fn test_deserialize_invalid_packet() {
+
+ let deserialized = String::from_packet_data(&[1, 2, 1, 3, 0, 0, 0]);
+
+ if let Err(PacketError::InvalidPacket) = deserialized {
+ assert!(true);
+ } else {
+ assert!(false, "Invalid packet error expected!");
+ }
+}
+
+#[test]
+fn test_corrupted_message_invalid_sparkle() {
+
+ let deserialized = String::from_packet_data(&[1, 4, 0, 159, 146, 150, 0, 0, 0b00000001, 0b11000111]); // 455
+
+ if let Err(PacketError::CorruptedMessage) = deserialized {
+ assert!(true);
+ } else {
+ assert!(false, "Corrupted message error expected!");
+ }
+}
+
+#[test]
+fn test_sparkle() {
+ let deserialized = String::from_packet_data(&[1, 4, 240, 159, 146, 150, 0, 0, 0b00000010, 0b10110111]); // 695 checksum
+
+ if let Ok(x) = deserialized {
+ assert_eq!("💖", x);
+ } else {
+ assert!(false, "Couldn't deserialize data");
+ }
+}
+
+
+#[test]
+fn test_invalid_checksum() {
+ let deserialized = String::from_packet_data(&[1, 4, 240, 159, 146, 150, 0, 0, 0b00010010, 0b10110111]);
+
+ if let Err(PacketError::InvalidChecksum) = deserialized {
+ assert!(true);
+ } else {
+ assert!(false, "Invalid checksum error expected");
+ }
+}
+
+#[test]
+fn test_empty_string_for_to_packet_data() {
+ let empty_vector: Vec<u8> = vec![];
+ assert_eq!(empty_vector, String::new().to_packet_data(10));
+}
+
+#[test]
+#[should_panic]
+fn test_size_zero_for_to_packet_data() {
+ String::from("asd").to_packet_data(0);
+}
+
+#[test]
+fn test_large_multibyte_string() {
+
+ let str = String::from("ʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥʥ");
+ let packets = str.to_packets(10).collect::<Vec<Packet>>();
+ assert!(packets.len() > 22);
+
+ let data = str.to_packet_data(10);
+ assert!(data.len() > 50);
+
+ if let Err(_) = String::from_packet_data(&data) {
+ assert!(false, "Couldn't deserialize serialized packet data");
+ }
+
+ if let Ok(x) = String::from_packet_data(&data) {
+ assert_eq!(x, str);
+ }
}

Добро решение, и ще ти дам бонус точка за обстойните тестове. Мисля си, че даже може би си написал повече тестове, отколкото си заслужава, но това е въпрос на интуиция, и обикновено повече тестове е по-добре от по-малко :).

Има някои езикови конструкции, с които би могъл да си съкратиш кода и вероятно да го направиш и по-четим -- хвърли им по едно око.