Helper for serializing Option<T>

This commit is contained in:
Jack Grigg 2018-12-01 17:16:32 +00:00
parent 667d6101c9
commit 70a7069058
No known key found for this signature in database
GPG Key ID: 9E8255172BBF9898
1 changed files with 73 additions and 0 deletions

View File

@ -82,6 +82,37 @@ impl Vector {
}
}
pub struct Optional;
impl Optional {
pub fn read<R: Read, T, F>(mut reader: R, func: F) -> io::Result<Option<T>>
where
F: Fn(&mut R) -> io::Result<T>,
{
match reader.read_u8()? {
0 => Ok(None),
1 => Ok(Some(func(&mut reader)?)),
_ => Err(io::Error::new(
io::ErrorKind::InvalidInput,
"non-canonical Option<T>",
)),
}
}
pub fn write<W: Write, T, F>(mut writer: W, val: &Option<T>, func: F) -> io::Result<()>
where
F: Fn(&mut W, &T) -> io::Result<()>,
{
match val {
None => writer.write_u8(0),
Some(e) => {
writer.write_u8(1)?;
func(&mut writer, e)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
@ -153,4 +184,46 @@ mod tests {
eval!(vec![7; 260], expected);
}
}
#[test]
fn optional() {
macro_rules! eval {
($value:expr, $expected:expr, $write:expr, $read:expr) => {
let mut data = vec![];
Optional::write(&mut data, &$value, $write).unwrap();
assert_eq!(&data[..], &$expected[..]);
match Optional::read(&data[..], $read) {
Ok(v) => assert_eq!(v, $value),
Err(e) => panic!("Unexpected error: {:?}", e),
}
};
}
macro_rules! eval_u8 {
($value:expr, $expected:expr) => {
eval!($value, $expected, |w, e| w.write_u8(*e), |r| r.read_u8())
};
}
macro_rules! eval_vec {
($value:expr, $expected:expr) => {
eval!(
$value,
$expected,
|w, v| Vector::write(w, v, |w, e| w.write_u8(*e)),
|r| Vector::read(r, |r| r.read_u8())
)
};
}
eval_u8!(None, [0]);
eval_u8!(Some(0), [1, 0]);
eval_u8!(Some(1), [1, 1]);
eval_u8!(Some(5), [1, 5]);
eval_vec!(Some(vec![]), [1, 0]);
eval_vec!(Some(vec![0]), [1, 1, 0]);
eval_vec!(Some(vec![1]), [1, 1, 1]);
eval_vec!(Some(vec![5; 8]), [1, 8, 5, 5, 5, 5, 5, 5, 5, 5]);
}
}