use crate::payload::Payload;
use crate::vector::Vector;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct RecordId(u64);
impl RecordId {
#[inline]
#[must_use]
pub const fn new(id: u64) -> Self {
Self(id)
}
#[inline]
#[must_use]
pub const fn get(self) -> u64 {
self.0
}
}
impl From<u64> for RecordId {
#[inline]
fn from(value: u64) -> Self {
Self(value)
}
}
impl From<RecordId> for u64 {
#[inline]
fn from(value: RecordId) -> Self {
value.0
}
}
impl core::fmt::Display for RecordId {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Record {
id: RecordId,
vector: Vector,
payload: Option<Payload>,
}
impl Record {
#[inline]
#[must_use]
pub fn new(id: impl Into<RecordId>, vector: Vector) -> Self {
Self {
id: id.into(),
vector,
payload: None,
}
}
#[inline]
#[must_use]
pub fn with_payload(id: impl Into<RecordId>, vector: Vector, payload: Payload) -> Self {
Self {
id: id.into(),
vector,
payload: Some(payload),
}
}
#[inline]
#[must_use]
pub const fn id(&self) -> RecordId {
self.id
}
#[inline]
#[must_use]
pub const fn vector(&self) -> &Vector {
&self.vector
}
#[inline]
#[must_use]
pub const fn payload(&self) -> Option<&Payload> {
self.payload.as_ref()
}
#[inline]
#[must_use]
pub fn into_parts(self) -> (RecordId, Vector, Option<Payload>) {
(self.id, self.vector, self.payload)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn record_id_round_trips_through_u64() {
let id = RecordId::new(42);
let raw: u64 = id.into();
assert_eq!(raw, 42);
let back: RecordId = raw.into();
assert_eq!(back, id);
}
#[test]
fn record_id_orders_lexicographically_on_u64() {
assert!(RecordId::new(1) < RecordId::new(2));
assert!(RecordId::new(u64::MAX) > RecordId::new(0));
}
#[test]
fn record_id_display_is_raw_u64() {
let s = format!("{}", RecordId::new(123));
assert_eq!(s, "123");
}
#[test]
fn record_new_has_no_payload() {
let r = Record::new(1_u64, Vector::new(vec![0.0, 1.0]).unwrap());
assert!(r.payload().is_none());
assert_eq!(r.id().get(), 1);
assert_eq!(r.vector().dim(), 2);
}
#[test]
fn record_with_payload_carries_metadata() {
let mut p = Payload::new();
p.insert("k", "v");
let r = Record::with_payload(RecordId::new(1), Vector::new(vec![0.0, 1.0]).unwrap(), p);
let payload = r.payload().expect("payload set");
assert!(payload.contains_key("k"));
}
#[test]
fn into_parts_decomposes_without_clone() {
let r = Record::new(RecordId::new(7), Vector::new(vec![1.0, 2.0, 3.0]).unwrap());
let (id, vec, payload) = r.into_parts();
assert_eq!(id.get(), 7);
assert_eq!(vec.dim(), 3);
assert!(payload.is_none());
}
}