2026-06-04 15:43:38 +02:00

48 lines
1.5 KiB
Rust

//! Opaque row identifiers.
//!
//! Each backend assigns its own bytes for a [`RowId`]; the trait treats them
//! opaquely. The in-memory backend and the KV backends use a big-endian `u64`
//! row counter; the geomerge backend encodes its `(CommitHash, counter)`
//! pair. Callers do not interpret the bytes: they hand a `RowId` back to the
//! same backend to reference an existing row.
//!
//! Storage is inline up to 36 bytes (the geomerge `(CommitHash, counter)`
//! width), which covers every encoding the workspace produces today. Wider
//! row-id encodings spill to the heap automatically via [`SmallVec`].
use smallvec::SmallVec;
const INLINE_BYTES: usize = 36;
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct RowId(SmallVec<[u8; INLINE_BYTES]>);
impl RowId {
/// Build a row id by copying the given bytes into inline storage when they
/// fit (≤ 36 bytes) or onto the heap when they don't.
pub fn new(bytes: impl AsRef<[u8]>) -> Self {
Self(SmallVec::from_slice(bytes.as_ref()))
}
/// View the underlying bytes.
#[must_use]
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
}
impl std::fmt::Display for RowId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for byte in &self.0 {
write!(f, "{byte:02x}")?;
}
Ok(())
}
}
impl From<u64> for RowId {
fn from(value: u64) -> Self {
Self(SmallVec::from_slice(&value.to_be_bytes()))
}
}