Key Trait

The Key trait enables types to define a serialization and deserialization format that preserves the order of the original type in serialized form. Whe comparing two values encoded with as_ord_bytes() using a byte-by-byte comparison operation should match the result produced by comparing the two original values using the Ord. For integer formats, this generally means encoding the bytes in network byte order (big endian).

For example, let's consider two values:

Valueas_ord_bytes()
1u16[ 0, 1]
300u16[ 1, 44]

1_u16.cmp(&300_u16) and 1_u16.as_ord_bytes()?.cmp(&300_u16.as_ord_bytes()?) both produce Ordering::Less.

Implementing the Key trait

The Key trait declares two functions: as_ord_bytes() and from_ord_bytes. The intention is to convert the type to bytes using a network byte order for numerical types, and for non-numerical types, the bytes need to be stored in binary-sortable order.

Here is how BonsaiDb implements Key for EnumKey:

impl<'k, T> Key<'k> for EnumKey<T>
where
    T: ToPrimitive + FromPrimitive + Clone + Eq + Ord + std::fmt::Debug + Send + Sync,
{
    const CAN_OWN_BYTES: bool = false;

    fn from_ord_bytes<'b>(bytes: ByteSource<'k, 'b>) -> Result<Self, Self::Error> {
        let primitive = u64::decode_variable(bytes.as_ref())?;
        T::from_u64(primitive)
            .map(Self)
            .ok_or_else(|| io::Error::new(ErrorKind::InvalidData, UnknownEnumVariant))
    }
}

impl<T> KeyEncoding<Self> for EnumKey<T>
where
    T: ToPrimitive + FromPrimitive + Clone + Eq + Ord + std::fmt::Debug + Send + Sync,
{
    type Error = io::Error;

    const LENGTH: Option<usize> = None;

    fn describe<Visitor>(visitor: &mut Visitor)
    where
        Visitor: KeyVisitor,
    {
        visitor.visit_type(KeyKind::Unsigned);
    }

    fn as_ord_bytes(&self) -> Result<Cow<'_, [u8]>, Self::Error> {
        let integer = self
            .0
            .to_u64()
            .map(Unsigned::from)
            .ok_or_else(|| io::Error::new(ErrorKind::InvalidData, IncorrectByteLength))?;
        Ok(Cow::Owned(integer.to_variable_vec()?))
    }
}

By implementing Key you can take full control of converting your view keys.