Решение на Network Packets от Антон Чернев

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

Към профила на Антон Чернев

Резултати

  • 20 точки от тестове
  • 0 бонус точки
  • 20 точки общо
  • 15 успешни тест(а)
  • 0 неуспешни тест(а)

Код

use std::cmp::min;
use std::convert::TryInto;
use std::fmt;
use std::str;
#[derive(PartialEq, Debug)]
pub enum PacketError {
InvalidPacket,
InvalidChecksum,
UnknownProtocolVersion,
CorruptedMessage,
}
impl fmt::Display for PacketError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let message: &str = match self {
PacketError::InvalidPacket => "Invalid Packet",
PacketError::InvalidChecksum => "Invalid Checksum",
PacketError::UnknownProtocolVersion => "Unknown Protocol Version",
PacketError::CorruptedMessage => "Corrupted Message"
};
write!(f, "{}", message)
}
}
impl std::error::Error for PacketError {}
#[derive(PartialEq, Debug)]
pub struct Packet<'a> {
bytes: &'a[u8]
}
impl<'a> Packet<'a> {
const VERSION: u8 = 1;
pub fn from_source(source: &'a[u8], size: u8) -> (Self, &'a[u8]) {
if size <= 0 {
panic!();
}
let length = min(source.len(), size as usize);
let (bytes, rest) = source.split_at(length);
(Self { bytes }, rest)
}
pub fn payload(&self) -> &'a[u8] {
self.bytes
}
pub fn serialize(&self) -> Vec<u8> {
let mut bytes: Vec<u8> = Vec::new();
bytes.push(Self::VERSION);
bytes.push(self.bytes.len() as u8);
let mut checksum: u32 = 0;
for byte in self.bytes {
bytes.push(*byte);
checksum += (*byte) as u32;
};
bytes.extend_from_slice(&checksum.to_be_bytes());
bytes
}
pub fn deserialize(bytes: &'a[u8]) -> Result<(Self, &'a[u8]), PacketError> {
let mut iter = bytes.iter();
match iter.next() {
None => return Err(PacketError::InvalidPacket),
Some(1) => (),
_ => return Err(PacketError::UnknownProtocolVersion)
};
let size = match iter.next() {
None => return Err(PacketError::InvalidPacket),
Some(size) => *size as usize
};
let bytes = iter.as_slice();
if bytes.len() < size {
return Err(PacketError::InvalidPacket);
}
let (payload, bytes) = bytes.split_at(size);
let mut checksum: u32 = 0;
for byte in payload {
checksum += *byte as u32;
}
if bytes.len() < 4 {
return Err(PacketError::InvalidPacket)
}
let (checksum_bytes, rest) = bytes.split_at(4);
if u32::from_be_bytes(checksum_bytes.try_into().unwrap()) != checksum {
return Err(PacketError::InvalidChecksum)
}
Ok((Self { bytes: payload }, rest))
}
}
pub struct PacketSerializer<'a> {
packet_size: u8,
bytes: &'a[u8]
}
impl<'a> Iterator for PacketSerializer<'a> {
type Item = Packet<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.bytes.len() == 0 {
return None;
}
let (packet, rest) = Packet::from_source(self.bytes, self.packet_size);
self.bytes = rest;
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 { bytes: self.as_bytes(), packet_size }
}
fn to_packet_data(&self, packet_size: u8) -> Vec<u8> {
let mut bytes: Vec<u8> = Vec::new();
for packet in self.to_packets(packet_size) {
bytes.extend(packet.serialize());
}
bytes
}
fn from_packet_data(mut packet_data: &[u8]) -> Result<Self, PacketError> {
let mut message = Vec::new();
while packet_data.len() > 0 {
let (packet, rest) = Packet::deserialize(packet_data)?;
message.extend_from_slice(packet.payload());
packet_data = rest;
}
match str::from_utf8(&message[..]) {
Err(_) => Err(PacketError::CorruptedMessage),
Ok(data) => Ok(String::from(data))
}
}
}

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

Compiling solution v0.1.0 (/tmp/d20200111-2173579-815z2f/solution)
    Finished test [unoptimized + debuginfo] target(s) in 3.72s
     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 ... 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 ... ok
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

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

   Doc-tests solution

