Skip to content

Commit

Permalink
Update Bencode Dictionary Keys To Be Byte Slices Instead Of UTF-8 Str…
Browse files Browse the repository at this point in the history
…ing Slices
  • Loading branch information
GGist committed Dec 28, 2016
1 parent d6b31d3 commit 202e3a7
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 70 deletions.
2 changes: 1 addition & 1 deletion bip_bencode/src/bencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub enum Bencode<'a> {
/// Bencode List.
List(Vec<Bencode<'a>>),
/// Bencode Dictionary.
Dict(BTreeMap<&'a str, Bencode<'a>>)
Dict(BTreeMap<&'a [u8], Bencode<'a>>)
}

impl<'a> Bencode<'a> {
Expand Down
67 changes: 36 additions & 31 deletions bip_bencode/src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,82 +12,87 @@ pub trait BencodeConvert {
/// Attempt to convert the given bencode value into an integer.
///
/// Error key is used to generate an appropriate error message should the operation return an error.
fn convert_int<'a>(&self, bencode: &Bencode<'a>, error_key: &str) -> Result<i64, Self::Error> {
fn convert_int<'a, E>(&self, bencode: &Bencode<'a>, error_key: E) -> Result<i64, Self::Error>
where E: AsRef<[u8]> {
bencode.int().ok_or(self.handle_error(BencodeConvertError::with_key(BencodeConvertErrorKind::WrongType,
"Bencode Is Not An Integer", error_key.to_owned())))
"Bencode Is Not An Integer", error_key.as_ref().to_owned())))
}

/// Attempt to convert the given bencode value into bytes.
///
/// EError key is used to generate an appropriate error message should the operation return an error.
fn convert_bytes<'a>(&self, bencode: &Bencode<'a>, error_key: &str) -> Result<&'a [u8], Self::Error> {
fn convert_bytes<'a, E>(&self, bencode: &Bencode<'a>, error_key: E) -> Result<&'a [u8], Self::Error>
where E: AsRef<[u8]> {
bencode.bytes().ok_or(self.handle_error(BencodeConvertError::with_key(BencodeConvertErrorKind::WrongType,
"Bencode Is Not Bytes", error_key.to_owned())))
"Bencode Is Not Bytes", error_key.as_ref().to_owned())))
}

/// Attempt to convert the given bencode value into a UTF-8 string.
///
/// Error key is used to generate an appropriate error message should the operation return an error.
fn convert_str<'a>(&self, bencode: &Bencode<'a>, error_key: &str) -> Result<&'a str, Self::Error> {
fn convert_str<'a, E>(&self, bencode: &Bencode<'a>, error_key: E) -> Result<&'a str, Self::Error>
where E: AsRef<[u8]> {
bencode.str().ok_or(self.handle_error(BencodeConvertError::with_key(BencodeConvertErrorKind::WrongType,
"Bencode Is Not A String", error_key.to_owned())))
"Bencode Is Not A String", error_key.as_ref().to_owned())))
}

/// Attempty to convert the given bencode value into a list.
///
/// Error key is used to generate an appropriate error message should the operation return an error.
fn convert_list<'a, 'b>(&self, bencode: &'b Bencode<'a>, error_key: &str)
-> Result<&'b [Bencode<'a>], Self::Error> {
fn convert_list<'a, 'b, E>(&self, bencode: &'b Bencode<'a>, error_key: E)
-> Result<&'b [Bencode<'a>], Self::Error> where E: AsRef<[u8]> {
bencode.list().ok_or(self.handle_error(BencodeConvertError::with_key(BencodeConvertErrorKind::WrongType,
"Bencode Is Not A List", error_key.to_owned())))
"Bencode Is Not A List", error_key.as_ref().to_owned())))
}

/// Attempt to convert the given bencode value into a dictionary.
///
/// Error key is used to generate an appropriate error message should the operation return an error.
fn convert_dict<'a, 'b>(&self, bencode: &'b Bencode<'a>, error_key: &str)
-> Result<&'b Dictionary<'a, Bencode<'a>>, Self::Error> {
fn convert_dict<'a, 'b, E>(&self, bencode: &'b Bencode<'a>, error_key: E)
-> Result<&'b Dictionary<'a, Bencode<'a>>, Self::Error> where E: AsRef<[u8]> {
bencode.dict().ok_or(self.handle_error(BencodeConvertError::with_key(BencodeConvertErrorKind::WrongType,
"Bencode Is Not A Dictionary", error_key.to_owned())))
"Bencode Is Not A Dictionary", error_key.as_ref().to_owned())))
}

