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.