use clubcard::{Clubcard, ClubcardIndex, ClubcardIndexEntry}; use crate::query::{CRLiteCoverage, ClubcardError}; use crate::W; /// A type with a TLS-like binary encoding. pub(crate) trait Codec: Sized { /// Append the encoded form of `self` to `buf`. fn encode(&self, buf: &mut Vec); /// Parse one value of `Self` from the front of `buf`. /// /// Returns the parsed value together with the unconsumed remainder of `buf`. fn read(buf: &[u8]) -> Result<(Self, &[u8]), ClubcardError>; } // ``` // struct { // CRLiteCoverage universe; // ClubcardIndex index; // FilterColumn approx_filter; // uint32 count, then `count` columns // FilterColumn exact_filter; // } Clubcard; // ``` // // where `FilterColumn` is `uint64 words` (a uint32 count followed by // that many big-endian words). impl Codec for Clubcard { fn encode(&self, buf: &mut Vec) { self.universe.encode(buf); self.index.encode(buf); encode_len::<1>(self.approx_filter.len(), buf); for column in &self.approx_filter { encode_seq::<4, u64>(column, buf); } encode_seq::<4, u64>(&self.exact_filter, buf); } fn read(buf: &[u8]) -> Result<(Self, &[u8]), ClubcardError> { let (universe, buf) = CRLiteCoverage::read(buf)?; let (index, buf) = ClubcardIndex::read(buf)?; let (column_count, mut buf) = read_len::<1>(buf)?; let mut approx_filter = Vec::with_capacity(column_count); for _ in 0..column_count { let (column, rest) = read_seq::<4, u64>(buf)?; approx_filter.push(column); buf = rest; } let (exact_filter, buf) = read_seq::<4, u64>(buf)?; Ok(( Clubcard { universe, partition: (), index, approx_filter, exact_filter, }, buf, )) } } // ``` // struct { // uint8 len; // opaque serial[len]; // } Exception; // serial as opaque<0..2^8-1> // // struct { // uint32 approx_filter_m; // uint8 approx_filter_rank; // uint32 approx_filter_offset; // uint32 exact_filter_m; // uint32 exact_filter_offset; // uint8 inverted; // Exception exceptions; // uint16 count, then `count` serials // } ClubcardIndexEntry; // ``` impl Codec for ClubcardIndexEntry { fn encode(&self, buf: &mut Vec) { (self.approx_filter_m as u32).encode(buf); (self.approx_filter_rank as u8).encode(buf); (self.approx_filter_offset as u32).encode(buf); (self.exact_filter_m as u32).encode(buf); (self.exact_filter_offset as u32).encode(buf); (self.inverted as u8).encode(buf); encode_len::<2>(self.exceptions.len(), buf); for serial in &self.exceptions { encode_vec::<1>(serial, buf); } } fn read(buf: &[u8]) -> Result<(Self, &[u8]), ClubcardError> { let (approx_filter_m, buf) = u32::read(buf)?; let (approx_filter_rank, buf) = u8::read(buf)?; let (approx_filter_offset, buf) = u32::read(buf)?; let (exact_filter_m, buf) = u32::read(buf)?; let (exact_filter_offset, buf) = u32::read(buf)?; let (inverted, buf) = u8::read(buf)?; let (count, mut buf) = read_len::<2>(buf)?; let mut exceptions = Vec::with_capacity(count); for _ in 0..count { let (serial, rest) = read_vec::<1>(buf)?; exceptions.push(serial.to_vec()); buf = rest; } Ok(( ClubcardIndexEntry { approx_filter_m: approx_filter_m as usize, exact_filter_m: exact_filter_m as usize, approx_filter_rank: approx_filter_rank as usize, approx_filter_offset: approx_filter_offset as usize, exact_filter_offset: exact_filter_offset as usize, inverted: inverted != 0, exceptions, }, buf, )) } } // `uint64`, big-endian. impl Codec for u64 { fn encode(&self, buf: &mut Vec) { buf.extend_from_slice(&self.to_be_bytes()); } fn read(buf: &[u8]) -> Result<(Self, &[u8]), ClubcardError> { let (bytes, rest) = buf.split_first_chunk().ok_or(ClubcardError::Deserialize)?; Ok((u64::from_be_bytes(*bytes), rest)) } } // `uint32`, big-endian. impl Codec for u32 { fn encode(&self, buf: &mut Vec) { buf.extend_from_slice(&self.to_be_bytes()); } fn read(buf: &[u8]) -> Result<(Self, &[u8]), ClubcardError> { let (bytes, rest) = buf.split_first_chunk().ok_or(ClubcardError::Deserialize)?; Ok((u32::from_be_bytes(*bytes), rest)) } } // `uint8`. impl Codec for u8 { fn encode(&self, buf: &mut Vec) { buf.push(*self); } fn read(buf: &[u8]) -> Result<(Self, &[u8]), ClubcardError> { let (&val, rest) = buf.split_first().ok_or(ClubcardError::Deserialize)?; Ok((val, rest)) } } /// Append an `N`-byte big-endian length (or item count) prefix. pub(crate) fn encode_len(len: usize, buf: &mut Vec) { buf.extend_from_slice(&len.to_be_bytes()[size_of::() - N..]); } /// Read an `N`-byte big-endian length (or item count) prefix. pub(crate) fn read_len(buf: &[u8]) -> Result<(usize, &[u8]), ClubcardError> { let (len, rest) = buf .split_first_chunk::() .ok_or(ClubcardError::Deserialize)?; let mut padded = [0u8; size_of::()]; padded[size_of::() - N..].copy_from_slice(len); Ok((usize::from_be_bytes(padded), rest)) } /// opaque content<0..2^(8*N)-1>: an `N`-byte byte-length prefix followed by the bytes. pub(crate) fn encode_vec(content: &[u8], buf: &mut Vec) { encode_len::(content.len(), buf); buf.extend_from_slice(content); } pub(crate) fn read_vec(buf: &[u8]) -> Result<(&[u8], &[u8]), ClubcardError> { let (len, rest) = read_len::(buf)?; rest.split_at_checked(len).ok_or(ClubcardError::Deserialize) } /// `T items`: an `N`-byte item *count* prefix followed by that many encoded `T`s. /// /// Unlike a byte-length prefix, the explicit count lets [`read_seq`] size the /// result vector with a single allocation up front. pub(crate) fn encode_seq(items: &[T], buf: &mut Vec) { encode_len::(items.len(), buf); for item in items { item.encode(buf); } } pub(crate) fn read_seq( buf: &[u8], ) -> Result<(Vec, &[u8]), ClubcardError> { let (count, mut buf) = read_len::(buf)?; // Every item is at least one byte, so the remaining length bounds the count. // Capping the reservation keeps a corrupt prefix from forcing a huge allocation. let mut items = Vec::with_capacity(count); for _ in 0..count { let (item, rest) = T::read(buf)?; items.push(item); buf = rest; } Ok((items, buf)) }