use super::codec::{Decoder, Encoder};
use crate::error::SearchError;
use crate::metadata::MetadataValue;
pub(super) const MAGIC: &[u8; 8] = b"WVSBND03";
pub(super) const VERSION: u32 = 2;
pub(super) const HEADER_LEN: usize = 80;
pub(super) const FNV_OFFSET: u64 = 0xcbf2_9ce4_8422_2325;
pub(super) const FNV_PRIME: u64 = 0x0000_0100_0000_01b3;
pub(super) fn encode_value(
encoder: &mut Encoder,
value: &MetadataValue,
) -> Result<(), SearchError> {
match value {
MetadataValue::Bool(value) => {
encoder.u8(0)?;
encoder.u8(u8::from(*value))
}
MetadataValue::I64(value) => {
encoder.u8(1)?;
encoder.bytes(&value.to_le_bytes())
}
MetadataValue::U64(value) => {
encoder.u8(2)?;
encoder.u64(*value)
}
MetadataValue::Text(value) => {
encoder.u8(3)?;
encoder.length_prefixed(value.as_bytes())
}
MetadataValue::Bytes(value) => {
encoder.u8(4)?;
encoder.length_prefixed(value)
}
}
}
pub(super) fn decode_value(decoder: &mut Decoder<'_>) -> Result<MetadataValue, SearchError> {
match decoder.u8()? {
0 => match decoder.u8()? {
0 => Ok(MetadataValue::Bool(false)),
1 => Ok(MetadataValue::Bool(true)),
_ => Err(SearchError::CorruptSnapshot(
"metadata Boolean value is invalid",
)),
},
1 => Ok(MetadataValue::I64(i64::from_le_bytes(
decoder
.take(8)?
.try_into()
.expect("checked eight-byte metadata value"),
))),
2 => Ok(MetadataValue::U64(decoder.u64()?)),
3 => Ok(MetadataValue::Text(
String::from_utf8(decoder.length_prefixed()?.to_vec())
.map_err(|_| SearchError::CorruptSnapshot("metadata text is not UTF-8"))?,
)),
4 => Ok(MetadataValue::Bytes(decoder.length_prefixed()?.to_vec())),
_ => Err(SearchError::CorruptSnapshot(
"metadata value tag is unknown",
)),
}
}
pub(super) fn read_u32(bytes: &[u8], offset: usize) -> Result<u32, SearchError> {
Ok(u32::from_le_bytes(
bytes
.get(offset..offset + 4)
.ok_or(SearchError::CorruptSnapshot("bundle u32 is truncated"))?
.try_into()
.expect("checked four-byte header value"),
))
}
pub(super) fn read_u64(bytes: &[u8], offset: usize) -> Result<u64, SearchError> {
Ok(u64::from_le_bytes(
bytes
.get(offset..offset + 8)
.ok_or(SearchError::CorruptSnapshot("bundle u64 is truncated"))?
.try_into()
.expect("checked eight-byte header value"),
))
}
pub(super) fn put_u32(bytes: &mut [u8], offset: usize, value: u32) {
bytes[offset..offset + 4].copy_from_slice(&value.to_le_bytes());
}
pub(super) fn put_u64(bytes: &mut [u8], offset: usize, value: u64) {
bytes[offset..offset + 8].copy_from_slice(&value.to_le_bytes());
}
pub(super) fn to_u32(value: usize) -> Result<u32, SearchError> {
u32::try_from(value).map_err(|_| SearchError::CapacityOverflow)
}
pub(super) fn to_u64(value: usize) -> Result<u64, SearchError> {
u64::try_from(value).map_err(|_| SearchError::CapacityOverflow)
}
pub(super) fn to_usize(value: u64) -> Result<usize, SearchError> {
usize::try_from(value).map_err(|_| SearchError::CapacityOverflow)
}