use super::ParseError;
const LENGTH_TERMINATOR: char = 0x0a as char;
pub fn split(content: &[u8]) -> Result<(&[u8], &[u8]), ParseError> {
let (message_end, content) = length(content)?;
if content.len() <= message_end {
return Err(ParseError::UnexpectedEnding(content.len()));
}
Ok((&content[0..message_end], &content[message_end..]))
}
fn length(content: &[u8]) -> Result<(usize, &[u8]), ParseError> {
let mut terminator_position = 0;
let mut whitespace_position = 0;
for (index, byte) in content.iter().enumerate() {
if byte.is_ascii_whitespace() && whitespace_position == 0 {
whitespace_position = index;
}
if *byte as char == LENGTH_TERMINATOR {
terminator_position = index;
break;
}
}
if terminator_position == 0 {
return Err(ParseError::MissingTerminator);
}
let decimal_range = if whitespace_position > 0 {
0..whitespace_position
} else {
0..terminator_position
};
let decimal_slice = &content[decimal_range.clone()];
let decimal_string = std::str::from_utf8(&decimal_slice)
.map_err(|error| ParseError::InvalidUnicode(decimal_range, error))?;
let message_begin = terminator_position + 1;
let byte_count = decimal_string
.parse::<usize>()
.map_err(|error| ParseError::InvalidByteCount(decimal_string.into(), error))?;
if byte_count == 0 {
return Err(ParseError::EmptyByteCount);
}
let message_end = byte_count;
Ok((message_end, &content[message_begin..]))
}
#[cfg(test)]
mod tests {
#[test]
fn test_valid_header1() {
let number = 1234;
let remainder = "more!";
let contents = format!("{} \u{0a}{}", number, remainder);
let (a, b) = super::length(contents.as_bytes()).unwrap();
assert_eq!(number, a);
assert_eq!(remainder, std::str::from_utf8(&b).unwrap());
}
#[test]
fn test_valid_header2() {
let contents = "12\u{0a}";
let (_, b) = super::length(contents.as_bytes()).unwrap();
assert_eq!(&[] as &[u8], b);
}
#[test]
fn test_invalid_header1() {
let contents = "12";
assert!(match super::length(contents.as_bytes()) {
Err(super::ParseError::MissingTerminator) => true,
_ => false,
});
}
#[test]
fn test_invalid_header2() {
let contents = "12$48 \u{0a}";
assert!(match super::length(contents.as_bytes()) {
Err(super::ParseError::InvalidByteCount(_, _)) => true,
_ => false,
});
}
#[test]
fn test_message1() {
let contents = "8 \u{0a}12345678Example";
let (c, b) = super::length(contents.as_bytes()).unwrap();
let m1 = std::str::from_utf8(&b[0..c]).unwrap();
let m2 = std::str::from_utf8(&b[c..]).unwrap();
assert_eq!(m1, "12345678");
assert_eq!(m2, "Example");
}
}