use core::mem::size_of;
use plugmem_arena::{BlobId, ListHandle, Slot, TermId, key};
use crate::id::{EdgeId, EntityId, FactId, NONE_U32};
pub const VALID_TO_OPEN: u64 = u64::MAX;
pub mod fact_flags {
pub const TOMBSTONE: u16 = 1;
pub const CLOSED: u16 = 1 << 1;
pub const HAS_VECTOR: u16 = 1 << 2;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FactRecord {
pub id: FactId,
pub entity: EntityId,
pub flags: u16,
pub kind: u16,
pub text: BlobId,
pub vector: u32,
pub revises: FactId,
pub recorded_at: u64,
pub valid_from: u64,
pub valid_to: u64,
}
impl FactRecord {
pub fn is_tombstone(&self) -> bool {
self.flags & fact_flags::TOMBSTONE != 0
}
pub fn is_closed(&self) -> bool {
self.flags & fact_flags::CLOSED != 0
}
pub fn has_vector(&self) -> bool {
self.flags & fact_flags::HAS_VECTOR != 0
}
pub fn is_live_at(&self, t: u64) -> bool {
!self.is_tombstone() && self.recorded_at <= t && self.valid_from <= t && t < self.valid_to
}
}
impl Slot for FactRecord {
const SIZE: usize = 48;
const KEY_LEN: usize = 4;
fn write(&self, out: &mut [u8]) {
key::write_u32(out, self.id.0);
key::write_u32(&mut out[4..], self.entity.0);
out[8..10].copy_from_slice(&self.flags.to_be_bytes());
out[10..12].copy_from_slice(&self.kind.to_be_bytes());
key::write_u32(&mut out[12..], self.text.0);
key::write_u32(&mut out[16..], self.vector);
key::write_u32(&mut out[20..], self.revises.0);
key::write_u64(&mut out[24..], self.recorded_at);
key::write_u64(&mut out[32..], self.valid_from);
key::write_u64(&mut out[40..], self.valid_to);
}
fn read(bytes: &[u8]) -> Self {
Self {
id: FactId(key::read_u32(bytes)),
entity: EntityId(key::read_u32(&bytes[4..])),
flags: u16::from_be_bytes(bytes[8..10].try_into().unwrap()),
kind: u16::from_be_bytes(bytes[10..12].try_into().unwrap()),
text: BlobId(key::read_u32(&bytes[12..])),
vector: key::read_u32(&bytes[16..]),
revises: FactId(key::read_u32(&bytes[20..])),
recorded_at: key::read_u64(&bytes[24..]),
valid_from: key::read_u64(&bytes[32..]),
valid_to: key::read_u64(&bytes[40..]),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FactAux {
pub id: FactId,
pub tags: ListHandle,
pub meta: BlobId,
}
impl Slot for FactAux {
const SIZE: usize = 20;
const KEY_LEN: usize = 4;
fn write(&self, out: &mut [u8]) {
key::write_u32(out, self.id.0);
out[4..16].copy_from_slice(&self.tags.to_bytes());
key::write_u32(&mut out[16..], self.meta.0);
}
fn read(bytes: &[u8]) -> Self {
Self {
id: FactId(key::read_u32(bytes)),
tags: ListHandle::from_bytes(bytes[4..16].try_into().unwrap()),
meta: BlobId(key::read_u32(&bytes[16..])),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EntityRecord {
pub id: EntityId,
pub name: BlobId,
pub name_term: TermId,
pub created_at: u64,
pub flags: u32,
}
impl Slot for EntityRecord {
const SIZE: usize = 24;
const KEY_LEN: usize = 4;
fn write(&self, out: &mut [u8]) {
key::write_u32(out, self.id.0);
key::write_u32(&mut out[4..], self.name.0);
key::write_u32(&mut out[8..], self.name_term.0);
key::write_u64(&mut out[12..], self.created_at);
key::write_u32(&mut out[20..], self.flags);
}
fn read(bytes: &[u8]) -> Self {
Self {
id: EntityId(key::read_u32(bytes)),
name: BlobId(key::read_u32(&bytes[4..])),
name_term: TermId(key::read_u32(&bytes[8..])),
created_at: key::read_u64(&bytes[12..]),
flags: key::read_u32(&bytes[20..]),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EntityByName {
pub name_term: TermId,
pub id: EntityId,
}
impl Slot for EntityByName {
const SIZE: usize = 8;
const KEY_LEN: usize = 8;
fn write(&self, out: &mut [u8]) {
key::write_u32(out, self.name_term.0);
key::write_u32(&mut out[4..], self.id.0);
}
fn read(bytes: &[u8]) -> Self {
Self {
name_term: TermId(key::read_u32(bytes)),
id: EntityId(key::read_u32(&bytes[4..])),
}
}
}
mod edge_at {
use core::mem::size_of;
pub(super) const A: usize = 0;
pub(super) const REL: usize = A + size_of::<u32>();
pub(super) const B: usize = REL + size_of::<u32>();
pub(super) const KEY_LEN: usize = B + size_of::<u32>();
pub(super) const FACT: usize = KEY_LEN;
pub(super) const EDGE: usize = FACT + size_of::<u32>();
pub(super) const VALID_FROM: usize = EDGE + size_of::<u32>();
pub(super) const SIZE: usize = VALID_FROM + size_of::<u64>();
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EdgeSlot {
pub a: EntityId,
pub rel: TermId,
pub b: EntityId,
pub fact: FactId,
pub edge: EdgeId,
pub valid_from: u64,
}
impl Slot for EdgeSlot {
const SIZE: usize = edge_at::SIZE;
const KEY_LEN: usize = edge_at::KEY_LEN;
fn write(&self, out: &mut [u8]) {
key::write_u32(&mut out[edge_at::A..], self.a.0);
key::write_u32(&mut out[edge_at::REL..], self.rel.0);
key::write_u32(&mut out[edge_at::B..], self.b.0);
key::write_u32(&mut out[edge_at::FACT..], self.fact.0);
key::write_u32(&mut out[edge_at::EDGE..], self.edge.0);
key::write_u64(&mut out[edge_at::VALID_FROM..], self.valid_from);
}
fn read(bytes: &[u8]) -> Self {
Self {
a: EntityId(key::read_u32(&bytes[edge_at::A..])),
rel: TermId(key::read_u32(&bytes[edge_at::REL..])),
b: EntityId(key::read_u32(&bytes[edge_at::B..])),
fact: FactId(key::read_u32(&bytes[edge_at::FACT..])),
edge: EdgeId(key::read_u32(&bytes[edge_at::EDGE..])),
valid_from: key::read_u64(&bytes[edge_at::VALID_FROM..]),
}
}
}
pub(crate) fn edge_key(a: EntityId, rel: TermId, b: EntityId) -> [u8; edge_at::KEY_LEN] {
let mut out = [0u8; edge_at::KEY_LEN];
key::write_u32(&mut out[edge_at::A..], a.0);
key::write_u32(&mut out[edge_at::REL..], rel.0);
key::write_u32(&mut out[edge_at::B..], b.0);
out
}
mod edge_hist_at {
use core::mem::size_of;
pub(super) const A: usize = 0;
pub(super) const VALID_FROM: usize = A + size_of::<u32>();
pub(super) const EDGE: usize = VALID_FROM + size_of::<u64>();
pub(super) const KEY_LEN: usize = EDGE + size_of::<u32>();
pub(super) const REL: usize = KEY_LEN;
pub(super) const B: usize = REL + size_of::<u32>();
pub(super) const FACT: usize = B + size_of::<u32>();
pub(super) const FLAGS: usize = FACT + size_of::<u32>();
pub(super) const KIND: usize = FLAGS + size_of::<u16>();
pub(super) const RECORDED_AT: usize = KIND + size_of::<u16>();
pub(super) const VALID_TO: usize = RECORDED_AT + size_of::<u64>();
pub(super) const SIZE: usize = VALID_TO + size_of::<u64>();
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EdgeHistorySlot {
pub a: EntityId,
pub rel: TermId,
pub b: EntityId,
pub edge: EdgeId,
pub fact: FactId,
pub flags: u16,
pub kind: u16,
pub recorded_at: u64,
pub valid_from: u64,
pub valid_to: u64,
}
impl EdgeHistorySlot {
pub fn active_at(&self, t: u64) -> bool {
self.valid_from <= t && t < self.valid_to
}
pub fn is_open(&self) -> bool {
self.valid_to == VALID_TO_OPEN
}
}
pub mod edge_flags {
pub const CLOSED: u16 = 1;
}
impl Slot for EdgeHistorySlot {
const SIZE: usize = edge_hist_at::SIZE;
const KEY_LEN: usize = edge_hist_at::KEY_LEN;
fn write(&self, out: &mut [u8]) {
key::write_u32(&mut out[edge_hist_at::A..], self.a.0);
key::write_u64(&mut out[edge_hist_at::VALID_FROM..], self.valid_from);
key::write_u32(&mut out[edge_hist_at::EDGE..], self.edge.0);
key::write_u32(&mut out[edge_hist_at::REL..], self.rel.0);
key::write_u32(&mut out[edge_hist_at::B..], self.b.0);
key::write_u32(&mut out[edge_hist_at::FACT..], self.fact.0);
let flags = edge_hist_at::FLAGS;
out[flags..flags + size_of::<u16>()].copy_from_slice(&self.flags.to_be_bytes());
let kind = edge_hist_at::KIND;
out[kind..kind + size_of::<u16>()].copy_from_slice(&self.kind.to_be_bytes());
key::write_u64(&mut out[edge_hist_at::RECORDED_AT..], self.recorded_at);
key::write_u64(&mut out[edge_hist_at::VALID_TO..], self.valid_to);
}
fn read(bytes: &[u8]) -> Self {
let flags = edge_hist_at::FLAGS;
let kind = edge_hist_at::KIND;
Self {
a: EntityId(key::read_u32(&bytes[edge_hist_at::A..])),
rel: TermId(key::read_u32(&bytes[edge_hist_at::REL..])),
b: EntityId(key::read_u32(&bytes[edge_hist_at::B..])),
edge: EdgeId(key::read_u32(&bytes[edge_hist_at::EDGE..])),
fact: FactId(key::read_u32(&bytes[edge_hist_at::FACT..])),
flags: u16::from_be_bytes(bytes[flags..flags + size_of::<u16>()].try_into().unwrap()),
kind: u16::from_be_bytes(bytes[kind..kind + size_of::<u16>()].try_into().unwrap()),
recorded_at: key::read_u64(&bytes[edge_hist_at::RECORDED_AT..]),
valid_from: key::read_u64(&bytes[edge_hist_at::VALID_FROM..]),
valid_to: key::read_u64(&bytes[edge_hist_at::VALID_TO..]),
}
}
}
pub(crate) fn edge_floor(a: EntityId) -> [u8; edge_at::KEY_LEN] {
edge_key(a, TermId(0), EntityId(0))
}
pub(crate) fn edge_end(a: EntityId) -> [u8; edge_at::KEY_LEN] {
edge_key(EntityId(a.0.saturating_add(1)), TermId(0), EntityId(0))
}
pub(crate) fn edge_history_key(
a: EntityId,
valid_from: u64,
edge: EdgeId,
) -> [u8; edge_hist_at::KEY_LEN] {
let mut out = [0u8; edge_hist_at::KEY_LEN];
key::write_u32(&mut out[edge_hist_at::A..], a.0);
key::write_u64(&mut out[edge_hist_at::VALID_FROM..], valid_from);
key::write_u32(&mut out[edge_hist_at::EDGE..], edge.0);
out
}
pub(crate) fn edge_history_floor(a: EntityId) -> [u8; edge_hist_at::KEY_LEN] {
edge_history_key(a, 0, EdgeId(0))
}
pub(crate) fn edge_history_ceiling(a: EntityId, as_of: u64) -> [u8; edge_hist_at::KEY_LEN] {
edge_history_key(a, as_of.saturating_add(1), EdgeId(0))
}
pub(crate) fn close_edge_history_payload(payload: &mut [u8], valid_to: u64) {
const KEY: usize = edge_hist_at::KEY_LEN;
const FLAGS: usize = edge_hist_at::FLAGS - KEY;
const VALID_TO: usize = edge_hist_at::VALID_TO - KEY;
let flags = u16::from_be_bytes(payload[FLAGS..FLAGS + size_of::<u16>()].try_into().unwrap())
| edge_flags::CLOSED;
payload[FLAGS..FLAGS + size_of::<u16>()].copy_from_slice(&flags.to_be_bytes());
key::write_u64(&mut payload[VALID_TO..], valid_to);
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TemporalSlot {
pub recorded_at: u64,
pub fact: FactId,
}
impl Slot for TemporalSlot {
const SIZE: usize = 12;
const KEY_LEN: usize = 12;
fn write(&self, out: &mut [u8]) {
key::write_pair(out, self.recorded_at, self.fact.0);
}
fn read(bytes: &[u8]) -> Self {
let (recorded_at, fact) = key::read_pair(bytes);
Self {
recorded_at,
fact: FactId(fact),
}
}
}
const _: () = {
assert!(FactRecord::SIZE == 48 && FactRecord::KEY_LEN == 4);
assert!(FactAux::SIZE == 20 && FactAux::KEY_LEN == 4);
assert!(EntityRecord::SIZE == 24 && EntityRecord::KEY_LEN == 4);
assert!(EntityByName::SIZE == 8 && EntityByName::KEY_LEN == 8);
assert!(EdgeSlot::SIZE == 28 && EdgeSlot::KEY_LEN == 12);
assert!(EdgeHistorySlot::SIZE == 48 && EdgeHistorySlot::KEY_LEN == 16);
assert!(TemporalSlot::SIZE == 12 && TemporalSlot::KEY_LEN == 12);
assert!(NONE_U32 == u32::MAX);
};