use serde::{Deserialize, Serialize};
use crate::{BufferOverflowOr, DatabaseEntry, Unifier};
type KeyRange<KU> = (<KU as Unifier>::D, <KU as Unifier>::D);
#[derive(Debug)]
pub(crate) enum Subtable {
Main,
Reserved,
Index(u8),
}
impl Serialize for Subtable {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let value = match self {
Subtable::Main => 0u8,
Subtable::Reserved => 1u8,
Subtable::Index(discriminator) => {
discriminator.checked_add(2).ok_or_else(|| {
serde::ser::Error::custom("Index discriminator overflow when adding 2")
})?
}
};
serializer.serialize_u8(value)
}
}
impl<'de> Deserialize<'de> for Subtable {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = u8::deserialize(deserializer)?;
match value {
0 => Ok(Subtable::Main),
1 => Err(serde::de::Error::custom("Reserved subtable value 1")),
n => Ok(Subtable::Index(n.checked_sub(2).ok_or_else(|| {
serde::de::Error::custom("Index discriminator underflow when subtracting 2")
})?)),
}
}
}
#[derive(Serialize, Deserialize, Debug)]
pub(crate) struct WrapPrelude {
scope: u8,
subtable: Subtable,
}
impl WrapPrelude {
pub fn new<R: DatabaseEntry>(subtable: Subtable) -> Self {
WrapPrelude {
scope: R::SCOPE,
subtable,
}
}
}
#[derive(Serialize, Deserialize, Debug)]
pub(crate) struct Wrap<R> {
prelude: WrapPrelude,
pub key: R,
}
pub(crate) fn wrap<R: DatabaseEntry, KU: Unifier>(
item_key: &R::Key,
unifier: &KU,
buffer: &mut KU::D,
) -> Result<(), BufferOverflowOr<KU::SerError>> {
unifier.serialize(buffer, WrapPrelude::new::<R>(Subtable::Main))?;
unifier.serialize_ref(buffer, item_key)?;
Ok(())
}
pub(crate) fn empty_wrap<R: DatabaseEntry, KU: Unifier>(
config: &KU,
) -> Result<KeyRange<KU>, BufferOverflowOr<KU::SerError>> {
let start = Wrap {
prelude: WrapPrelude {
scope: R::SCOPE,
subtable: Subtable::Main,
},
key: (),
};
let end = Wrap {
prelude: WrapPrelude {
scope: R::SCOPE,
subtable: Subtable::Reserved,
},
key: (),
};
let mut start_buffer = KU::D::default();
config.serialize(&mut start_buffer, start)?;
let mut end_buffer = KU::D::default();
config.serialize(&mut end_buffer, end)?;
Ok((start_buffer, end_buffer))
}