initial commit, bencode decoding

This commit is contained in:
2016-12-11 04:00:01 -05:00
commit 74b81bf5e8
7 changed files with 344 additions and 0 deletions

143
src/bencode/decode.rs Normal file
View File

@@ -0,0 +1,143 @@
use std::collections::BTreeMap;
use std::num::ParseIntError;
use std::str::{self, Utf8Error};
use bencode::Object;
use buffer::Buffer;
#[derive(Debug)]
pub struct DecodeError;
impl From<Utf8Error> for DecodeError {
fn from(_: Utf8Error) -> Self {
DecodeError
}
}
impl From<ParseIntError> for DecodeError {
fn from(_: ParseIntError) -> Self {
DecodeError
}
}
pub type DecodeResult<T> = Result<T, DecodeError>;
pub fn decode(data: &[u8]) -> DecodeResult<Object> {
let mut buf = Buffer::new(data);
decode_object(&mut buf)
}
fn decode_object(buf: &mut Buffer) -> DecodeResult<Object> {
match buf.get(0) {
Some(b'i') => {
buf.advance(1);
decode_int(buf, b'e')
},
Some(b'0' ... b'9') => {
decode_bytes(buf)
}
Some(b'l') => {
buf.advance(1);
let mut list = Vec::new();
while let Some(term) = buf.get(0) {
if term == b'e' {
buf.advance(1);
break;
}
list.push(decode_object(buf)?);
}
Ok(Object::List(list))
}
Some(b'd') => {
buf.advance(1);
let mut dict = BTreeMap::new();
while let Some(term) = buf.get(0) {
if term == b'e' {
buf.advance(1);
break;
}
let key = _decode_bytes(buf)?;
let val = decode_object(buf)?;
dict.insert(key, val);
}
Ok(Object::Dict(dict))
}
_ => Err(DecodeError),
}
}
fn decode_int(buf: &mut Buffer, term: u8) -> DecodeResult<Object> {
_decode_int(buf, term).map(|num| Object::Int(num))
}
fn _decode_int(buf: &mut Buffer, term: u8) -> DecodeResult<i64> {
if let Some(end) = buf.find(term) {
let obj = {
let num = str::from_utf8(&buf[..end])?;
num.parse()?
};
buf.advance(end + 1);
Ok(obj)
} else {
Err(DecodeError)
}
}
fn decode_bytes(buf: &mut Buffer) -> DecodeResult<Object> {
_decode_bytes(buf).map(|bytes| Object::Bytes(bytes))
}
fn _decode_bytes(buf: &mut Buffer) -> Result<Vec<u8>, DecodeError> {
let size = _decode_int(buf, b':')? as usize;
let bytes = buf[..size].to_vec();
buf.advance(size);
Ok(bytes)
}
#[test]
fn test_int_pos() {
let mut buf = Buffer::new(b"i1337e");
buf.advance(1);
assert_eq!(decode_int(&mut buf, b'e').unwrap(), Object::Int(1337));
assert_eq!(buf.pos(), 6);
}
#[test]
fn test_int_neg() {
let mut buf = Buffer::new(b"i-1337e");
buf.advance(1);
assert_eq!(decode_int(&mut buf, b'e').unwrap(), Object::Int(-1337));
assert_eq!(buf.pos(), 7);
}
#[test]
fn test_bytes() {
let mut buf = Buffer::new(b"5:hello");
assert_eq!(decode_bytes(&mut buf).unwrap(), Object::Bytes(b"hello".to_vec()));
assert_eq!(buf.pos(), 7);
}
#[test]
fn test_list() {
let mut buf = Buffer::new(b"li1ei2ei3ee");
let obj = decode_object(&mut buf).unwrap();
let list = obj.as_list().unwrap();
assert_eq!(list, vec![Object::Int(1), Object::Int(2), Object::Int(3)]);
assert_eq!(buf.pos(), 11);
}
#[test]
fn test_dict() {
let mut buf = Buffer::new(b"d5:helloi1337ee");
let obj = decode_object(&mut buf).unwrap();
let dict = obj.as_dict().unwrap();
assert_eq!(dict[&b"hello"[..]], Object::Int(1337));
assert_eq!(buf.pos(), 15);
}