/// Look up a value in a dictionary of bencoded values using the given key.
fn lookup<'a, 'b>(&self, dictionary: &'b Dictionary<'a, Bencode<'a>>, key: &str)
-> Result<&'b Bencode<'a>, Self::Error> {
match dictionary.lookup(key) {
fn lookup<'a, 'b, K>(&self, dictionary: &'b Dictionary<'a, Bencode<'a>>, key: K)
-> Result<&'b Bencode<'a>, Self::Error> where K: AsRef<[u8]> {
let key_ref = key.as_ref();

match dictionary.lookup(key_ref) {
Some(n) => Ok(n),
None => Err(self.handle_error(BencodeConvertError::with_key(BencodeConvertErrorKind::MissingKey,
"Dictionary Missing Key", key.to_owned())))
"Dictionary Missing Key", key_ref.to_owned())))
}
}

/// Combines a lookup operation on the given key with a conversion of the value, if found, to an integer.
fn lookup_and_convert_int<'a>(&self, dictionary: &Dictionary<'a, Bencode<'a>>, key: &str)
-> Result<i64, Self::Error> {
self.convert_int(try!(self.lookup(dictionary, key)), key)
fn lookup_and_convert_int<'a, K>(&self, dictionary: &Dictionary<'a, Bencode<'a>>, key: K)
-> Result<i64, Self::Error> where K: AsRef<[u8]> {
self.convert_int(try!(self.lookup(dictionary, &key)), &key)
}

/// Combines a lookup operation on the given key with a conversion of the value, if found, to a series of bytes.
fn lookup_and_convert_bytes<'a>(&self, dictionary: &Dictionary<'a, Bencode<'a>>, key: &str)
-> Result<&'a [u8], Self::Error> {
self.convert_bytes(try!(self.lookup(dictionary, key)), key)
fn lookup_and_convert_bytes<'a, K>(&self, dictionary: &Dictionary<'a, Bencode<'a>>, key: K)
-> Result<&'a [u8], Self::Error> where K: AsRef<[u8]> {
self.convert_bytes(try!(self.lookup(dictionary, &key)), &key)
}

/// Combines a lookup operation on the given key with a conversion of the value, if found, to a UTF-8 string.
fn lookup_and_convert_str<'a>(&self, dictionary: &Dictionary<'a, Bencode<'a>>, key: &str)
-> Result<&'a str, Self::Error> {
self.convert_str(try!(self.lookup(dictionary, key)), key)
fn lookup_and_convert_str<'a, K>(&self, dictionary: &Dictionary<'a, Bencode<'a>>, key: K)
-> Result<&'a str, Self::Error> where K: AsRef<[u8]> {
self.convert_str(try!(self.lookup(dictionary, &key)), &key)
}

/// Combines a lookup operation on the given key with a conversion of the value, if found, to a list.
fn lookup_and_convert_list<'a: 'b, 'b>(&self, dictionary: &'b Dictionary<'a, Bencode<'a>>, key: &str)
-> Result<&'b [Bencode<'a>], Self::Error> {
self.convert_list(try!(self.lookup(dictionary, key)), key)
fn lookup_and_convert_list<'a: 'b, 'b, K>(&self, dictionary: &'b Dictionary<'a, Bencode<'a>>, key: K)
-> Result<&'b [Bencode<'a>], Self::Error> where K: AsRef<[u8]> {
self.convert_list(try!(self.lookup(dictionary, &key)), &key)
}

/// Combines a lookup operation on the given key with a conversion of the value, if found, to a dictionary.
fn lookup_and_convert_dict<'a: 'b, 'b>(&self, dictionary: &'b Dictionary<'a, Bencode<'a>>, key: &str)
-> Result<&'b Dictionary<'a, Bencode<'a>>, Self::Error> {
self.convert_dict(try!(self.lookup(dictionary, key)), key)
fn lookup_and_convert_dict<'a: 'b, 'b, K>(&self, dictionary: &'b Dictionary<'a, Bencode<'a>>, key: K)
-> Result<&'b Dictionary<'a, Bencode<'a>>, Self::Error> where K: AsRef<[u8]> {
self.convert_dict(try!(self.lookup(dictionary, &key)), &key)
}
}
33 changes: 13 additions & 20 deletions bip_bencode/src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use error::{BencodeParseError, BencodeParseErrorKind, BencodeParseResult};
// underlying recursive type is a dictionary, it is a programming error otherwise)
enum IBencodeType<'a> {
Bencode(Bencode<'a>),
BencodeMapping(&'a str, Bencode<'a>)
BencodeMapping(&'a [u8], Bencode<'a>)
}

/// Decodes the given list of bytes at the given position into a bencoded structures.
Expand Down Expand Up @@ -337,17 +337,10 @@ fn decode_bytes<'a>(bytes: &'a [u8], pos: usize) -> BencodeParseResult<(&'a [u8]
}

/// Returns the key reference as well as the starting byte of the next type.
fn decode_key<'a>(bytes: &'a [u8], pos: usize) -> BencodeParseResult<(&'a str, usize)> {
fn decode_key<'a>(bytes: &'a [u8], pos: usize) -> BencodeParseResult<(&'a [u8], usize)> {
let (key_bytes, next_pos) = try!(decode_bytes(bytes, pos));
let key = match str::from_utf8(key_bytes) {
Ok(n) => n,
Err(_) => {
return Err(BencodeParseError::with_pos(BencodeParseErrorKind::InvalidByte,
"Invalid UTF-8 Key Found For Dictionar", Some(next_pos)))
}
};

Ok((key, next_pos))
Ok((key_bytes, next_pos))
}

fn peek_byte(bytes: &[u8], pos: usize, err_msg: &'static str) -> BencodeParseResult<u8> {
Expand Down Expand Up @@ -388,12 +381,12 @@ mod tests {
let bencode = Bencode::decode(GENERAL).unwrap();

let ben_dict = bencode.dict().unwrap();
assert_eq!(ben_dict.lookup("").unwrap().str().unwrap(), "zero_len_key");
assert_eq!(ben_dict.lookup("location").unwrap().str().unwrap(), "udp://test.com:80");
assert_eq!(ben_dict.lookup("number").unwrap().int().unwrap(), 500500i64);
assert_eq!(ben_dict.lookup("".as_bytes()).unwrap().str().unwrap(), "zero_len_key");
assert_eq!(ben_dict.lookup("location".as_bytes()).unwrap().str().unwrap(), "udp://test.com:80");
assert_eq!(ben_dict.lookup("number".as_bytes()).unwrap().int().unwrap(), 500500i64);

let nested_dict = ben_dict.lookup("nested dict").unwrap().dict().unwrap();
let nested_list = nested_dict.lookup("list").unwrap().list().unwrap();
let nested_dict = ben_dict.lookup("nested dict".as_bytes()).unwrap().dict().unwrap();
let nested_list = nested_dict.lookup("list".as_bytes()).unwrap().list().unwrap();
assert_eq!(nested_list[0].int().unwrap(), -500500i64);
}

Expand All @@ -415,12 +408,12 @@ mod tests {
fn positive_decode_dict() {
let bencode = Bencode::decode(DICTIONARY).unwrap();
let dict = bencode.dict().unwrap();
assert_eq!(dict.lookup("test_key").unwrap().str().unwrap(), "test_value");
assert_eq!(dict.lookup("test_key".as_bytes()).unwrap().str().unwrap(), "test_value");

let nested_dict = dict.lookup("test_dict").unwrap().dict().unwrap();
assert_eq!(nested_dict.lookup("nested_key").unwrap().str().unwrap(), "nested_value");
let nested_dict = dict.lookup("test_dict".as_bytes()).unwrap().dict().unwrap();
assert_eq!(nested_dict.lookup("nested_key".as_bytes()).unwrap().str().unwrap(), "nested_value");

let nested_list = nested_dict.lookup("nested_list").unwrap().list().unwrap();
let nested_list = nested_dict.lookup("nested_list".as_bytes()).unwrap().list().unwrap();
assert_eq!(nested_list[0].int().unwrap(), 500i64);
assert_eq!(nested_list[1].int().unwrap(), -500i64);
assert_eq!(nested_list[2].int().unwrap(), 0i64);
Expand All @@ -440,7 +433,7 @@ mod tests {
assert_eq!(nested_list[0].str().unwrap(), "nested_bytes");

let nested_dict = list[5].dict().unwrap();
assert_eq!(nested_dict.lookup("test_key").unwrap().str().unwrap(), "test_value");
assert_eq!(nested_dict.lookup("test_key".as_bytes()).unwrap().str().unwrap(), "test_value");
}

#[test]
Expand Down
22 changes: 11 additions & 11 deletions bip_bencode/src/dictionary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,39 @@ use std::collections::{BTreeMap};
/// Trait for working with generic map data structures.
pub trait Dictionary<'a, V> {
/// Convert the dictionary to an unordered list of key/value pairs.
fn to_list(&self) -> Vec<(&'a str, &V)>;
fn to_list(&self) -> Vec<(&'a [u8], &V)>;

/// Lookup a value in the dictionary.
fn lookup(&self, key: &str) -> Option<&V>;
fn lookup(&self, key: &[u8]) -> Option<&V>;

/// Lookup a mutable value in the dictionary.
fn lookup_mut(&mut self, key: &str) -> Option<&mut V>;
fn lookup_mut(&mut self, key: &[u8]) -> Option<&mut V>;

/// Insert a key/value pair into the dictionary.
fn insert(&mut self, key: &'a str, value: V) -> Option<V>;
fn insert(&mut self, key: &'a [u8], value: V) -> Option<V>;

/// Remove a value from the dictionary and return it.
fn remove(&mut self, key: &str) -> Option<V>;
fn remove(&mut self, key: &[u8]) -> Option<V>;
}

impl<'a, V> Dictionary<'a, V> for BTreeMap<&'a str, V> {
fn to_list(&self) -> Vec<(&'a str, &V)> {
impl<'a, V> Dictionary<'a, V> for BTreeMap<&'a [u8], V> {
fn to_list(&self) -> Vec<(&'a [u8], &V)> {
self.iter().map(|(k, v)| (*k, v)).collect()
}

fn lookup(&self, key: &str) -> Option<&V> {
fn lookup(&self, key: &[u8]) -> Option<&V> {
self.get(key)
}

fn lookup_mut(&mut self, key: &str) -> Option<&mut V> {
fn lookup_mut(&mut self, key: &[u8]) -> Option<&mut V> {
self.get_mut(key)
}

fn insert(&mut self, key: &'a str, value: V) -> Option<V> {
fn insert(&mut self, key: &'a [u8], value: V) -> Option<V> {
self.insert(key, value)
}

fn remove(&mut self, key: &str) -> Option<V> {
fn remove(&mut self, key: &[u8]) -> Option<V> {
self.remove(key)
}
}
2 changes: 1 addition & 1 deletion bip_bencode/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ fn encode_dict<'a>(dict: &Dictionary<'a, Bencode<'a>>) -> Vec<u8> {
bytes.push(::DICT_START);
// Iterate And Dictionary Encode The (String, Bencode) Pairs
for &(ref key, ref value) in sort_dict.iter() {
bytes.extend(encode_bytes(key.as_bytes()));
bytes.extend(encode_bytes(key));
bytes.extend(encode(*value));
}
bytes.push(::BEN_END);
Expand Down
10 changes: 5 additions & 5 deletions bip_bencode/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,16 @@ pub enum BencodeConvertErrorKind {
pub struct BencodeConvertError {
kind: BencodeConvertErrorKind,
desc: &'static str,
key: Cow<'static, str>
key: Cow<'static, [u8]>
}

impl BencodeConvertError {
pub fn new(kind: BencodeConvertErrorKind, desc: &'static str) -> BencodeConvertError {
BencodeConvertError::with_key(kind, desc, "")
BencodeConvertError::with_key(kind, desc, "".as_bytes())
}

pub fn with_key<T>(kind: BencodeConvertErrorKind, desc: &'static str, key: T)
-> BencodeConvertError where T: Into<Cow<'static, str>> {
-> BencodeConvertError where T: Into<Cow<'static, [u8]>> {
BencodeConvertError{ kind: kind, desc: desc, key: key.into() }
}

Expand All @@ -108,7 +108,7 @@ impl BencodeConvertError {
self.desc
}

pub fn key(&self) -> &str {
pub fn key(&self) -> &[u8] {
&self.key
}
}
Expand All @@ -119,7 +119,7 @@ impl Display for BencodeConvertError {

try!(f.write_fmt(format_args!(", Description: {}", self.desc)));

try!(f.write_fmt(format_args!(", Key: {}", self.key)));
try!(f.write_fmt(format_args!(", Key: {:?}", self.key)));

Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion bip_bencode/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//! let data = b"d12:lucky_numberi7ee";
//! let bencode = Bencode::decode(data).unwrap();
//!
//! assert_eq!(7, bencode.dict().unwrap().lookup("lucky_number")
//! assert_eq!(7, bencode.dict().unwrap().lookup("lucky_number".as_bytes())
//! .unwrap().int().unwrap());
//! }
//! ```
Expand Down

0 comments on commit 202e3a7

Please sign in to comment.