[bencode] Implement encoding
This commit is contained in:
parent
1dcf4f6a37
commit
32650e811d
@ -22,7 +22,7 @@ struct Torrent {
|
|||||||
extra: HashMap<str, str>
|
extra: HashMap<str, str>
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
||||||
pub struct ByteString(Vec<u8>);
|
pub struct ByteString(Vec<u8>);
|
||||||
|
|
||||||
impl Display for ByteString {
|
impl Display for ByteString {
|
||||||
@ -85,6 +85,30 @@ impl Display for Bencode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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> {
|
pub fn decode(input: &[u8]) -> Result<Bencode> {
|
||||||
let (result, end_pos) = Self::decode_type(input)?;
|
let (result, end_pos) = Self::decode_type(input)?;
|
||||||
ensure!(end_pos == input.len() - 1,
|
ensure!(end_pos == input.len() - 1,
|
||||||
@ -206,6 +230,28 @@ impl Bencode {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
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]
|
#[test]
|
||||||
fn test_integer_only() {
|
fn test_integer_only() {
|
||||||
assert_eq!(Bencode::decode_int_only("42".as_bytes()).unwrap(), 42);
|
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("💩")));
|
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())
|
format!("{}:{input}", input.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bytes_str() {
|
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(util_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(util_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(util_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 💩, this is a long text").as_bytes()).unwrap(), Bencode::Bytes(ByteString::from_str("hallo 💩, this is a long text")));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -262,7 +308,7 @@ mod tests {
|
|||||||
str.len() - 1,
|
str.len() - 1,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
let str = format!("{}e", test_encode_bytes("hallo"));
|
let str = format!("{}e", util_encode_bytes("hallo"));
|
||||||
assert_eq!(Bencode::decode_list(
|
assert_eq!(Bencode::decode_list(
|
||||||
str.as_bytes()).unwrap(),
|
str.as_bytes()).unwrap(),
|
||||||
(
|
(
|
||||||
@ -272,7 +318,7 @@ mod tests {
|
|||||||
str.len() - 1,
|
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(
|
assert_eq!(Bencode::decode_list(
|
||||||
str.as_bytes()).unwrap(),
|
str.as_bytes()).unwrap(),
|
||||||
(
|
(
|
||||||
@ -283,7 +329,7 @@ mod tests {
|
|||||||
str.len() - 1,
|
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(
|
assert_eq!(Bencode::decode_list(
|
||||||
str.as_bytes()).unwrap(),
|
str.as_bytes()).unwrap(),
|
||||||
(
|
(
|
||||||
@ -308,7 +354,7 @@ mod tests {
|
|||||||
]),
|
]),
|
||||||
4)
|
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(
|
assert_eq!(Bencode::decode_list(
|
||||||
str.as_bytes()).unwrap(),
|
str.as_bytes()).unwrap(),
|
||||||
(Bencode::List(vec![
|
(Bencode::List(vec![
|
||||||
@ -319,7 +365,7 @@ mod tests {
|
|||||||
]),
|
]),
|
||||||
str.len() - 1)
|
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(
|
assert_eq!(Bencode::decode_list(
|
||||||
str.as_bytes()).unwrap(),
|
str.as_bytes()).unwrap(),
|
||||||
(Bencode::List(vec![
|
(Bencode::List(vec![
|
||||||
@ -350,20 +396,20 @@ mod tests {
|
|||||||
])
|
])
|
||||||
);
|
);
|
||||||
assert_eq!(Bencode::decode(
|
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::List(vec![
|
||||||
Bencode::Bytes(ByteString::from_str("hallo")),
|
Bencode::Bytes(ByteString::from_str("hallo")),
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
assert_eq!(Bencode::decode(
|
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::List(vec![
|
||||||
Bencode::Bytes(ByteString::from_str("hallo")),
|
Bencode::Bytes(ByteString::from_str("hallo")),
|
||||||
Bencode::Integer(42),
|
Bencode::Integer(42),
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
assert_eq!(Bencode::decode(
|
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::List(vec![
|
||||||
Bencode::Integer(-17),
|
Bencode::Integer(-17),
|
||||||
Bencode::Bytes(ByteString::from_str("hallo")),
|
Bencode::Bytes(ByteString::from_str("hallo")),
|
||||||
@ -377,7 +423,7 @@ mod tests {
|
|||||||
Bencode::List(Vec::new()),
|
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(),
|
assert_eq!(Bencode::decode(str.as_bytes()).unwrap(),
|
||||||
Bencode::List(vec![
|
Bencode::List(vec![
|
||||||
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(),
|
assert_eq!(Bencode::decode(str.as_bytes()).unwrap(),
|
||||||
Bencode::List(vec![
|
Bencode::List(vec![
|
||||||
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(),
|
assert_eq!(Bencode::decode(str.as_bytes()).unwrap(),
|
||||||
Bencode::List(vec![
|
Bencode::List(vec![
|
||||||
Bencode::List(vec![
|
Bencode::List(vec![
|
||||||
@ -464,7 +510,7 @@ mod tests {
|
|||||||
(ByteString::from_str("foo"), Bencode::Integer(42)),
|
(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(),
|
assert_eq!(Bencode::decode(str.as_bytes()).unwrap(),
|
||||||
Bencode::Dict(HashMap::from([
|
Bencode::Dict(HashMap::from([
|
||||||
(ByteString::from_str("💩"), Bencode::Integer(42)),
|
(ByteString::from_str("💩"), Bencode::Integer(42)),
|
||||||
|
Loading…
Reference in New Issue
Block a user