Решение на Network Packets от Парашкев Катерски

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

Към профила на Парашкев Катерски

Резултати

  • 17 точки от тестове
  • 0 бонус точки
  • 17 точки общо
  • 13 успешни тест(а)
  • 2 неуспешни тест(а)

Код

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 {
Self::InvalidPacket => write!(f, "invalid packet"),
Self::InvalidChecksum => write!(f, "invalid checksum"),
Self::UnknownProtocolVersion => write!(f, "unknown protocol version"),
Self::CorruptedMessage => write!(f, "corrupted message"),
}
}
}
impl std::error::Error for PacketError {}
#[derive(PartialEq, Debug)]
pub struct Packet<'a> {
version: u8,
payload: &'a [u8],
}
impl<'a> Packet<'a> {
pub fn from_source(source: &'a [u8], size: u8) -> (Self, &'a [u8]) {
if size == 0 {panic!("Ivane!");}
let size = if size as usize <= source.len() {size} else {source.len() as u8};
(
Packet {payload : &source[0..size as usize], version:1u8},
&source[size as usize..],
)
}
pub fn payload(&self) -> &[u8] {
self.payload
}
pub fn serialize(&self) -> Vec<u8> {
let mut ser = self.payload.to_vec();
let size = self.payload.len() as u8;
ser.extend( ser
.iter()
.map(|c|{*c as u32})
.sum::<u32>()
.to_be_bytes()
.to_vec() );
ser.push(self.version);
ser.push(size);
ser.rotate_left(size as usize + 4);
ser
}
pub fn deserialize(bytes: &[u8]) -> Result<(Packet, &[u8]), PacketError> {
use std::convert::TryInto;
if bytes.len() < 6 {
return Err(PacketError::InvalidPacket);
}
let version = bytes[0];
let size = bytes[1] as usize;
if version != 1u8 {
return Err(PacketError::UnknownProtocolVersion);
} else if size > bytes.len() {
return Err(PacketError::InvalidPacket);
}
let payload = &bytes[2..size+2];
let checksum= u32::from_be_bytes(bytes[size+2..size+6].try_into().unwrap());
let my_checksum: u32 = bytes[2..size+2].iter().map(|x|{*x as u32}).sum();
if checksum != my_checksum {
return Err(PacketError::InvalidChecksum);
}
Ok((Packet {payload: payload, version}, &bytes[size+6..]))
}
}
pub struct PacketSerializer<'a> {
message: &'a [u8],
packet_size: u8,
}
impl<'a> Iterator for PacketSerializer<'a> {
type Item = Packet<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.message.len() == 0 {
return None;
}
let (packet, message) = Packet::from_source(self.message, self.packet_size);
self.message = message;
Some(packet)
}
}
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 {
PacketSerializer { message: self.as_bytes(), packet_size }
}
fn to_packet_data(&self, packet_size: u8) -> Vec<u8> {
self.to_packets(packet_size)
.map(|p|{p.serialize()})
.fold(Vec::<u8>::new(), |mut acc, x| {acc.extend(x); acc})
}
fn from_packet_data(packet_data: &[u8]) -> Result<Self, PacketError> {
use std::str;
let mut remainder = packet_data;
let mut result = Vec::<u8>::new();
loop {
let (packet, new_remainder) = Packet::deserialize(remainder)?;
remainder = new_remainder;
result.extend(packet.payload.to_vec());
if remainder.len() == 0 {
break;
}
}
let res = str::from_utf8(&result)?;
Ok(res.to_string())
}
}
impl From<std::str::Utf8Error> for PacketError {
fn from(_: std::str::Utf8Error) -> Self {
PacketError::CorruptedMessage
}
}

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

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

running 0 tests

test result: ok. 0 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 ... FAILED
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 'called `Result::unwrap()` on an `Err` value: InvalidPacket', src/libcore/result.rs:1165:5
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_deserialize_invalid_packet stdout ----
thread 'main' panicked at 'index 10 out of range for slice of length 9', src/libcore/slice/mod.rs:2664:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

---- solution_test::test_full_roundtrip_for_zero_size_string stdout ----
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: InvalidPacket', tests/solution_test.rs:221:5


failures:
    solution_test::test_deserialize_invalid_packet
    solution_test::test_full_roundtrip_for_zero_size_string

test result: FAILED. 13 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out

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

История (1 версия и 2 коментара)

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