[bencode] Implement encoding
This commit is contained in:
parent
1dcf4f6a37
commit
32650e811d
@ -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)),
|
||||
|
Loading…
Reference in New Issue
Block a user