[bencode] Decode bytes

This commit is contained in:
Fabian 2024-07-21 13:32:10 +02:00
parent 3d0f1875a8
commit 81017b3f90

View File

@ -24,6 +24,16 @@ struct Torrent {
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct ByteString(Vec<u8>);
impl ByteString {
pub fn from_str(input: &str) -> Self {
ByteString(input.as_bytes().to_vec())
}
pub fn from_slice(input: &[u8]) -> Self {
ByteString(input.to_vec())
}
}
#[derive(Debug, PartialEq)]
pub enum Bencode {
Integer(i64),
@ -42,21 +52,14 @@ enum BencodeType {
impl Bencode {
pub fn decode(input: &str) -> Result<Bencode> {
Self::decode_slice(input.as_bytes())
Self::decode_type(input.as_bytes())
}
fn decode_slice(input: &[u8]) -> Result<Bencode>{
fn decode_type(input: &[u8]) -> Result<Bencode>{
if input.len() == 0 {
return Err(anyhow!("Empty string is not valid bencode"));
}
let char = input[0] as char;
// let type_ = match char {
// 'i' => Ok(Discriminant(Bencode::Integer)),
// 'l' => Ok(Discriminant(Bencode::List)),
// 'd' => Ok(Discriminant(Bencode::Dict)),
// '0'..='9' => Ok(Discriminant(Bencode::Integer)),
// _ => Err(anyhow!("Unknown bencoding char: {char}")),
// }?;
let type_ = match char {
'i' => Ok(BencodeType::Integer),
'l' => Ok(BencodeType::List),
@ -75,30 +78,53 @@ impl Bencode {
}
end_pos += 1;
}
let to_decode = match type_ {
BencodeType::Integer | BencodeType::List | BencodeType::Dict=> &input[1..end_pos],
BencodeType::Bytes => {
let bytes_len = Self::decode_int_only(&input[0..end_pos])? as usize;
let bytes_start= end_pos + 1;
&input[bytes_start..bytes_start + bytes_len]
},
};
match type_ {
BencodeType::Integer => Self::decode_int(&input[1..end_pos]),
BencodeType::List => Self::dummy(),
BencodeType::Dict => Self::dummy(),
BencodeType::Bytes => Self::dummy(),
BencodeType::Integer => Self::decode_int(to_decode),
BencodeType::List => Self::dummy(to_decode),
BencodeType::Dict => Self::dummy(to_decode),
BencodeType::Bytes => Self::decode_bytes(to_decode),
}
}
fn decode_int_only(input: &[u8]) -> Result<i64> {
let int_str = std::str::from_utf8(input)?;
int_str.parse::<i64>().map_err(anyhow::Error::msg)
}
fn decode_int(input: &[u8]) -> Result<Bencode> {
let int_str = std::str::from_utf8(input)?;
let int = int_str.parse::<i64>()?;
let int = Self::decode_int_only(input)?;
Ok(Bencode::Integer(int))
}
fn dummy() -> Result<Bencode> {
fn decode_bytes(input: &[u8]) -> Result<Bencode> {
Ok(Bencode::Bytes(ByteString::from_slice(input)))
}
fn dummy(_input: &[u8]) -> Result<Bencode> {
Ok(Bencode::Integer(42))
}
}
#[cfg(test)]
mod tests {
// Note this useful idiom: importing names from outer (for mod tests) scope.
use super::*;
#[test]
fn test_integer_only() {
assert_eq!(Bencode::decode_int_only("42".as_bytes()).unwrap(), 42);
assert_eq!(Bencode::decode_int_only("17".as_bytes()).unwrap(), 17);
assert_eq!(Bencode::decode_int_only("-17".as_bytes()).unwrap(), -17);
}
#[test]
fn test_integer() {
assert_eq!(Bencode::decode_int("42".as_bytes()).unwrap(), Bencode::Integer(42));
@ -113,4 +139,23 @@ mod tests {
assert_eq!(Bencode::decode("i-17e").unwrap(), Bencode::Integer(-17));
}
#[test]
fn test_bytes() {
assert_eq!(Bencode::decode_bytes("hallo".as_bytes()).unwrap(), Bencode::Bytes(ByteString::from_str("hallo")));
assert_eq!(Bencode::decode_bytes("tschüss".as_bytes()).unwrap(), Bencode::Bytes(ByteString::from_str("tschüss")));
assert_eq!(Bencode::decode_bytes("💩".as_bytes()).unwrap(), Bencode::Bytes(ByteString::from_str("💩")));
}
#[test]
fn test_bytes_str() {
let str = "hallo";
assert_eq!(Bencode::decode(format!("{}:{str}", str.len()).as_str()).unwrap(), Bencode::Bytes(ByteString::from_str("hallo")));
let str = "tschüss";
assert_eq!(Bencode::decode(format!("{}:{str}", str.len()).as_str()).unwrap(), Bencode::Bytes(ByteString::from_str("tschüss")));
let str = "💩";
assert_eq!(Bencode::decode(format!("{}:{str}", str.len()).as_str()).unwrap(), Bencode::Bytes(ByteString::from_str("💩")));
let str = "hallo 💩, this is a long text";
assert_eq!(Bencode::decode(format!("{}:{str}", str.len()).as_str()).unwrap(), Bencode::Bytes(ByteString::from_str("hallo 💩, this is a long text")));
}
}