[bencode] Implement encoding

This commit is contained in:
Fabian 2024-07-23 22:41:40 +02:00
parent 1dcf4f6a37
commit 32650e811d

View File

@ -22,7 +22,7 @@ struct Torrent {
extra: HashMap<str, str>
}*/
#[derive(Debug, PartialEq, Eq, Hash)]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct ByteString(Vec<u8>);
impl Display for ByteString {
@ -85,6 +85,30 @@ impl Display for Bencode {
}
impl Bencode {
pub fn encode(input: &Self) -> Vec<u8> {
match input {
Bencode::Integer(i) => {format!("i{}e", i).as_bytes().to_vec()}
Bencode::Bytes(b) => {[format!("{}:", b.0.len()).as_bytes(), &b.0[..]].concat()}
Bencode::List(l) => {
let mut result = vec!['l' as u8];
for item in l {
result.extend(Self::encode(item))
}
result.push('e' as u8);
result
}
Bencode::Dict(d) => {
let mut result = vec!['d' as u8];
for (k, v) in d {
result.extend(Self::encode(&Bencode::Bytes(k.clone())));
result.extend(Self::encode(v));
}
result.push('e' as u8);
result
}
}
}
pub fn decode(input: &[u8]) -> Result<Bencode> {
let (result, end_pos) = Self::decode_type(input)?;
ensure!(end_pos == input.len() - 1,
@ -206,6 +230,28 @@ impl Bencode {
mod tests {
use super::*;
#[test]
fn test_encode_int() {
assert_eq!(Bencode::encode(&Bencode::Integer(42)), "i42e".as_bytes());
assert_eq!(Bencode::encode(&Bencode::Integer(17)), "i17e".as_bytes());
}
#[test]
fn test_encode_bytes() {
assert_eq!(Bencode::encode(&Bencode::Bytes(ByteString::from_str("foo"))), "3:foo".as_bytes());
assert_eq!(Bencode::encode(&Bencode::Bytes(ByteString::from_str("bar"))), "3:bar".as_bytes());
}
#[test]
fn test_encode_list() {
assert_eq!(Bencode::encode(&Bencode::List(vec![Bencode::Bytes(ByteString::from_str("foo")), Bencode::Integer(42)])), "l3:fooi42ee".as_bytes());
}
#[test]
fn test_encode_dict() {
assert_eq!(Bencode::encode(&Bencode::Dict(HashMap::from([(ByteString::from_str("foo"), Bencode::Integer(42))]))), "d3:fooi42ee".as_bytes());
}
#[test]
fn test_integer_only() {
assert_eq!(Bencode::decode_int_only("42".as_bytes()).unwrap(), 42);
@ -234,16 +280,16 @@ mod tests {
assert_eq!(Bencode::decode_bytes("💩".as_bytes()).unwrap(), Bencode::Bytes(ByteString::from_str("💩")));
}
fn test_encode_bytes(input: &str) -> String {
fn util_encode_bytes(input: &str) -> String {
format!("{}:{input}", input.len())
}
#[test]
fn test_bytes_str() {
assert_eq!(Bencode::decode(test_encode_bytes("hallo").as_bytes()).unwrap(), Bencode::Bytes(ByteString::from_str("hallo")));
assert_eq!(Bencode::decode(test_encode_bytes("tschüss").as_bytes()).unwrap(), Bencode::Bytes(ByteString::from_str("tschüss")));
assert_eq!(Bencode::decode(test_encode_bytes("💩").as_bytes()).unwrap(), Bencode::Bytes(ByteString::from_str("💩")));
assert_eq!(Bencode::decode(test_encode_bytes("hallo 💩, this is a long text").as_bytes()).unwrap(), Bencode::Bytes(ByteString::from_str("hallo 💩, this is a long text")));
assert_eq!(Bencode::decode(util_encode_bytes("hallo").as_bytes()).unwrap(), Bencode::Bytes(ByteString::from_str("hallo")));
assert_eq!(Bencode::decode(util_encode_bytes("tschüss").as_bytes()).unwrap(), Bencode::Bytes(ByteString::from_str("tschüss")));
assert_eq!(Bencode::decode(util_encode_bytes("💩").as_bytes()).unwrap(), Bencode::Bytes(ByteString::from_str("💩")));
assert_eq!(Bencode::decode(util_encode_bytes("hallo 💩, this is a long text").as_bytes()).unwrap(), Bencode::Bytes(ByteString::from_str("hallo 💩, this is a long text")));
}
#[test]
@ -262,7 +308,7 @@ mod tests {
str.len() - 1,
)
);
let str = format!("{}e", test_encode_bytes("hallo"));
let str = format!("{}e", util_encode_bytes("hallo"));
assert_eq!(Bencode::decode_list(
str.as_bytes()).unwrap(),
(
@ -272,7 +318,7 @@ mod tests {
str.len() - 1,
)
);
let str = format!("{}{}e", test_encode_bytes("hallo"), "i42e");
let str = format!("{}{}e", util_encode_bytes("hallo"), "i42e");
assert_eq!(Bencode::decode_list(
str.as_bytes()).unwrap(),
(
@ -283,7 +329,7 @@ mod tests {
str.len() - 1,
)
);
let str = format!("{}{}{}{}e", "i-17e", test_encode_bytes("hallo"), "i42e", test_encode_bytes("tschüssi💩"));
let str = format!("{}{}{}{}e", "i-17e", util_encode_bytes("hallo"), "i42e", util_encode_bytes("tschüssi💩"));
assert_eq!(Bencode::decode_list(
str.as_bytes()).unwrap(),
(
@ -308,7 +354,7 @@ mod tests {
]),
4)
);
let str = format!("l{}{}ee", test_encode_bytes("hallo"), "i42e");
let str = format!("l{}{}ee", util_encode_bytes("hallo"), "i42e");
assert_eq!(Bencode::decode_list(
str.as_bytes()).unwrap(),
(Bencode::List(vec![
@ -319,7 +365,7 @@ mod tests {
]),
str.len() - 1)
);
let str = format!("l{}{}el{}{}{}ee", test_encode_bytes("hallo"), "i42e", "i17e", test_encode_bytes("tschüss💩"), "i33e");
let str = format!("l{}{}el{}{}{}ee", util_encode_bytes("hallo"), "i42e", "i17e", util_encode_bytes("tschüss💩"), "i33e");
assert_eq!(Bencode::decode_list(
str.as_bytes()).unwrap(),
(Bencode::List(vec![
@ -350,20 +396,20 @@ mod tests {
])
);
assert_eq!(Bencode::decode(
(format!("l{}e", test_encode_bytes("hallo"))).as_bytes()).unwrap(),
(format!("l{}e", util_encode_bytes("hallo"))).as_bytes()).unwrap(),
Bencode::List(vec![
Bencode::Bytes(ByteString::from_str("hallo")),
])
);
assert_eq!(Bencode::decode(
(format!("l{}{}e", test_encode_bytes("hallo"), "i42e")).as_bytes()).unwrap(),
(format!("l{}{}e", util_encode_bytes("hallo"), "i42e")).as_bytes()).unwrap(),
Bencode::List(vec![
Bencode::Bytes(ByteString::from_str("hallo")),
Bencode::Integer(42),
])
);
assert_eq!(Bencode::decode(
(format!("l{}{}{}{}e", "i-17e", test_encode_bytes("hallo"), "i42e", test_encode_bytes("tschüssi💩"))).as_bytes()).unwrap(),
(format!("l{}{}{}{}e", "i-17e", util_encode_bytes("hallo"), "i42e", util_encode_bytes("tschüssi💩"))).as_bytes()).unwrap(),
Bencode::List(vec![
Bencode::Integer(-17),
Bencode::Bytes(ByteString::from_str("hallo")),
@ -377,7 +423,7 @@ mod tests {
Bencode::List(Vec::new()),
]),
);
let str = format!("ll{}{}ee", test_encode_bytes("hallo"), "i42e");
let str = format!("ll{}{}ee", util_encode_bytes("hallo"), "i42e");
assert_eq!(Bencode::decode(str.as_bytes()).unwrap(),
Bencode::List(vec![
Bencode::List(vec![
@ -386,7 +432,7 @@ mod tests {
]),
]),
);
let str = format!("ll{}{}el{}{}{}ee", test_encode_bytes("hallo"), "i42e", "i17e", test_encode_bytes("tschüss💩"), "i33e");
let str = format!("ll{}{}el{}{}{}ee", util_encode_bytes("hallo"), "i42e", "i17e", util_encode_bytes("tschüss💩"), "i33e");
assert_eq!(Bencode::decode(str.as_bytes()).unwrap(),
Bencode::List(vec![
Bencode::List(vec![
@ -400,7 +446,7 @@ mod tests {
]),
]),
);
let str = format!("ll{}{}ed{}{}{}{}ee", test_encode_bytes("hallo"), "i42e", test_encode_bytes("foo"), "i23e", test_encode_bytes("bar"), test_encode_bytes("baz"));
let str = format!("ll{}{}ed{}{}{}{}ee", util_encode_bytes("hallo"), "i42e", util_encode_bytes("foo"), "i23e", util_encode_bytes("bar"), util_encode_bytes("baz"));
assert_eq!(Bencode::decode(str.as_bytes()).unwrap(),
Bencode::List(vec![
Bencode::List(vec![
@ -464,7 +510,7 @@ mod tests {
(ByteString::from_str("foo"), Bencode::Integer(42)),
]))
);
let str = format!("d{}i42ee", test_encode_bytes("💩"));
let str = format!("d{}i42ee", util_encode_bytes("💩"));
assert_eq!(Bencode::decode(str.as_bytes()).unwrap(),
Bencode::Dict(HashMap::from([
(ByteString::from_str("💩"), Bencode::Integer(42)),