Implement metaframe parsing

next
Sayan Nandan 3 years ago
parent 559af81ee9
commit 2fed0e876b

@ -45,30 +45,44 @@ impl<'a> Parser<'a> {
buffer,
}
}
fn read_until(&self, until: usize) -> ParseResult<&[u8]> {
if let Some(b) = self.buffer.get(self.cursor + 1..until) {
/// Read from the current cursor position to `until` number of positions ahead
/// This **will forward the cursor itself** if the bytes exist or it will just return a `NotEnough` error
fn read_until(&mut self, until: usize) -> ParseResult<&[u8]> {
if let Some(b) = self.buffer.get(self.cursor..self.cursor + until) {
self.cursor += until;
Ok(b)
} else {
Err(ParseError::NotEnough)
}
}
/// This returns the position at which the line parsing began and the position at which the line parsing
/// stopped, in other words, you should be able to do self.buffer[started_at..stopped_at] to get a line
/// and do it unchecked. This **will move the internal cursor ahead**
fn read_line(&mut self) -> (usize, usize) {
let started_at = self.cursor;
let mut stopped_at = self.cursor;
while self.cursor < self.buffer.len() {
if self.buffer[self.cursor] == b'\n' {
// Oh no! Newline reached, time to break the loop
// But before that ... we read the newline, so let's advance the cursor
self.incr_cursor();
break;
}
// So this isn't an LF, great! Let's forward the stopped_at position
stopped_at += 1;
self.incr_cursor();
}
(started_at, stopped_at)
}
/// This function will return the number of bytes this sizeline has (this is usually the number of items in
/// the following line)
/// This **will forward the cursor itself**
fn read_sizeline(&mut self) -> ParseResult<usize> {
if let Some(b'#') = self.buffer.get(self.cursor) {
// Good, we found a #; time to move ahead
self.incr_cursor();
let started_at = self.cursor;
let mut stopped_at = self.cursor;
while self.cursor < self.buffer.len() {
if self.buffer[self.cursor] == b'\n' {
// Oh no! Newline reached, time to break the loop
// But before that ... we read the newline, so let's advance the cursor
self.incr_cursor();
break;
}
// So this isn't an LF, great! Let's forward the stopped_at position
stopped_at += 1;
self.incr_cursor();
}
// Now read the remaining line
let (started_at, stopped_at) = self.read_line();
Self::parse_into_usize(&self.buffer[started_at..stopped_at])
} else {
// A sizeline should begin with a '#'; this one doesn't so it's a bad packet; ugh
@ -96,6 +110,27 @@ impl<'a> Parser<'a> {
}
Ok(item_usize)
}
/// This will return the number of datagroups present in this query packet
///
/// This **will forward the cursor itself**
fn parse_metaframe(&mut self) -> ParseResult<usize> {
// This will give us the `#<m>\n`
let metaframe_sizeline = self.read_sizeline()?;
// Now we want to read `*<n>\n`
let our_chunk = self.read_until(metaframe_sizeline)?;
if our_chunk[0] == b'!' {
// Good, this will tell us the number of actions
// Let us attempt to read the usize from this point onwards
// that is excluding the '!' (so 1..)
// also push the cursor ahead because we want to ignore the LF char
// as read_until won't skip the newline
let ret = Self::parse_into_usize(&our_chunk[1..])?;
self.incr_cursor();
Ok(ret)
} else {
Err(ParseError::UnexpectedByte)
}
}
}
#[test]
@ -103,4 +138,13 @@ fn test_sizeline_parse() {
let sizeline = "#125\n".as_bytes();
let mut parser = Parser::new(&sizeline);
assert_eq!(125, parser.read_sizeline().unwrap());
assert_eq!(parser.cursor, sizeline.len());
}
#[test]
fn test_metaframe_parse() {
let metaframe = "#2\n!2\n".as_bytes();
let mut parser = Parser::new(&metaframe);
assert_eq!(2, parser.parse_metaframe().unwrap());
assert_eq!(parser.cursor, metaframe.len());
}

Loading…
Cancel
Save