pub trait BElement<T> where T: BElement<T> {
fn decode(encoded: &[u8]) -> Result<(usize, T), &'static str>;
}
#[derive(Eq, PartialEq, Debug)]
pub struct BNumber {
number: i64,
}
impl BNumber {
pub fn new(number: i64) -> BNumber {
BNumber { number: number }
}
}
impl BElement<BNumber> for BNumber {
fn decode(encoded: &[u8]) -> Result<(usize, BNumber), &'static str> {
if encoded.len() < 1 {
Err("empty string isn't valid BNumber")
} else {
match encoded[0] as char {
'i' => {
let mut i : usize = 1;
while i < encoded.len() && encoded[i] as char != 'e' {
i += 1;
}
if i == encoded.len() {
return Err("expected 'e' after number");
}
let number: &[u8] = &encoded[1..i];
let str_number: String = String::from_utf8_lossy(number).into_owned();
if let Ok(x) = str_number.parse::<i64>() {
Ok((i, BNumber::new(x)))
} else {
Err("expected correct i64 number")
}
},
_ => Err("expected 'i' before number")
}
}
}
}
#[derive(Eq, PartialEq, Debug)]
pub struct BString {
data: String,
}
impl BString {
pub fn new(data: &[u8]) -> BString {
BString { data: String::from_utf8_lossy(data).into_owned() }
}
}
impl BElement<BString> for BString {
fn decode(encoded: &[u8]) -> Result<(usize, BString), &'static str> {
let mut i: usize = 0;
while i < encoded.len() && encoded[i] as char != ':' {
i += 1;
}
if i == encoded.len() {
Err("expected :, but end was found")
} else {
let length: &[u8] = &encoded[0..i];
if let Ok(x) = String::from_utf8_lossy(length).into_owned().parse::<usize>() {
if i + x + 1 <= encoded.len() {
let value: &[u8] = &encoded[i + 1..i + x + 1];
Ok((i + x, BString::new(value)))
} else {
Err("expected more bytes, but end was found")
}
} else {
Err("expected correct usize number, representing length")
}
}
}
}
#[cfg(test)]
mod bnumber_tests {
extern crate rand;
use super::*;
fn test_bnumber(string: &[u8], index: usize, result: i64) {
let (ind, num) = BNumber::decode(string).ok().expect("invalid test");
assert_eq!(result, num.number);
assert_eq!(index, ind);
}
fn test_bnumber_invalid(string: &[u8], expected: &str) {
let error = BNumber::decode(string).err().expect("invalid test");
assert_eq!(expected, error);
}
#[test]
fn test1_bnumber_simple() {
test_bnumber("i300e".as_bytes(), 4, 300);
}
#[test]
fn test2_bnumber_negative() {
test_bnumber("i-23487e".as_bytes(), 7, -23487);
}
#[test]
fn test3_bnumber_invalid_format() {
test_bnumber_invalid("l487e".as_bytes(), "expected 'i' before number");
}
#[test]
fn test4_bnumber_invalid_format() {
test_bnumber_invalid("i487k".as_bytes(), "expected 'e' after number");
}
#[test]
fn test5_bnumber_invalid_number() {
test_bnumber_invalid("i-650-4e".as_bytes(), "expected correct i64 number");
}
#[test]
fn test6_bnumber_too_big_number() {
test_bnumber_invalid("i2398475629384765298346529384756293487562923452983e".as_bytes()
, "expected correct i64 number");
}
#[test]
fn test7_bnumber_zero() {
test_bnumber("i0e".as_bytes(), 2, 0);
}
#[test]
fn test8_bnumer_empty_number() {
test_bnumber_invalid("ie".as_bytes(), "expected correct i64 number");
}
#[test]
fn test9_bnumer_too_short() {
test_bnumber_invalid("i".as_bytes(), "expected 'e' after number");
}
#[test]
fn test10_bnumer_even_shorter() {
test_bnumber_invalid("".as_bytes(), "empty string isn't valid BNumber");
}
#[test]
fn test11_bnumer_stress() {
for _ in 0..100000 {
let number: i64 = rand::random::<i64>();
let string: String = format!("i{}e", number);
test_bnumber(string.as_bytes(), string.len() - 1, number);
}
}
}
#[cfg(test)]
mod bstring_tests {
use super::*;
fn test_bstring(string: &[u8], index: usize, result: String) {
let (ind, bstr) = BString::decode(string).ok().expect("invalid test");
assert_eq!(index, ind);
assert_eq!(result, bstr.data);
}
fn test_bstring_invalid(string: &[u8], expected: &str) {
let error = BString::decode(string).err().expect("invalid test");
assert_eq!(expected, error);
}
#[test]
fn test1_bstring_simple() {
test_bstring("3:abc".as_bytes(), 4, "abc".to_string());
}
#[test]
fn test2_bstring_short() {
test_bstring("1:a".as_bytes(), 2, "a".to_string());
}
#[test]
fn test3_bstring_even_shorter() {
test_bstring("0:".as_bytes(), 1, "".to_string());
}
#[test]
fn test4_bstring_digits() {
test_bstring("5:12345".as_bytes(), 6, "12345".to_string());
}
#[test]
fn test5_bstring_bad_symbols() {
test_bstring("14:!@#$%^&*()_+-=".as_bytes(), 16, "!@#$%^&*()_+-=".to_string());
}
#[test]
fn test6_bstring_empty() {
test_bstring_invalid("".as_bytes(), "expected :, but end was found");
}
#[test]
fn test7_bstring_bad_len() {
test_bstring_invalid("1:".as_bytes(), "expected more bytes, but end was found");
}
#[test]
fn test8_bstring_no_colon() {
test_bstring_invalid("128911".as_bytes(), "expected :, but end was found");
}
#[test]
fn test9_bstring_invalid_len() {
test_bstring_invalid("2a:a".as_bytes(), "expected correct usize number, representing length");
}
#[test]
fn test10_bstring_colon_first() {
test_bstring_invalid(":123".as_bytes(), "expected correct usize number, representing length");
}
}