weavatrix-search-vector 0.3.1

Persistent, mutable, bounded vector candidate search for Rust and Weavatrix
Documentation
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)
}