//! 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 for RowId { fn from(value: u64) -> Self { Self(SmallVec::from_slice(&value.to_be_bytes())) } }