diff --git a/src/bencode/encode.rs b/src/bencode/encode.rs new file mode 100644 index 0000000..feb5635 --- /dev/null +++ b/src/bencode/encode.rs @@ -0,0 +1,73 @@ +use std::borrow::Borrow; +use std::collections::BTreeMap; + +use bencode::Object; + +pub fn encode(obj: B) -> Vec where B: Borrow { + let mut buff = Vec::new(); + encode_object(&mut buff, obj.borrow()); + buff +} + +fn encode_object(buff: &mut Vec, obj: &Object) { + match *obj { + Object::Int(num) => encode_int(buff, num), + Object::Bytes(ref bytes) => encode_bytes(buff, bytes), + Object::List(ref list) => encode_list(buff, list), + Object::Dict(ref dict) => encode_dict(buff, dict), + } +} + +fn encode_int(buff: &mut Vec, num: i64) { + buff.extend_from_slice(format!("i{}e", num).as_bytes()); +} + +fn encode_bytes(buff: &mut Vec, bytes: &[u8]) { + buff.extend_from_slice(format!("{}:", bytes.len()).as_bytes()); + buff.extend_from_slice(bytes); +} + +fn encode_list(buff: &mut Vec, list: &[Object]) { + buff.push(b'l'); + for obj in list { + encode_object(buff, obj); + } + buff.push(b'e'); +} + +fn encode_dict(buff: &mut Vec, dict: &BTreeMap, Object>) { + buff.push(b'd'); + for (key, val) in dict { + encode_bytes(buff, key); + encode_object(buff, val); + } + buff.push(b'e'); +} + +#[test] +fn test_int_pos() { + assert_eq!(encode(Object::Int(1337)), b"i1337e"); +} + +#[test] +fn test_int_neg() { + assert_eq!(encode(Object::Int(-1337)), b"i-1337e"); +} + +#[test] +fn test_bytes() { + assert_eq!(encode(Object::Bytes(b"hello".to_vec())), b"5:hello"); +} + +#[test] +fn test_list() { + let list = vec![Object::Int(1), Object::Int(2), Object::Int(3)]; + assert_eq!(encode(Object::List(list)), b"li1ei2ei3ee"); +} + +#[test] +fn test_dict() { + let mut dict = BTreeMap::new(); + dict.insert(b"hello".to_vec(), Object::Int(1337)); + assert_eq!(encode(Object::Dict(dict)), b"d5:helloi1337ee") +} diff --git a/src/bencode/mod.rs b/src/bencode/mod.rs index a34c164..94493c2 100644 --- a/src/bencode/mod.rs +++ b/src/bencode/mod.rs @@ -1,10 +1,12 @@ mod decode; +mod encode; use std::collections::BTreeMap; use std::fmt; use std::str; pub use self::decode::{decode, DecodeError, DecodeResult}; +pub use self::encode::encode; #[derive(Eq, PartialEq)] pub enum Object {