extern crate futures; #[derive(Debug, PartialEq)] pub enum Error { CorruptVarint } #[derive(Debug, PartialEq)] pub enum Varint { /// a numeric value Value(u64), /// the reserved "unknown" value Unknown } /// Try to parse an EBML varint 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 size of the parsed varint. pub fn decode_varint(bytes: &[u8]) -> Result, Error> { 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 { Ok(Some((Varint::Unknown, value_length))) } else { Ok(Some((Varint::Value(value), value_length))) } } #[cfg(test)] mod tests { use futures::future::{ok, Future}; use super::{decode_varint, Error}; use super::Varint::{Unknown, Value}; #[test] fn hello_futures() { let my_future = ok::("Hello".into()) .map(|hello| hello + ", Futures!"); let string_result = my_future.wait().unwrap(); assert_eq!(string_result, "Hello, Futures!"); } #[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)))); } }