Last active
December 29, 2016 21:10
-
-
Save jdiez17/0f98ef663fa5b74201f97384fd86b590 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
use std::vec::Vec; | |
use std::iter::Iterator; | |
use std::str; | |
use byteorder::{ByteOrder, LittleEndian}; | |
type SizeMap<'a> = HashMap<Vec<&'a str>, usize>; | |
fn element_size<'a, I>(path: I, bytes: &'a [u8]) -> (SizeMap<'a>, usize) | |
where I: IntoIterator<Item = &'a str> { | |
let el_type = bytes[0]; | |
let el_name_len = bytes.iter().position(|&c| c == 0x00).unwrap(); | |
let el_name = str::from_utf8(&bytes[1..el_name_len]).unwrap(); | |
// TODO this does not need to be mut | |
let mut el_path: Vec<_> = path.into_iter().collect(); | |
el_path.push(el_name); | |
let mut res = SizeMap::new(); | |
let mut i = 1 /* el_type */ + el_name_len; | |
i += match el_type { | |
// double | |
0x01 => 4, | |
// string | |
0x02 => { | |
panic!("TODO"); | |
} | |
// embedded document | |
0x03 => { | |
let (sz, incr) = document_size(el_path.clone(), &bytes[i..]); | |
res.extend(sz.into_iter()); | |
incr | |
} | |
// array | |
0x04 => { | |
let (sz, incr) = document_size(el_path.clone(), &bytes[i..]); | |
res.extend(sz.into_iter()); | |
incr | |
} | |
// binary | |
0x05 => { | |
panic!("TODO"); | |
} | |
// undefined (?) | |
0x06 => 0, | |
// ObjectId | |
0x07 => 12, | |
// bool | |
0x08 => 1, | |
_ => panic!("Unknown element type {}", el_type) | |
}; | |
res.insert(el_path, i); | |
(res, i) | |
} | |
fn document_size<'a, I>(path: I, bytes: &'a [u8]) -> (SizeMap<'a>, usize) | |
where I: IntoIterator<Item = &'a str> { | |
let doc_size = LittleEndian::read_u32(&bytes) as usize; | |
let el_path: Vec<_> = path.into_iter().collect(); | |
let mut res = SizeMap::new(); | |
let mut i = 4; | |
while bytes[i] != 0x00 { | |
let (sz, incr) = element_size(el_path.clone(), &bytes[i..]); | |
res.extend(sz.into_iter()); | |
i += incr; | |
} | |
i += 1; | |
assert!(doc_size == i); | |
res.insert(el_path, i); | |
(res, i) | |
} | |
fn bson_size(bytes: &[u8]) -> SizeMap { | |
let (sz, _) = document_size(vec!["root"], &bytes[..]); | |
sz | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn test_sizes() { | |
let doc = vec![ | |
0x21, 0x00, 0x00, 0x00, // Document size | |
0x08, 0x66, 0x6f, 0x6f, 0x00, 0x01, // "foo" => true | |
0x08, 0x62, 0x61, 0x72, 0x00, 0x00, // "bar" => false | |
0x03, 0x62, 0x61, 0x7a, 0x00, // "baz" => { | |
0x0b, 0x00, 0x00, 0x00, | |
0x08, 0x71, 0x75, 0x78, 0x00, 0x01, // "qux" => true } | |
0x00, | |
0x00 // Document end | |
]; | |
let mut expct = SizeMap::new(); | |
expct.insert(vec!["root"], 0x21); | |
expct.insert(vec!["root", "foo"], 0x06); | |
expct.insert(vec!["root", "bar"], 0x06); | |
expct.insert(vec!["root", "baz"], 0x10); | |
expct.insert(vec!["root", "baz", "qux"], 0x06); | |
assert_eq!(expct, bson_size(&doc[..])); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment