Решение на Network Packets от Моника Киркова
Резултати
- 5 точки от тестове
- 0 бонус точки
- 5 точки общо
- 4 успешни тест(а)
- 11 неуспешни тест(а)
Код
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20200111-2173579-1rnz1dw/solution) warning: unused import: `std::convert::TryInto` --> src/lib.rs:3:5 | 3 | use std::convert::TryInto; | ^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default warning: unnecessary parentheses around `if` condition --> src/lib.rs:89:11 | 89 | if(bytes.len() < 7 || (packet.size as usize) > packet.payload.len()){ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses | = note: `#[warn(unused_parens)]` on by default warning: unnecessary parentheses around `if` condition --> src/lib.rs:91:18 | 91 | }else if (packet.version != 1){ | ^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses warning: unnecessary parentheses around `if` condition --> src/lib.rs:93:18 | 93 | }else if (packet.checksum != sumCheck){ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses warning: unnecessary parentheses around `if` condition --> src/lib.rs:95:17 | 95 | }else if((packet.size as usize) < packet.payload.len()){ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses warning: unnecessary parentheses around `if` condition --> src/lib.rs:115:11 | 115 | if(self.bytes.len() == 0){ | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses warning: unnecessary parentheses around `if` condition --> src/lib.rs:143:15 | 143 | if(check.is_none()){ | ^^^^^^^^^^^^^^^^^ help: remove these parentheses warning: unnecessary parentheses around assigned value --> src/lib.rs:159:25 | 159 | let error = (Packet::deserialize(bytes)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses warning: unnecessary parentheses around assigned value --> src/lib.rs:169:27 | 169 | finalString = (finalString.to_owned() + (str::from_utf8(currPayload).unwrap())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses warning: unused variable: `a` --> src/lib.rs:157:17 | 157 | let mut a = ""; | ^ help: consider prefixing with an underscore: `_a` | = note: `#[warn(unused_variables)]` on by default warning: unused variable: `val` --> src/lib.rs:162:20 | 162 | Ok(val)=>{ | ^^^ help: consider prefixing with an underscore: `_val` warning: variable `sumCheck` is assigned to, but never used --> src/lib.rs:165:21 | 165 | let mut sumCheck : u32 = 0; | ^^^^^^^^ | = note: consider using `_sumCheck` instead warning: variable does not need to be mutable --> src/lib.rs:46:13 | 46 | let mut packet = Packet { | ----^^^^^^ | | | help: remove this `mut` | = note: `#[warn(unused_mut)]` on by default warning: variable does not need to be mutable --> src/lib.rs:142:17 | 142 | let mut check = package.next(); | ----^^^^^ | | | help: remove this `mut` warning: variable does not need to be mutable --> src/lib.rs:157:13 | 157 | let mut a = ""; | ----^ | | | help: remove this `mut` warning: variable does not need to be mutable --> src/lib.rs:163:25 | 163 | let mut packet = &(Packet::deserialize(bytes)).unwrap().0; | ----^^^^^^ | | | help: remove this `mut` warning: variable does not need to be mutable --> src/lib.rs:164:17 | 164 | let mut currPayload = packet.payload; | ----^^^^^^^^^^^ | | | help: remove this `mut` warning: variable `checkBytes` should have a snake case name --> src/lib.rs:78:13 | 78 | let checkBytes: [u8; 4] = [check[0], check[1], check[2], check[3]]; | ^^^^^^^^^^ help: convert the identifier to snake case: `check_bytes` | = note: `#[warn(non_snake_case)]` on by default warning: variable `sumCheck` should have a snake case name --> src/lib.rs:85:17 | 85 | let mut sumCheck : u32 = 0; | ^^^^^^^^ help: convert the identifier to snake case: `sum_check` warning: variable `nextPacket` should have a snake case name --> src/lib.rs:118:13 | 118 | let nextPacket = Packet::from_source(self.bytes, self.packet_size).0; | ^^^^^^^^^^ help: convert the identifier to snake case: `next_packet` warning: variable `vecOfBytes` should have a snake case name --> src/lib.rs:140:17 | 140 | let mut vecOfBytes = Vec::new(); | ^^^^^^^^^^ help: convert the identifier to snake case: `vec_of_bytes` warning: variable `finalString` should have a snake case name --> src/lib.rs:156:17 | 156 | let mut finalString: std::string::String = "".to_string(); | ^^^^^^^^^^^ help: convert the identifier to snake case: `final_string` warning: variable `currPayload` should have a snake case name --> src/lib.rs:164:21 | 164 | let mut currPayload = packet.payload; | ^^^^^^^^^^^ help: convert the identifier to snake case: `curr_payload` warning: variable `sumCheck` should have a snake case name --> src/lib.rs:165:21 | 165 | let mut sumCheck : u32 = 0; | ^^^^^^^^ help: convert the identifier to snake case: `sum_check` warning: unused import: `std::convert::TryInto` --> src/lib.rs:3:5 | 3 | use std::convert::TryInto; | ^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default warning: unnecessary parentheses around `if` condition --> src/lib.rs:89:11 | 89 | if(bytes.len() < 7 || (packet.size as usize) > packet.payload.len()){ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses | = note: `#[warn(unused_parens)]` on by default warning: unnecessary parentheses around `if` condition --> src/lib.rs:91:18 | 91 | }else if (packet.version != 1){ | ^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses warning: unnecessary parentheses around `if` condition --> src/lib.rs:93:18 | 93 | }else if (packet.checksum != sumCheck){ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses warning: unnecessary parentheses around `if` condition --> src/lib.rs:95:17 | 95 | }else if((packet.size as usize) < packet.payload.len()){ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses warning: unnecessary parentheses around `if` condition --> src/lib.rs:115:11 | 115 | if(self.bytes.len() == 0){ | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses warning: unnecessary parentheses around `if` condition --> src/lib.rs:143:15 | 143 | if(check.is_none()){ | ^^^^^^^^^^^^^^^^^ help: remove these parentheses warning: unnecessary parentheses around assigned value --> src/lib.rs:159:25 | 159 | let error = (Packet::deserialize(bytes)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses warning: unnecessary parentheses around assigned value --> src/lib.rs:169:27 | 169 | finalString = (finalString.to_owned() + (str::from_utf8(currPayload).unwrap())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove these parentheses warning: unused variable: `a` --> src/lib.rs:157:17 | 157 | let mut a = ""; | ^ help: consider prefixing with an underscore: `_a` | = note: `#[warn(unused_variables)]` on by default warning: unused variable: `val` --> src/lib.rs:162:20 | 162 | Ok(val)=>{ | ^^^ help: consider prefixing with an underscore: `_val` warning: variable `sumCheck` is assigned to, but never used --> src/lib.rs:165:21 | 165 | let mut sumCheck : u32 = 0; | ^^^^^^^^ | = note: consider using `_sumCheck` instead warning: variable does not need to be mutable --> src/lib.rs:46:13 | 46 | let mut packet = Packet { | ----^^^^^^ | | | help: remove this `mut` | = note: `#[warn(unused_mut)]` on by default warning: variable does not need to be mutable --> src/lib.rs:142:17 | 142 | let mut check = package.next(); | ----^^^^^ | | | help: remove this `mut` warning: variable does not need to be mutable --> src/lib.rs:157:13 | 157 | let mut a = ""; | ----^ | | | help: remove this `mut` warning: variable does not need to be mutable --> src/lib.rs:163:25 | 163 | let mut packet = &(Packet::deserialize(bytes)).unwrap().0; | ----^^^^^^ | | | help: remove this `mut` warning: variable does not need to be mutable --> src/lib.rs:164:17 | 164 | let mut currPayload = packet.payload; | ----^^^^^^^^^^^ | | | help: remove this `mut` warning: variable `checkBytes` should have a snake case name --> src/lib.rs:78:13 | 78 | let checkBytes: [u8; 4] = [check[0], check[1], check[2], check[3]]; | ^^^^^^^^^^ help: convert the identifier to snake case: `check_bytes` | = note: `#[warn(non_snake_case)]` on by default warning: variable `sumCheck` should have a snake case name --> src/lib.rs:85:17 | 85 | let mut sumCheck : u32 = 0; | ^^^^^^^^ help: convert the identifier to snake case: `sum_check` warning: variable `nextPacket` should have a snake case name --> src/lib.rs:118:13 | 118 | let nextPacket = Packet::from_source(self.bytes, self.packet_size).0; | ^^^^^^^^^^ help: convert the identifier to snake case: `next_packet` warning: variable `vecOfBytes` should have a snake case name --> src/lib.rs:140:17 | 140 | let mut vecOfBytes = Vec::new(); | ^^^^^^^^^^ help: convert the identifier to snake case: `vec_of_bytes` warning: variable `finalString` should have a snake case name --> src/lib.rs:156:17 | 156 | let mut finalString: std::string::String = "".to_string(); | ^^^^^^^^^^^ help: convert the identifier to snake case: `final_string` warning: variable `currPayload` should have a snake case name --> src/lib.rs:164:21 | 164 | let mut currPayload = packet.payload; | ^^^^^^^^^^^ help: convert the identifier to snake case: `curr_payload` warning: variable `sumCheck` should have a snake case name --> src/lib.rs:165:21 | 165 | let mut sumCheck : u32 = 0; | ^^^^^^^^ help: convert the identifier to snake case: `sum_check` Finished test [unoptimized + debuginfo] target(s) in 3.76s 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 ... FAILED test solution_test::test_construct_packet_with_remainder ... ok test solution_test::test_construct_packet_with_remainder_cyrillic ... FAILED test solution_test::test_consuming_packets ... thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:378:21 FAILED test solution_test::test_deserialize_invalid_packet ... FAILED test solution_test::test_deserialize_packet ... FAILED test solution_test::test_deserialize_unicode_packet ... FAILED test solution_test::test_full_roundtrip ... thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:378:21 FAILED test solution_test::test_full_roundtrip_for_zero_size_string ... ok test solution_test::test_invalid_packet_combination ... thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:378:21 FAILED test solution_test::test_iterating_packets ... thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:378:21 FAILED test solution_test::test_iterating_packets_for_zero_size_string ... ok test solution_test::test_serialize_packet ... FAILED test solution_test::test_zero_size ... FAILED failures: ---- solution_test::test_construct_packet_no_remainder stdout ---- thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:378:21 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. ---- solution_test::test_construct_packet_with_remainder_cyrillic stdout ---- thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:378:21 ---- solution_test::test_consuming_packets stdout ---- thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:197:5 ---- solution_test::test_deserialize_invalid_packet stdout ---- thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:378:21 ---- solution_test::test_deserialize_packet stdout ---- thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:378:21 ---- solution_test::test_deserialize_unicode_packet stdout ---- thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:378:21 ---- solution_test::test_full_roundtrip stdout ---- thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:210:5 ---- solution_test::test_invalid_packet_combination stdout ---- thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:232:5 ---- solution_test::test_iterating_packets stdout ---- thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:172:5 ---- solution_test::test_serialize_packet stdout ---- thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', src/libcore/option.rs:378:21 ---- solution_test::test_zero_size stdout ---- note: test did not panic as expected failures: solution_test::test_construct_packet_no_remainder solution_test::test_construct_packet_with_remainder_cyrillic solution_test::test_consuming_packets solution_test::test_deserialize_invalid_packet solution_test::test_deserialize_packet solution_test::test_deserialize_unicode_packet solution_test::test_full_roundtrip solution_test::test_invalid_packet_combination solution_test::test_iterating_packets solution_test::test_serialize_packet solution_test::test_zero_size test result: FAILED. 4 passed; 11 failed; 0 ignored; 0 measured; 0 filtered out error: test failed, to rerun pass '--test solution_test'
История (2 версии и 4 коментара)
Моника качи решение на 03.12.2019 16:57 (преди почти 6 години)
use std::fmt;
use std::str;
use std::convert::TryInto;
#[derive(Debug)]
pub enum PacketError {
InvalidPacket,
InvalidChecksum,
UnknownProtocolVersion,
CorruptedMessage,
}
impl fmt::Display for PacketError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let err_msg = match self {
PacketError::InvalidPacket => "InvalidPacket",
PacketError::InvalidChecksum => "InvalidChecksum",
PacketError::UnknownProtocolVersion=>"UnknownProtocolVersion",
PacketError::CorruptedMessage=>"CorruptedMessage",
};
(write!(f, "{}", err_msg))
}
}
impl std::error::Error for PacketError {}
#[derive(PartialEq, Debug)]
pub struct Packet<'a> {
payload: &'a[u8],
checksum: u32,
version: u8,
size:u8,
}
impl<'a> Packet<'a> {
pub fn from_source(source: &'a [u8], size: u8) -> (Self, &[u8]) {
let n = size as usize;
let first = source.get(0..n).unwrap();
let second = source.get(n..source.len()).unwrap();
let mut checksum : u32 = 0;
for i in 0..first.len() {
checksum += *first.get(i).unwrap() as u32;
}
Доста C-подобен начин за итерация :). Вместо да итерираш по индекс, просто можеш да итерираш по елементите на колекцията: for byte in first { checksum += *byte as u32 }
или нещо подобно. Същото се отнася за останалите цикли.
let mut packet = Packet {
payload: first,
version:1,
size: size,
checksum:checksum,
};
(packet, second)
}
pub fn payload(&self) -> &[u8] {
(&self.payload)
}
pub fn serialize(&self) -> Vec<u8>{
let slice = &self.payload();
let mut vec = Vec::new();
vec.push(*&self.version);
vec.push(*&self.size);
for i in 0..slice.len() {
vec.push(*slice.get(i).unwrap());
}
let check = &self.checksum.to_be_bytes();
for i in 0..4{
vec.push(check[i]);
}
(vec)
}
pub fn deserialize(bytes: &[u8]) -> Result<(Packet, &[u8]), PacketError>{
let pos = bytes[1] as usize;
let check = bytes.get(2+pos..6+pos).unwrap();
let checkBytes: [u8; 4] = [check[0], check[1], check[2], check[3]];
let packet = Packet {
version: bytes[0],
size: bytes[1],
payload: bytes.get(2..2+pos).unwrap(),
checksum: u32::from_be_bytes(checkBytes),
};
let mut sumCheck : u32 = 0;
for i in 0..packet.payload.len() {
sumCheck += *packet.payload.get(i).unwrap() as u32;
}
if(bytes.len() < 7 || (packet.size as usize) > packet.payload.len()){
Err(PacketError::InvalidPacket)
}else if (packet.version != 1){
Err(PacketError::UnknownProtocolVersion)
}else if (packet.checksum != sumCheck){
Err(PacketError::InvalidChecksum)
}else if((packet.size as usize) < packet.payload.len()){
Err(PacketError::InvalidChecksum)
}
else{
let exp = bytes.get(6+pos..bytes.len()).unwrap();
let pair = (packet, exp);
Ok(pair)
}
}
}
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 nextPacket = Packet::from_source(self.bytes, self.packet_size).0;
self.bytes = Packet::from_source(self.bytes, self.packet_size).1;
Можеш да pattern-match-неш компонентите на един tuple:
let (nextPacket, bytes) = Packet::from_source(self.bytes, self.packet_size);
self.bytes = bytes;
Some(nextPacket)
(Some(nextPacket))
}
}
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 p = PacketSerializer{
packet_size: packet_size,
bytes: self.as_bytes(),
};
(p)
}
fn to_packet_data(&self, packet_size: u8) -> Vec<u8> {
let mut package = self.to_packets(packet_size);
let mut vecOfBytes = Vec::new();
while package.bytes.len() > 0{
let mut check = package.next();
if(check.is_none()){
- println!("fdg");
- break;
+ return vecOfBytes;
}
let vec = (check.unwrap()).serialize();
for i in 0..vec.len(){
vecOfBytes.push(vec[i]);
}
}
Идеята PacketSerializer
да бъде итератор е за да може да итерирате по него:
for packet in self.to_packets(packet_size) {
for byte in packet.serialize() {
vecOfBytes.push(byte);
}
}
Или нещо такова.
(vecOfBytes)
}
fn from_packet_data(packet_data: &[u8]) -> Result<Self, PacketError>{
let mut bytes = packet_data;
let mut finalString: std::string::String = "".to_string();
let mut a = "";
while bytes.len() > 0{
let error = (Packet::deserialize(bytes));
match error{
Err(e)=> return Err(e),
Ok(val)=>{
let mut packet = &(Packet::deserialize(bytes)).unwrap().0;
let mut currPayload = packet.payload;
let mut sumCheck : u32 = 0;
for i in 0..packet.payload.len() {
sumCheck += *packet.payload.get(i).unwrap() as u32;
}
finalString = (finalString.to_owned() + (str::from_utf8(currPayload).unwrap()));
bytes = (Packet::deserialize(bytes)).unwrap().1;
}
}
}
Ok(finalString.to_string())
}
}
Обещаващо начало на решение, но прибързано :). Късно си почнала, другия път си дай мноого повече време. Разгледай останалите решения, имаш доста логика, която е C-подобна и игнорира инструментите, които ти дава езика -- в Rust има по-лесни начини да решиш тези проблеми.
Доста C-подобен начин за итерация :). Вместо да итерираш по индекс, просто можеш да итерираш по елементите на колекцията:
for byte in first { checksum += *byte as u32 }
или нещо подобно. Същото се отнася за останалите цикли.Можеш да pattern-match-неш компонентите на един tuple:
Идеята
PacketSerializer
да бъде итератор е за да може да итерирате по него:Или нещо такова.