use serde::{Deserialize, Serialize};
use velo_ext::WorkerId;
const WORKER_SHIFT: u32 = 64;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct DataHandle(u128);
#[derive(Serialize, Deserialize)]
struct DataHandleWire {
hi: u64,
lo: u64,
}
impl DataHandle {
pub fn pack(worker_id: WorkerId, local_id: u64) -> Self {
let raw = ((worker_id.as_u64() as u128) << WORKER_SHIFT) | (local_id as u128);
Self(raw)
}
pub fn unpack(&self) -> (WorkerId, u64) {
let worker_id = WorkerId::from_u64((self.0 >> WORKER_SHIFT) as u64);
let local_id = self.0 as u64;
(worker_id, local_id)
}
pub fn worker_id(&self) -> WorkerId {
self.unpack().0
}
pub fn as_u128(&self) -> u128 {
self.0
}
pub fn from_u128(raw: u128) -> Self {
Self(raw)
}
}
impl Serialize for DataHandle {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
DataHandleWire {
hi: (self.0 >> 64) as u64,
lo: self.0 as u64,
}
.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for DataHandle {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let wire = DataHandleWire::deserialize(deserializer)?;
Ok(Self(((wire.hi as u128) << 64) | (wire.lo as u128)))
}
}
impl std::fmt::Display for DataHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let (worker_id, local_id) = self.unpack();
write!(
f,
"DataHandle(worker={}, local={})",
worker_id.as_u64(),
local_id
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pack_unpack_roundtrip() {
let worker_id = WorkerId::from_u64(0xDEAD_BEEF_1234_5678);
let local_id: u64 = 42;
let handle = DataHandle::pack(worker_id, local_id);
let (recovered_worker, recovered_local) = handle.unpack();
assert_eq!(recovered_worker, worker_id);
assert_eq!(recovered_local, local_id);
}
#[test]
fn test_serde_json_roundtrip() {
let worker_id = WorkerId::from_u64(0xDEAD_BEEF_1234_5678);
let local_id: u64 = 99;
let handle = DataHandle::pack(worker_id, local_id);
let encoded = serde_json::to_vec(&handle).expect("serialize");
let decoded: DataHandle = serde_json::from_slice(&encoded).expect("deserialize");
assert_eq!(handle, decoded);
let (w, l) = decoded.unpack();
assert_eq!(w, worker_id);
assert_eq!(l, local_id);
}
#[test]
fn test_worker_id_accessor() {
let wid = WorkerId::from_u64(123);
let handle = DataHandle::pack(wid, 456);
assert_eq!(handle.worker_id(), wid);
}
#[test]
fn test_from_u128() {
let wid = WorkerId::from_u64(7);
let handle = DataHandle::pack(wid, 42);
let raw = handle.as_u128();
let handle2 = DataHandle::from_u128(raw);
assert_eq!(handle, handle2);
}
#[test]
fn test_max_values_roundtrip() {
let worker_id = WorkerId::from_u64(u64::MAX);
let local_id = u64::MAX;
let handle = DataHandle::pack(worker_id, local_id);
let encoded = serde_json::to_vec(&handle).unwrap();
let decoded: DataHandle = serde_json::from_slice(&encoded).unwrap();
assert_eq!(handle, decoded);
let (w, l) = decoded.unpack();
assert_eq!(w.as_u64(), u64::MAX);
assert_eq!(l, u64::MAX);
}
}