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:
| Value | as_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.