webmetro/src/lib.rs

106 lines
2.8 KiB
Rust
Raw Normal View History

2017-01-10 03:40:21 +00:00
extern crate futures;
2017-01-12 05:41:35 +00:00
#[derive(Debug, PartialEq)]
pub enum Error {
CorruptVarint
}
#[derive(Debug, PartialEq)]
2017-01-12 12:37:29 +00:00
pub enum Varint {
2017-01-12 05:41:35 +00:00
Value(u64),
Unknown
}
/// Try to parse an EBML varint starting at the start of the given slice.
/// Returns an Err() if the format is corrupt.
/// Returns Ok(None) if more bytes are needed to get a result.
/// Returns Ok(Some((varint, next))) to return a varint value and
/// the starting location fo the next
2017-01-12 12:37:29 +00:00
pub fn decode_varint(bytes: &[u8]) -> Result<Option<(Varint, usize)>, Error> {
2017-01-12 05:41:35 +00:00
let mut value: u64 = 0;
let mut value_length = 1;
let mut mask: u8 = 0x80;
let mut unknown_marker: u64 = !0;
if bytes.len() == 0 {
return Ok(None)
}
// get length marker bit from first byte & parse first byte
while mask > 0 {
if (mask & bytes[0]) != 0 {
value = (bytes[0] & !mask) as u64;
unknown_marker = (mask - 1) as u64;
break
}
value_length += 1;
mask = mask >> 1;
}
if mask == 0 {
return Err(Error::CorruptVarint)
}
// check we have enough data to parse
if value_length > bytes.len() {
return Ok(None)
}
// decode remaining bytes
for i in 1..value_length {
value = (value << 8) + (bytes[i] as u64);
unknown_marker = (unknown_marker << 8) + 0xFF;
}
// determine result
if value == unknown_marker {
2017-01-12 12:37:29 +00:00
Ok(Some((Varint::Unknown, value_length)))
2017-01-12 05:41:35 +00:00
} else {
2017-01-12 12:37:29 +00:00
Ok(Some((Varint::Value(value), value_length)))
2017-01-12 05:41:35 +00:00
}
}
2017-01-10 03:40:21 +00:00
#[cfg(test)]
mod tests {
use futures::future::{ok, Future};
2017-01-12 05:41:35 +00:00
use super::{decode_varint, Error};
2017-01-12 12:37:29 +00:00
use super::Varint::{Unknown, Value};
2017-01-10 03:40:21 +00:00
#[test]
fn hello_futures() {
let my_future = ok::<String, ()>("Hello".into())
.map(|hello| hello + ", Futures!");
let string_result = my_future.wait().unwrap();
assert_eq!(string_result, "Hello, Futures!");
}
2017-01-12 05:41:35 +00:00
#[test]
fn fail_corrupted_varints() {
assert_eq!(decode_varint(&[0]), Err(Error::CorruptVarint));
assert_eq!(decode_varint(&[0, 0, 0]), Err(Error::CorruptVarint));
}
#[test]
fn incomplete_varints() {
assert_eq!(decode_varint(&[]), Ok(None));
assert_eq!(decode_varint(&[0x40]), Ok(None));
assert_eq!(decode_varint(&[0x01, 0, 0]), Ok(None));
}
#[test]
fn parse_varints() {
assert_eq!(decode_varint(&[0xFF]), Ok(Some((Unknown, 1))));
assert_eq!(decode_varint(&[0x7F, 0xFF]), Ok(Some((Unknown, 2))));
assert_eq!(decode_varint(&[0x80]), Ok(Some((Value(0), 1))));
assert_eq!(decode_varint(&[0x81]), Ok(Some((Value(1), 1))));
assert_eq!(decode_varint(&[0x40, 52]), Ok(Some((Value(52), 2))));
// test extra data in buffer
assert_eq!(decode_varint(&[0x83, 0x11]), Ok(Some((Value(3), 1))));
}
2017-01-10 03:40:21 +00:00
}