use crate::db::schema::FieldId;
use std::num::NonZeroU32;
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub(in crate::db) struct SchemaVersion(u32);
impl SchemaVersion {
#[must_use]
pub(in crate::db) const fn new(raw: u32) -> Self {
Self(raw)
}
#[must_use]
pub(in crate::db) const fn initial() -> Self {
Self(1)
}
#[must_use]
pub(in crate::db) const fn get(self) -> u32 {
self.0
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub(in crate::db) struct RowLayoutVersion(NonZeroU32);
impl RowLayoutVersion {
pub(in crate::db) const INITIAL: Self = Self(NonZeroU32::MIN);
#[must_use]
pub(in crate::db) const fn new(raw: u32) -> Option<Self> {
match NonZeroU32::new(raw) {
Some(raw) => Some(Self(raw)),
None => None,
}
}
#[must_use]
pub(in crate::db) const fn get(self) -> u32 {
self.0.get()
}
#[must_use]
pub(in crate::db) const fn checked_next(self) -> Option<Self> {
match self.get().checked_add(1) {
Some(raw) => Self::new(raw),
None => None,
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub(in crate::db) struct SchemaFieldSlot(u16);
impl SchemaFieldSlot {
#[must_use]
pub(in crate::db) const fn new(raw: u16) -> Self {
Self(raw)
}
#[must_use]
pub(in crate::db) fn from_generated_index(index: usize) -> Self {
let slot = u16::try_from(index).expect("schema layout invariant");
Self(slot)
}
#[must_use]
pub(in crate::db) const fn get(self) -> u16 {
self.0
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) struct SchemaRowLayout {
current_version: RowLayoutVersion,
history_floor: RowLayoutVersion,
field_to_slot: Vec<(FieldId, SchemaFieldSlot)>,
}
impl SchemaRowLayout {
#[must_use]
pub(in crate::db) const fn new(
current_version: RowLayoutVersion,
history_floor: RowLayoutVersion,
field_to_slot: Vec<(FieldId, SchemaFieldSlot)>,
) -> Self {
Self {
current_version,
history_floor,
field_to_slot,
}
}
#[must_use]
pub(in crate::db) const fn single_version(
version: RowLayoutVersion,
field_to_slot: Vec<(FieldId, SchemaFieldSlot)>,
) -> Self {
Self::new(version, version, field_to_slot)
}
#[must_use]
#[cfg(test)]
pub(in crate::db) const fn initial(field_to_slot: Vec<(FieldId, SchemaFieldSlot)>) -> Self {
Self::single_version(RowLayoutVersion::INITIAL, field_to_slot)
}
#[must_use]
pub(in crate::db) const fn current_version(&self) -> RowLayoutVersion {
self.current_version
}
#[must_use]
pub(in crate::db) const fn history_floor(&self) -> RowLayoutVersion {
self.history_floor
}
#[must_use]
pub(in crate::db) const fn field_to_slot(&self) -> &[(FieldId, SchemaFieldSlot)] {
self.field_to_slot.as_slice()
}
#[must_use]
#[cfg(any(test, feature = "sql"))]
pub(in crate::db) fn next_unallocated_slot(&self) -> SchemaFieldSlot {
SchemaFieldSlot::from_generated_index(self.field_to_slot.len())
}
#[must_use]
pub(in crate::db) const fn allocated_slot_count(&self) -> usize {
self.field_to_slot.len()
}
#[must_use]
pub(in crate::db) fn slot_for_field(&self, field_id: FieldId) -> Option<SchemaFieldSlot> {
self.field_to_slot
.iter()
.find_map(|(id, slot)| (*id == field_id).then_some(*slot))
}
}