use oxgraph_snapshot::kinds;
use zerocopy::{
FromBytes, Immutable, IntoBytes, KnownLayout,
byteorder::{LE, U32, U64},
};
use crate::{
ElementId, IncidenceId, PropertyFamily, PropertySubject, PropertyType, RelationId,
RelationTypeId,
};
pub(crate) const OXGDB_FORMAT_VERSION: u32 = 1;
pub(crate) const OXGDB_SECTION_VERSION: u32 = 1;
pub(crate) const RELATION_TYPE_NONE: u64 = 0;
pub(crate) const SECTION_DB_HEADER: u32 = 0x0300;
pub(crate) const SECTION_STRING_TABLE: u32 = 0x0301;
pub(crate) const SECTION_CATALOG_ROLES: u32 = 0x0302;
pub(crate) const SECTION_CATALOG_LABELS: u32 = 0x0303;
pub(crate) const SECTION_CATALOG_RELATION_TYPES: u32 = 0x0304;
pub(crate) const SECTION_CATALOG_PROPERTY_KEYS: u32 = 0x0305;
pub(crate) const SECTION_CATALOG_PROJECTIONS: u32 = 0x0306;
pub(crate) const SECTION_CATALOG_INDEXES: u32 = 0x0307;
pub(crate) const SECTION_CATALOG_DEFS: u32 = 0x0308;
pub(crate) const SECTION_ELEMENT_RECORDS: u32 = 0x0310;
pub(crate) const SECTION_ELEMENT_LABELS: u32 = 0x0311;
pub(crate) const SECTION_RELATION_RECORDS: u32 = 0x0312;
pub(crate) const SECTION_RELATION_LABELS: u32 = 0x0313;
pub(crate) const SECTION_INCIDENCE_RECORDS: u32 = 0x0314;
pub(crate) const SECTION_PROPERTY_SNAPSHOT: u32 = 0x0320;
pub(crate) const SECTION_IDENTITY_MAP: u32 = 0x0321;
pub(crate) const SECTION_PROPERTY_RECORDS: u32 = 0x0322;
pub(crate) const SECTION_PROPERTY_TEXT: u32 = 0x0323;
pub(crate) const SECTION_CSR_OUT: u32 = 0x0330;
pub(crate) const SECTION_CSC_IN: u32 = 0x0331;
pub(crate) const SECTION_HYPER_BCSR: u32 = 0x0332;
pub(crate) const SECTION_INDEX_EQUALITY: u32 = 0x0340;
pub(crate) const SECTION_INDEX_LABEL_POSTINGS: u32 = 0x0341;
pub(crate) const ALL_SECTION_KINDS: [u32; 23] = [
SECTION_DB_HEADER,
SECTION_STRING_TABLE,
SECTION_CATALOG_ROLES,
SECTION_CATALOG_LABELS,
SECTION_CATALOG_RELATION_TYPES,
SECTION_CATALOG_PROPERTY_KEYS,
SECTION_CATALOG_PROJECTIONS,
SECTION_CATALOG_INDEXES,
SECTION_CATALOG_DEFS,
SECTION_ELEMENT_RECORDS,
SECTION_ELEMENT_LABELS,
SECTION_RELATION_RECORDS,
SECTION_RELATION_LABELS,
SECTION_INCIDENCE_RECORDS,
SECTION_PROPERTY_SNAPSHOT,
SECTION_IDENTITY_MAP,
SECTION_PROPERTY_RECORDS,
SECTION_PROPERTY_TEXT,
SECTION_CSR_OUT,
SECTION_CSC_IN,
SECTION_HYPER_BCSR,
SECTION_INDEX_EQUALITY,
SECTION_INDEX_LABEL_POSTINGS,
];
const _: () = {
let mut index = 0;
while index < ALL_SECTION_KINDS.len() {
assert!(
kinds::in_band(ALL_SECTION_KINDS[index], kinds::DATABASE_BAND),
"OXGDB section kind escaped DATABASE_BAND",
);
index += 1;
}
};
#[derive(Clone, Copy, Debug, FromBytes, Immutable, IntoBytes, KnownLayout)]
#[repr(C)]
pub(crate) struct DbHeaderRecord {
pub(crate) format_version: U32<LE>,
pub(crate) flags: U32<LE>,
pub(crate) commit_seq: U64<LE>,
pub(crate) transaction_id: U64<LE>,
pub(crate) checkpoint_generation: U64<LE>,
pub(crate) next_element: U64<LE>,
pub(crate) next_relation: U64<LE>,
pub(crate) next_incidence: U64<LE>,
pub(crate) next_role: U64<LE>,
pub(crate) next_label: U64<LE>,
pub(crate) next_relation_type: U64<LE>,
pub(crate) next_property_key: U64<LE>,
pub(crate) next_projection: U64<LE>,
pub(crate) next_index: U64<LE>,
}
#[derive(Clone, Copy, Debug, FromBytes, Immutable, IntoBytes, KnownLayout)]
#[repr(C)]
pub(crate) struct NamedWire {
pub(crate) id: U64<LE>,
pub(crate) name_off: U32<LE>,
pub(crate) name_len: U32<LE>,
}
#[derive(Clone, Copy, Debug, FromBytes, Immutable, IntoBytes, KnownLayout)]
#[repr(C)]
pub(crate) struct PropertyKeyWire {
pub(crate) id: U64<LE>,
pub(crate) name_off: U32<LE>,
pub(crate) name_len: U32<LE>,
pub(crate) family: U32<LE>,
pub(crate) value_type: U32<LE>,
}
#[derive(Clone, Copy, Debug, FromBytes, Immutable, IntoBytes, KnownLayout)]
#[repr(C)]
pub(crate) struct DefWire {
pub(crate) id: U64<LE>,
pub(crate) name_off: U32<LE>,
pub(crate) name_len: U32<LE>,
pub(crate) kind: U32<LE>,
pub(crate) payload_off: U32<LE>,
pub(crate) payload_len: U32<LE>,
}
#[derive(Clone, Copy, Debug, FromBytes, Immutable, IntoBytes, KnownLayout)]
#[repr(C)]
pub(crate) struct ElementWire {
pub(crate) id: U64<LE>,
pub(crate) label_off: U32<LE>,
pub(crate) label_len: U32<LE>,
}
#[derive(Clone, Copy, Debug, FromBytes, Immutable, IntoBytes, KnownLayout)]
#[repr(C)]
pub(crate) struct RelationWire {
pub(crate) id: U64<LE>,
pub(crate) relation_type: U64<LE>,
pub(crate) label_off: U32<LE>,
pub(crate) label_len: U32<LE>,
}
#[derive(Clone, Copy, Debug, FromBytes, Immutable, IntoBytes, KnownLayout)]
#[repr(C)]
pub(crate) struct IncidenceWire {
pub(crate) id: U64<LE>,
pub(crate) relation: U64<LE>,
pub(crate) element: U64<LE>,
pub(crate) role: U64<LE>,
}
pub(crate) const fn encode_relation_type(value: Option<RelationTypeId>) -> u64 {
match value {
None => RELATION_TYPE_NONE,
Some(id) => id.get(),
}
}
pub(crate) const fn decode_relation_type(raw: u64) -> Option<RelationTypeId> {
if raw == RELATION_TYPE_NONE {
None
} else {
Some(RelationTypeId::new(raw))
}
}
pub(crate) const fn property_family_tag(family: PropertyFamily) -> u32 {
match family {
PropertyFamily::Element => 0,
PropertyFamily::Relation => 1,
PropertyFamily::Incidence => 2,
}
}
pub(crate) const fn property_family_from_tag(tag: u32) -> Option<PropertyFamily> {
match tag {
0 => Some(PropertyFamily::Element),
1 => Some(PropertyFamily::Relation),
2 => Some(PropertyFamily::Incidence),
_ => None,
}
}
pub(crate) const fn property_type_tag(value_type: PropertyType) -> u32 {
match value_type {
PropertyType::Boolean => 0,
PropertyType::Integer => 1,
PropertyType::Text => 2,
}
}
pub(crate) const fn property_type_from_tag(tag: u32) -> Option<PropertyType> {
match tag {
0 => Some(PropertyType::Boolean),
1 => Some(PropertyType::Integer),
2 => Some(PropertyType::Text),
_ => None,
}
}
pub(crate) const fn encode_subject(subject: PropertySubject) -> (u32, u64) {
match subject {
PropertySubject::Element(id) => (0, id.get()),
PropertySubject::Relation(id) => (1, id.get()),
PropertySubject::Incidence(id) => (2, id.get()),
}
}
pub(crate) const fn decode_subject(kind: u32, id: u64) -> Option<PropertySubject> {
match kind {
0 => Some(PropertySubject::Element(ElementId::new(id))),
1 => Some(PropertySubject::Relation(RelationId::new(id))),
2 => Some(PropertySubject::Incidence(IncidenceId::new(id))),
_ => None,
}
}
#[derive(Clone, Copy, Debug, FromBytes, Immutable, IntoBytes, KnownLayout)]
#[repr(C)]
pub(crate) struct PropertyWire {
pub(crate) subject_kind: U32<LE>,
pub(crate) value_tag: U32<LE>,
pub(crate) subject_id: U64<LE>,
pub(crate) key: U64<LE>,
pub(crate) scalar: U64<LE>,
pub(crate) text_off: U32<LE>,
pub(crate) text_len: U32<LE>,
}
#[cfg(test)]
mod tests {
use proptest::prelude::*;
use super::*;
proptest! {
#[test]
fn relation_type_some_roundtrips(raw in 1u64..=u64::MAX) {
let id = RelationTypeId::new(raw);
prop_assert_eq!(decode_relation_type(encode_relation_type(Some(id))), Some(id));
}
}
#[test]
fn relation_type_none_uses_sentinel() {
assert_eq!(encode_relation_type(None), RELATION_TYPE_NONE);
assert_eq!(decode_relation_type(RELATION_TYPE_NONE), None);
}
#[test]
fn property_family_tags_roundtrip() {
for family in [
PropertyFamily::Element,
PropertyFamily::Relation,
PropertyFamily::Incidence,
] {
assert_eq!(
property_family_from_tag(property_family_tag(family)),
Some(family)
);
}
assert_eq!(property_family_from_tag(3), None);
}
#[test]
fn property_type_tags_roundtrip() {
for value_type in [
PropertyType::Boolean,
PropertyType::Integer,
PropertyType::Text,
] {
assert_eq!(
property_type_from_tag(property_type_tag(value_type)),
Some(value_type)
);
}
assert_eq!(property_type_from_tag(3), None);
}
}