running 0 tests

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

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

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

Антон качи решение на 03.12.2019 01:11 (преди почти 6 години)

use std::cmp::min;
use std::convert::TryInto;
use std::fmt;
use std::str;
#[derive(PartialEq, Debug)]
pub enum PacketError {
InvalidPacket,
InvalidChecksum,
UnknownProtocolVersion,
CorruptedMessage,
}
impl fmt::Display for PacketError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let message: &str = match self {
PacketError::InvalidPacket => "Invalid Packet",
PacketError::InvalidChecksum => "Invalid Checksum",
PacketError::UnknownProtocolVersion => "Unknown Protocol Version",
PacketError::CorruptedMessage => "Corrupted Message"
};
write!(f, "{}", message)
}
}
impl std::error::Error for PacketError {}
#[derive(PartialEq, Debug)]
pub struct Packet<'a> {
bytes: &'a[u8]
}
impl<'a> Packet<'a> {
const VERSION: u8 = 1;
pub fn from_source(source: &'a[u8], size: u8) -> (Self, &'a[u8]) {
if size <= 0 {
panic!();
}
let length = min(source.len(), size as usize);
let (bytes, rest) = source.split_at(length);
(Self { bytes }, rest)
}
pub fn payload(&self) -> &'a[u8] {
self.bytes
}
pub fn serialize(&self) -> Vec<u8> {
let mut bytes: Vec<u8> = Vec::new();
bytes.push(Self::VERSION);
bytes.push(self.bytes.len() as u8);
let mut checksum: u32 = 0;
for byte in self.bytes {
bytes.push(*byte);
checksum += (*byte) as u32;
};
bytes.extend_from_slice(&checksum.to_be_bytes());
bytes
}
pub fn deserialize(bytes: &'a[u8]) -> Result<(Self, &'a[u8]), PacketError> {
let mut iter = bytes.iter();
match iter.next() {
None => return Err(PacketError::InvalidPacket),
Some(1) => (),
_ => return Err(PacketError::UnknownProtocolVersion)
};
let size = match iter.next() {
None => return Err(PacketError::InvalidPacket),
Some(size) => *size as usize
};
let bytes = iter.as_slice();
if bytes.len() < size {
return Err(PacketError::InvalidPacket);
}
let (payload, bytes) = bytes.split_at(size);
let mut checksum: u32 = 0;
for byte in payload {
checksum += *byte as u32;
}
if bytes.len() < 4 {
return Err(PacketError::InvalidPacket)
}
let (checksum_bytes, rest) = bytes.split_at(4);
if u32::from_be_bytes(checksum_bytes.try_into().unwrap()) != checksum {
return Err(PacketError::InvalidChecksum)
}
Ok((Self { bytes: payload }, rest))
}
}
pub struct PacketSerializer<'a> {
packet_size: u8,
bytes: &'a[u8]
}
impl<'a> Iterator for PacketSerializer<'a> {
type Item = Packet<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.bytes.len() == 0 {
return None;
}
let (packet, rest) = Packet::from_source(self.bytes, self.packet_size);
self.bytes = rest;
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 { bytes: self.as_bytes(), packet_size }
}
fn to_packet_data(&self, packet_size: u8) -> Vec<u8> {
let mut bytes: Vec<u8> = Vec::new();
for packet in self.to_packets(packet_size) {
bytes.extend(packet.serialize());
}
bytes
}
fn from_packet_data(mut packet_data: &[u8]) -> Result<Self, PacketError> {
- let mut message = String::new();
+ let mut message = Vec::new();
while packet_data.len() > 0 {
let (packet, rest) = Packet::deserialize(packet_data)?;
- message.push_str(match str::from_utf8(packet.payload()) {
- Err(_) => return Err(PacketError::CorruptedMessage),
- Ok(payload) => payload
- });
+ message.extend_from_slice(packet.payload());
packet_data = rest;
}
- Ok(message)
+ match str::from_utf8(&message[..]) {
+ Err(_) => Err(PacketError::CorruptedMessage),
+ Ok(data) => Ok(String::from(data))
+ }
}
}