use std::{
convert::{TryFrom, TryInto},
io::{self, Read},
};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use super::{Error, MemoType, Report, ReportAuthorizationKey, SignedReport, TemporaryContactKey};
trait ReadExt: io::Read + Sized {
#[inline]
fn read_32_bytes(&mut self) -> io::Result<[u8; 32]> {
let mut bytes = [0; 32];
self.read_exact(&mut bytes)?;
Ok(bytes)
}
#[inline]
fn read_64_bytes(&mut self) -> io::Result<[u8; 64]> {
let mut bytes = [0; 64];
self.read_exact(&mut bytes)?;
Ok(bytes)
}
#[inline]
fn read_compact_vec(&mut self) -> io::Result<Vec<u8>> {
let len = self.read_u8()? as usize;
let mut bytes = Vec::with_capacity(len);
self.take(len as u64).read_to_end(&mut bytes)?;
Ok(bytes)
}
}
impl<R: io::Read> ReadExt for R {}
impl TryFrom<u8> for MemoType {
type Error = Error;
fn try_from(t: u8) -> Result<MemoType, Self::Error> {
match t {
0 => Ok(MemoType::CoEpiV1),
1 => Ok(MemoType::CovidWatchV1),
t => Err(Error::UnknownMemoType(t)),
}
}
}
impl Report {
pub(crate) fn size_hint(&self) -> usize {
32 + 32 + 2 + 2 + 1 + 1 + self.memo_data.len()
}
pub fn read<R: std::io::Read>(mut reader: R) -> Result<Report, Error> {
let report = Report {
rvk: reader.read_32_bytes()?.into(),
tck_bytes: reader.read_32_bytes()?,
j_1: reader.read_u16::<LittleEndian>()?,
j_2: reader.read_u16::<LittleEndian>()?,
memo_type: reader.read_u8()?.try_into()?,
memo_data: reader.read_compact_vec()?,
};
if report.j_1 > 0 {
Ok(report)
} else {
Err(Error::InvalidReportIndex)
}
}
pub fn write<W: io::Write>(&self, mut writer: W) -> Result<(), Error> {
let memo_len = u8::try_from(self.memo_data.len())
.map_err(|_| Error::OversizeMemo(self.memo_data.len()))?;
writer.write_all(&<[u8; 32]>::from(self.rvk))?;
writer.write_all(&self.tck_bytes)?;
writer.write_u16::<LittleEndian>(self.j_1)?;
writer.write_u16::<LittleEndian>(self.j_2)?;
writer.write_u8(self.memo_type as u8)?;
writer.write_u8(memo_len)?;
writer.write_all(&self.memo_data)?;
Ok(())
}
}
impl SignedReport {
pub fn read<R: io::Read>(mut reader: R) -> Result<SignedReport, Error> {
Ok(SignedReport {
report: Report::read(&mut reader)?,
sig: reader.read_64_bytes()?.into(),
})
}
pub fn write<W: io::Write>(&self, mut writer: W) -> Result<(), Error> {
self.report.write(&mut writer)?;
writer.write_all(&<[u8; 64]>::from(self.sig)[..])?;
Ok(())
}
}
impl ReportAuthorizationKey {
pub fn read<R: io::Read>(mut reader: R) -> Result<ReportAuthorizationKey, io::Error> {
Ok(ReportAuthorizationKey {
rak: reader.read_32_bytes()?.into(),
})
}
pub fn write<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
writer.write_all(&<[u8; 32]>::from(self.rak))
}
}
impl TemporaryContactKey {
pub fn read<R: io::Read>(mut reader: R) -> Result<TemporaryContactKey, io::Error> {
Ok(TemporaryContactKey {
index: reader.read_u16::<LittleEndian>()?,
rvk: reader.read_32_bytes()?.into(),
tck_bytes: reader.read_32_bytes()?,
})
}
pub fn write<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
writer.write_u16::<LittleEndian>(self.index)?;
writer.write_all(&<[u8; 32]>::from(self.rvk))?;
writer.write_all(&self.tck_bytes)?;
Ok(())
}
}