1use core::mem::size_of;
16
17use plugmem_arena::{BlobId, ListHandle, Slot, TermId, key};
18
19use crate::id::{EdgeId, EntityId, FactId, NONE_U32};
20
21pub const VALID_TO_OPEN: u64 = u64::MAX;
23
24pub mod fact_flags {
26 pub const TOMBSTONE: u16 = 1;
28 pub const CLOSED: u16 = 1 << 1;
31 pub const HAS_VECTOR: u16 = 1 << 2;
34}
35
36#[derive(Clone, Copy, Debug, PartialEq, Eq)]
51#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
52pub struct FactRecord {
53 pub id: FactId,
55 pub entity: EntityId,
57 pub flags: u16,
59 pub kind: u16,
61 pub text: BlobId,
63 pub vector: u32,
66 pub revises: FactId,
71 pub recorded_at: u64,
73 pub valid_from: u64,
75 pub valid_to: u64,
77}
78
79impl FactRecord {
80 pub fn is_tombstone(&self) -> bool {
82 self.flags & fact_flags::TOMBSTONE != 0
83 }
84
85 pub fn is_closed(&self) -> bool {
87 self.flags & fact_flags::CLOSED != 0
88 }
89
90 pub fn has_vector(&self) -> bool {
92 self.flags & fact_flags::HAS_VECTOR != 0
93 }
94
95 pub fn is_live_at(&self, t: u64) -> bool {
98 !self.is_tombstone() && self.recorded_at <= t && self.valid_from <= t && t < self.valid_to
99 }
100}
101
102impl Slot for FactRecord {
103 const SIZE: usize = 48;
104 const KEY_LEN: usize = 4;
105
106 fn write(&self, out: &mut [u8]) {
107 key::write_u32(out, self.id.0);
108 key::write_u32(&mut out[4..], self.entity.0);
109 out[8..10].copy_from_slice(&self.flags.to_be_bytes());
110 out[10..12].copy_from_slice(&self.kind.to_be_bytes());
111 key::write_u32(&mut out[12..], self.text.0);
112 key::write_u32(&mut out[16..], self.vector);
113 key::write_u32(&mut out[20..], self.revises.0);
114 key::write_u64(&mut out[24..], self.recorded_at);
115 key::write_u64(&mut out[32..], self.valid_from);
116 key::write_u64(&mut out[40..], self.valid_to);
117 }
118
119 fn read(bytes: &[u8]) -> Self {
120 Self {
121 id: FactId(key::read_u32(bytes)),
122 entity: EntityId(key::read_u32(&bytes[4..])),
123 flags: u16::from_be_bytes(bytes[8..10].try_into().unwrap()),
124 kind: u16::from_be_bytes(bytes[10..12].try_into().unwrap()),
125 text: BlobId(key::read_u32(&bytes[12..])),
126 vector: key::read_u32(&bytes[16..]),
127 revises: FactId(key::read_u32(&bytes[20..])),
128 recorded_at: key::read_u64(&bytes[24..]),
129 valid_from: key::read_u64(&bytes[32..]),
130 valid_to: key::read_u64(&bytes[40..]),
131 }
132 }
133}
134
135#[derive(Clone, Copy, Debug, PartialEq, Eq)]
143#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
144pub struct FactAux {
145 pub id: FactId,
147 pub tags: ListHandle,
149 pub meta: BlobId,
153}
154
155impl Slot for FactAux {
156 const SIZE: usize = 20;
157 const KEY_LEN: usize = 4;
158
159 fn write(&self, out: &mut [u8]) {
160 key::write_u32(out, self.id.0);
161 out[4..16].copy_from_slice(&self.tags.to_bytes());
162 key::write_u32(&mut out[16..], self.meta.0);
163 }
164
165 fn read(bytes: &[u8]) -> Self {
166 Self {
167 id: FactId(key::read_u32(bytes)),
168 tags: ListHandle::from_bytes(bytes[4..16].try_into().unwrap()),
169 meta: BlobId(key::read_u32(&bytes[16..])),
170 }
171 }
172}
173
174#[derive(Clone, Copy, Debug, PartialEq, Eq)]
184#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
185pub struct EntityRecord {
186 pub id: EntityId,
188 pub name: BlobId,
190 pub name_term: TermId,
192 pub created_at: u64,
194 pub flags: u32,
196}
197
198impl Slot for EntityRecord {
199 const SIZE: usize = 24;
200 const KEY_LEN: usize = 4;
201
202 fn write(&self, out: &mut [u8]) {
203 key::write_u32(out, self.id.0);
204 key::write_u32(&mut out[4..], self.name.0);
205 key::write_u32(&mut out[8..], self.name_term.0);
206 key::write_u64(&mut out[12..], self.created_at);
207 key::write_u32(&mut out[20..], self.flags);
208 }
209
210 fn read(bytes: &[u8]) -> Self {
211 Self {
212 id: EntityId(key::read_u32(bytes)),
213 name: BlobId(key::read_u32(&bytes[4..])),
214 name_term: TermId(key::read_u32(&bytes[8..])),
215 created_at: key::read_u64(&bytes[12..]),
216 flags: key::read_u32(&bytes[20..]),
217 }
218 }
219}
220
221#[derive(Clone, Copy, Debug, PartialEq, Eq)]
228#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
229pub struct EntityByName {
230 pub name_term: TermId,
232 pub id: EntityId,
234}
235
236impl Slot for EntityByName {
237 const SIZE: usize = 8;
238 const KEY_LEN: usize = 8;
239
240 fn write(&self, out: &mut [u8]) {
241 key::write_u32(out, self.name_term.0);
242 key::write_u32(&mut out[4..], self.id.0);
243 }
244
245 fn read(bytes: &[u8]) -> Self {
246 Self {
247 name_term: TermId(key::read_u32(bytes)),
248 id: EntityId(key::read_u32(&bytes[4..])),
249 }
250 }
251}
252
253mod edge_at {
257 use core::mem::size_of;
258
259 pub(super) const A: usize = 0;
260 pub(super) const REL: usize = A + size_of::<u32>();
261 pub(super) const B: usize = REL + size_of::<u32>();
262 pub(super) const KEY_LEN: usize = B + size_of::<u32>();
264 pub(super) const FACT: usize = KEY_LEN;
265 pub(super) const EDGE: usize = FACT + size_of::<u32>();
266 pub(super) const VALID_FROM: usize = EDGE + size_of::<u32>();
267 pub(super) const SIZE: usize = VALID_FROM + size_of::<u64>();
268}
269
270#[derive(Clone, Copy, Debug, PartialEq, Eq)]
284#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
285pub struct EdgeSlot {
286 pub a: EntityId,
288 pub rel: TermId,
290 pub b: EntityId,
292 pub fact: FactId,
296 pub edge: EdgeId,
298 pub valid_from: u64,
301}
302
303impl Slot for EdgeSlot {
304 const SIZE: usize = edge_at::SIZE;
305 const KEY_LEN: usize = edge_at::KEY_LEN;
306
307 fn write(&self, out: &mut [u8]) {
308 key::write_u32(&mut out[edge_at::A..], self.a.0);
309 key::write_u32(&mut out[edge_at::REL..], self.rel.0);
310 key::write_u32(&mut out[edge_at::B..], self.b.0);
311 key::write_u32(&mut out[edge_at::FACT..], self.fact.0);
312 key::write_u32(&mut out[edge_at::EDGE..], self.edge.0);
313 key::write_u64(&mut out[edge_at::VALID_FROM..], self.valid_from);
314 }
315
316 fn read(bytes: &[u8]) -> Self {
317 Self {
318 a: EntityId(key::read_u32(&bytes[edge_at::A..])),
319 rel: TermId(key::read_u32(&bytes[edge_at::REL..])),
320 b: EntityId(key::read_u32(&bytes[edge_at::B..])),
321 fact: FactId(key::read_u32(&bytes[edge_at::FACT..])),
322 edge: EdgeId(key::read_u32(&bytes[edge_at::EDGE..])),
323 valid_from: key::read_u64(&bytes[edge_at::VALID_FROM..]),
324 }
325 }
326}
327
328pub(crate) fn edge_key(a: EntityId, rel: TermId, b: EntityId) -> [u8; edge_at::KEY_LEN] {
330 let mut out = [0u8; edge_at::KEY_LEN];
331 key::write_u32(&mut out[edge_at::A..], a.0);
332 key::write_u32(&mut out[edge_at::REL..], rel.0);
333 key::write_u32(&mut out[edge_at::B..], b.0);
334 out
335}
336
337mod edge_hist_at {
340 use core::mem::size_of;
341
342 pub(super) const A: usize = 0;
343 pub(super) const VALID_FROM: usize = A + size_of::<u32>();
344 pub(super) const EDGE: usize = VALID_FROM + size_of::<u64>();
345 pub(super) const KEY_LEN: usize = EDGE + size_of::<u32>();
348 pub(super) const REL: usize = KEY_LEN;
349 pub(super) const B: usize = REL + size_of::<u32>();
350 pub(super) const FACT: usize = B + size_of::<u32>();
351 pub(super) const FLAGS: usize = FACT + size_of::<u32>();
352 pub(super) const KIND: usize = FLAGS + size_of::<u16>();
353 pub(super) const RECORDED_AT: usize = KIND + size_of::<u16>();
354 pub(super) const VALID_TO: usize = RECORDED_AT + size_of::<u64>();
355 pub(super) const SIZE: usize = VALID_TO + size_of::<u64>();
356}
357
358#[derive(Clone, Copy, Debug, PartialEq, Eq)]
373#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
374pub struct EdgeHistorySlot {
375 pub a: EntityId,
377 pub rel: TermId,
379 pub b: EntityId,
381 pub edge: EdgeId,
383 pub fact: FactId,
385 pub flags: u16,
387 pub kind: u16,
389 pub recorded_at: u64,
391 pub valid_from: u64,
393 pub valid_to: u64,
396}
397
398impl EdgeHistorySlot {
399 pub fn active_at(&self, t: u64) -> bool {
401 self.valid_from <= t && t < self.valid_to
402 }
403
404 pub fn is_open(&self) -> bool {
406 self.valid_to == VALID_TO_OPEN
407 }
408}
409
410pub mod edge_flags {
412 pub const CLOSED: u16 = 1;
414}
415
416impl Slot for EdgeHistorySlot {
417 const SIZE: usize = edge_hist_at::SIZE;
418 const KEY_LEN: usize = edge_hist_at::KEY_LEN;
419
420 fn write(&self, out: &mut [u8]) {
421 key::write_u32(&mut out[edge_hist_at::A..], self.a.0);
422 key::write_u64(&mut out[edge_hist_at::VALID_FROM..], self.valid_from);
423 key::write_u32(&mut out[edge_hist_at::EDGE..], self.edge.0);
424 key::write_u32(&mut out[edge_hist_at::REL..], self.rel.0);
425 key::write_u32(&mut out[edge_hist_at::B..], self.b.0);
426 key::write_u32(&mut out[edge_hist_at::FACT..], self.fact.0);
427 let flags = edge_hist_at::FLAGS;
428 out[flags..flags + size_of::<u16>()].copy_from_slice(&self.flags.to_be_bytes());
429 let kind = edge_hist_at::KIND;
430 out[kind..kind + size_of::<u16>()].copy_from_slice(&self.kind.to_be_bytes());
431 key::write_u64(&mut out[edge_hist_at::RECORDED_AT..], self.recorded_at);
432 key::write_u64(&mut out[edge_hist_at::VALID_TO..], self.valid_to);
433 }
434
435 fn read(bytes: &[u8]) -> Self {
436 let flags = edge_hist_at::FLAGS;
437 let kind = edge_hist_at::KIND;
438 Self {
439 a: EntityId(key::read_u32(&bytes[edge_hist_at::A..])),
440 rel: TermId(key::read_u32(&bytes[edge_hist_at::REL..])),
441 b: EntityId(key::read_u32(&bytes[edge_hist_at::B..])),
442 edge: EdgeId(key::read_u32(&bytes[edge_hist_at::EDGE..])),
443 fact: FactId(key::read_u32(&bytes[edge_hist_at::FACT..])),
444 flags: u16::from_be_bytes(bytes[flags..flags + size_of::<u16>()].try_into().unwrap()),
445 kind: u16::from_be_bytes(bytes[kind..kind + size_of::<u16>()].try_into().unwrap()),
446 recorded_at: key::read_u64(&bytes[edge_hist_at::RECORDED_AT..]),
447 valid_from: key::read_u64(&bytes[edge_hist_at::VALID_FROM..]),
448 valid_to: key::read_u64(&bytes[edge_hist_at::VALID_TO..]),
449 }
450 }
451}
452
453pub(crate) fn edge_floor(a: EntityId) -> [u8; edge_at::KEY_LEN] {
456 edge_key(a, TermId(0), EntityId(0))
457}
458
459pub(crate) fn edge_end(a: EntityId) -> [u8; edge_at::KEY_LEN] {
463 edge_key(EntityId(a.0.saturating_add(1)), TermId(0), EntityId(0))
464}
465
466pub(crate) fn edge_history_key(
468 a: EntityId,
469 valid_from: u64,
470 edge: EdgeId,
471) -> [u8; edge_hist_at::KEY_LEN] {
472 let mut out = [0u8; edge_hist_at::KEY_LEN];
473 key::write_u32(&mut out[edge_hist_at::A..], a.0);
474 key::write_u64(&mut out[edge_hist_at::VALID_FROM..], valid_from);
475 key::write_u32(&mut out[edge_hist_at::EDGE..], edge.0);
476 out
477}
478
479pub(crate) fn edge_history_floor(a: EntityId) -> [u8; edge_hist_at::KEY_LEN] {
482 edge_history_key(a, 0, EdgeId(0))
483}
484
485pub(crate) fn edge_history_ceiling(a: EntityId, as_of: u64) -> [u8; edge_hist_at::KEY_LEN] {
492 edge_history_key(a, as_of.saturating_add(1), EdgeId(0))
493}
494
495pub(crate) fn close_edge_history_payload(payload: &mut [u8], valid_to: u64) {
501 const KEY: usize = edge_hist_at::KEY_LEN;
502 const FLAGS: usize = edge_hist_at::FLAGS - KEY;
503 const VALID_TO: usize = edge_hist_at::VALID_TO - KEY;
504 let flags = u16::from_be_bytes(payload[FLAGS..FLAGS + size_of::<u16>()].try_into().unwrap())
505 | edge_flags::CLOSED;
506 payload[FLAGS..FLAGS + size_of::<u16>()].copy_from_slice(&flags.to_be_bytes());
507 key::write_u64(&mut payload[VALID_TO..], valid_to);
508}
509
510#[derive(Clone, Copy, Debug, PartialEq, Eq)]
516#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
517pub struct TemporalSlot {
518 pub recorded_at: u64,
520 pub fact: FactId,
522}
523
524impl Slot for TemporalSlot {
525 const SIZE: usize = 12;
526 const KEY_LEN: usize = 12;
527
528 fn write(&self, out: &mut [u8]) {
529 key::write_pair(out, self.recorded_at, self.fact.0);
530 }
531
532 fn read(bytes: &[u8]) -> Self {
533 let (recorded_at, fact) = key::read_pair(bytes);
534 Self {
535 recorded_at,
536 fact: FactId(fact),
537 }
538 }
539}
540
541const _: () = {
544 assert!(FactRecord::SIZE == 48 && FactRecord::KEY_LEN == 4);
545 assert!(FactAux::SIZE == 20 && FactAux::KEY_LEN == 4);
546 assert!(EntityRecord::SIZE == 24 && EntityRecord::KEY_LEN == 4);
547 assert!(EntityByName::SIZE == 8 && EntityByName::KEY_LEN == 8);
548 assert!(EdgeSlot::SIZE == 28 && EdgeSlot::KEY_LEN == 12);
549 assert!(EdgeHistorySlot::SIZE == 48 && EdgeHistorySlot::KEY_LEN == 16);
550 assert!(TemporalSlot::SIZE == 12 && TemporalSlot::KEY_LEN == 12);
551 assert!(NONE_U32 == u32::MAX);
553};