1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
use std::io;
use std::io::Read;
use std::iter::Peekable;
use std::collections::HashMap;

use value::Value;

#[derive(Debug)]
pub enum DecodeError {
    IOError(io::Error),
    UnexpectedEndOfBuffer,
    UnexpectedCharacter(String)
}

macro_rules! try_read {
    ($e: expr) => (
        match $e.next() {
            None => return Err(DecodeError::UnexpectedEndOfBuffer),
            Some(Err(e)) => return Err(DecodeError::IOError(e)),
            Some(Ok(c)) => c,
        }
    );
}
macro_rules! try_peek {
    ($e: expr) => ({
        let tmp = match $e.peek() {
            None => return Err(DecodeError::UnexpectedEndOfBuffer),
            Some(&Err(_)) => {
                // We need an owned version of IOError. If peek() raised one,
                // hopefully, next() will, so let's do it.
                // Unfortunately, we cannot do it now because the reader is
                // still mutably borrowed, so let's defer the call.
                None
            }
            Some(&Ok(c)) => Some(c),
        };
        match tmp {
            Some(c) => c,
            None => return Err(DecodeError::IOError($e.next().unwrap().unwrap_err()))
        }
    });
}

fn read_integer<R: io::Read>(bytes: &mut Peekable<io::Bytes<R>>) -> Result<i64, DecodeError> {
    let mut res = 0i64;
    let first_digit = try_peek!(bytes);
    let multiplicator = if first_digit as char == '-' { try_read!(bytes); -1 } else { 1 };
    loop {
        let digit = try_read!(bytes);
        match digit as char {
            'e' => break,
            '0' ... '9' => res = res*10 + (digit as i64 - ('0' as i64)),
            _ => return Err(DecodeError::UnexpectedCharacter(format!("'{}' while reading an integer.", digit as char))),
        }
    };
    Ok(multiplicator * res)
}

fn read_list<R: io::Read>(bytes: &mut Peekable<io::Bytes<R>>) -> Result<Vec<Value>, DecodeError> {
    let mut res = Vec::<Value>::new();
    loop {
        let digit = try_peek!(bytes);
        match digit as char {
            'e' => break,
            _ => res.push(try!(read(bytes))),
        }
    }
    Ok(res)
}

fn read_string<R: io::Read>(bytes: &mut Peekable<io::Bytes<R>>, first_byte: u8) -> Result<Vec<u8>, DecodeError> {
    assert!(first_byte >= '0' as u8);
    assert!(first_byte <= '9' as u8);
    let mut length = first_byte as usize - ('0' as usize);
    loop {
        let digit = try_read!(bytes);
        match digit as char {
            ':' => break,
            '0' ... '9' => length = length*10 + digit as usize - ('0' as usize),
            _ => return Err(DecodeError::UnexpectedCharacter(format!("'{}' while reading a string length", digit as char)))
        }
    }
    let mut res = Vec::new();
    res.reserve(length);
    for _ in 0..length {
        res.push(try_read!(bytes));
    }
    Ok(res)
}

fn read_dict<R: io::Read>(bytes: &mut Peekable<io::Bytes<R>>) -> Result<HashMap<Vec<u8>, Value>, DecodeError> {
    let mut res = HashMap::<Vec<u8>, Value>::new();
    loop {
        let first_byte = try_read!(bytes);
        match first_byte as char {
            'e' => break,
            '0' ... '9' => res.insert(try!(read_string(bytes, first_byte)), try!(read(bytes))),
            first_char => return Err(DecodeError::UnexpectedCharacter(format!("'{}' while expecting 'e' or 'e' or '0'..'9' (next key in dict)", first_char))),
        };
    }
    Ok(res)
}


pub fn read<R: io::Read>(bytes: &mut Peekable<io::Bytes<R>>) -> Result<Value, DecodeError> {
    let byte = try_read!(bytes);
    match byte as char {
        'i' => read_integer(bytes).map(Value::Integer),
        'l' => read_list(bytes).map(Value::List),
        'd' => read_dict(bytes).map(Value::Dictionary),
        '0' ... '9' => read_string(bytes, byte).map(Value::String),
        _ => Err(DecodeError::UnexpectedCharacter(format!("'{}' instead of the first byte of an object.", byte)))
    }
}

pub fn decode(sl: &[u8]) -> Result<Value, DecodeError> {
    read(&mut sl.bytes().peekable())
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use value::Value;
    use super::*;

    #[test]
    fn integer() {
        assert_eq!(decode(b"i1234e").unwrap(), Value::Integer(1234));
        assert_eq!(decode(b"i1234eaaaa").unwrap(), Value::Integer(1234));
        assert_eq!(decode(b"i-1234e").unwrap(), Value::Integer(-1234));
        assert_eq!(decode(b"i0e").unwrap(), Value::Integer(0));
        assert!(decode(b"i12a34e").is_err());
    }

    #[test]
    fn string() {
        assert_eq!(decode(b"5:abcde").unwrap(), Value::String(b"abcde".to_vec()));
        assert_eq!(decode(b"5:abcdefg").unwrap(), Value::String(b"abcde".to_vec()));
        assert_eq!(decode(b"0:").unwrap(), Value::String(b"".to_vec()));
        assert!(decode(b"-1:").is_err());
    }

    #[test]
    fn array() {
        assert_eq!(decode(b"li1234ee").unwrap(), Value::List(vec![Value::Integer(1234)]));
        assert_eq!(decode(b"li1234ei0ee").unwrap(), Value::List(vec![Value::Integer(1234), Value::Integer(0)]));
    }

    #[test]
    fn dict() {
        let mut expected = HashMap::new();
        expected.insert(b"cow".to_vec(), Value::String(b"moo".to_vec()));
        expected.insert(b"spam".to_vec(), Value::String(b"eggs".to_vec()));
        assert_eq!(decode(b"d3:cow3:moo4:spam4:eggse").unwrap(), Value::Dictionary(expected));
    }
}