From 64697abe41453c75858248cf4e6bb9258ff967dd Mon Sep 17 00:00:00 2001 From: ivanjermakov Date: Sun, 22 Oct 2023 18:17:53 +0200 Subject: [PATCH] `ByteString` alias; `BencodeValue::encode` --- src/bencode.rs | 72 ++++++++++++++++++++++++++++++++++++++++++-------- src/types.rs | 1 + 2 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 src/types.rs diff --git a/src/bencode.rs b/src/bencode.rs index 9b8d70c..f78045c 100644 --- a/src/bencode.rs +++ b/src/bencode.rs @@ -1,14 +1,55 @@ use core::fmt; use std::{collections::BTreeMap, vec}; +use crate::types::ByteString; + #[derive(Clone, PartialEq, Eq, Hash)] pub enum BencodeValue { - String(Vec), + String(ByteString), Int(i64), List(Vec), Dict(BTreeMap), } +impl BencodeValue { + pub fn encode(&self) -> ByteString { + match self { + BencodeValue::String(s) => { + [s.len().to_string().as_bytes(), ":".as_bytes(), s.as_slice()].concat() + } + BencodeValue::Int(i) => { + ["i".as_bytes(), i.to_string().as_bytes(), "e".as_bytes()].concat() + } + BencodeValue::List(l) => vec![ + "l".as_bytes().to_vec(), + l.iter().flat_map(|v| v.encode()).collect(), + "e".as_bytes().to_vec(), + ] + .into_iter() + .flatten() + .collect(), + BencodeValue::Dict(d) => vec![ + "d".as_bytes().to_vec(), + d.iter() + .flat_map(|(k, v)| { + [ + BencodeValue::String(k.as_bytes().to_vec()) + .encode() + .as_slice(), + v.encode().as_slice(), + ] + .concat() + }) + .collect(), + "e".as_bytes().to_vec(), + ] + .into_iter() + .flatten() + .collect(), + } + } +} + impl fmt::Debug for BencodeValue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { match self { @@ -23,7 +64,19 @@ impl fmt::Debug for BencodeValue { } } -pub fn parse_bencoded(bencoded: Vec) -> (Option, Vec) { +#[allow(dead_code)] +pub fn bencode_string(value: ByteString) -> ByteString { + vec![ + value.len().to_string().as_bytes().to_vec(), + ":".as_bytes().to_vec(), + value, + ] + .into_iter() + .flatten() + .collect() +} + +pub fn parse_bencoded(bencoded: ByteString) -> (Option, ByteString) { let next = bencoded.first().unwrap(); match *next as char { c if c.is_ascii_digit() => parse_string(bencoded), @@ -38,7 +91,7 @@ pub fn parse_bencoded(bencoded: Vec) -> (Option, Vec) { } /// Format: : -pub fn parse_string(bencoded: Vec) -> (Option, Vec) { +pub fn parse_string(bencoded: ByteString) -> (Option, ByteString) { let mut i = 0; let size_chars = bencoded @@ -57,7 +110,7 @@ pub fn parse_string(bencoded: Vec) -> (Option, Vec) { } i += 1; - let str: Vec = bencoded + let str: ByteString = bencoded .iter() .skip(size_chars.len() + 1) .take(size as usize) @@ -72,7 +125,7 @@ pub fn parse_string(bencoded: Vec) -> (Option, Vec) { } /// Format: ie -pub fn parse_int(bencoded: Vec) -> (Option, Vec) { +pub fn parse_int(bencoded: ByteString) -> (Option, ByteString) { let mut i = 0; if bencoded.get(i).filter(|c| (**c as char) == 'i').is_none() { @@ -104,7 +157,7 @@ pub fn parse_int(bencoded: Vec) -> (Option, Vec) { } /// Format: le -pub fn parse_list(bencoded: Vec) -> (Option, Vec) { +pub fn parse_list(bencoded: ByteString) -> (Option, ByteString) { let mut i = 0; let mut items = vec![]; @@ -134,7 +187,7 @@ pub fn parse_list(bencoded: Vec) -> (Option, Vec) { } /// Format: de -pub fn parse_dict(bencoded: Vec) -> (Option, Vec) { +pub fn parse_dict(bencoded: ByteString) -> (Option, ByteString) { let mut i = 0; let mut map: BTreeMap = BTreeMap::new(); @@ -149,10 +202,7 @@ pub fn parse_dict(bencoded: Vec) -> (Option, Vec) { { i = bencoded.len() - left.len(); match item { - BencodeValue::String(s) => match String::from_utf8(s) { - Ok(s) => s, - _ => return (None, bencoded), - }, + BencodeValue::String(s) => String::from_utf8_lossy(s.as_slice()).to_string(), _ => return (None, bencoded), } } else { diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 0000000..b4043f0 --- /dev/null +++ b/src/types.rs @@ -0,0 +1 @@ +pub type ByteString = Vec;