use bytemuck::{Pod, Zeroable};
use std::mem::{align_of, size_of};
pub fn cast_slice<T: Pod>(v: &[T]) -> &[u8] {
bytemuck::cast_slice(v)
}
pub fn cast_slice_mut<T: Pod>(v: &mut [T]) -> &mut [u8] {
bytemuck::cast_slice_mut(v)
}
pub fn cast_slice_from<T: Pod>(v: &[u8]) -> &[T] {
bytemuck::cast_slice(v)
}
pub fn cast_slice_from_mut<T: Pod>(v: &mut [u8]) -> &mut [T] {
bytemuck::cast_slice_mut(v)
}
pub fn expect_exact_len(actual: usize, expected: usize) -> Result<(), String> {
if actual == expected {
Ok(())
} else {
Err(format!("expected {expected} bytes, got {actual}"))
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Pod, Zeroable)]
pub struct WireCountU32(pub u32);
pub trait WirePoint: Copy {
fn to_wire(self) -> u64;
fn from_wire(w: u64) -> Self;
}
pub const WIRE_VERSION: u16 = 1;
#[repr(C)]
#[derive(Copy, Clone, Pod, Zeroable)]
pub struct WireHdr {
pub version_le: u16, pub kind_le: u16, pub reserved_le: u32, }
impl WireHdr {
pub fn new(kind: u16) -> Self {
Self {
version_le: WIRE_VERSION.to_le(),
kind_le: kind.to_le(),
reserved_le: 0,
}
}
pub fn kind(&self) -> u16 {
u16::from_le(self.kind_le)
}
pub fn version(&self) -> u16 {
u16::from_le(self.version_le)
}
}
#[repr(C)]
#[derive(Copy, Clone, Pod, Zeroable)]
pub struct WireCount {
pub n_le: u32, }
impl WireCount {
pub fn new(n: usize) -> Self {
Self {
n_le: (n as u32).to_le(),
}
}
pub fn get(&self) -> usize {
u32::from_le(self.n_le) as usize
}
}
#[repr(C)]
#[derive(Copy, Clone, Pod, Zeroable)]
pub struct WirePointRepr {
pub id_le: u64,
}
impl WirePointRepr {
pub fn of(id: u64) -> Self {
Self { id_le: id.to_le() }
}
pub fn get(&self) -> u64 {
u64::from_le(self.id_le)
}
}
#[repr(C)]
#[derive(Copy, Clone, Pod, Zeroable)]
pub struct WireAdj {
pub src_le: u64,
pub dst_le: u64,
}
impl WireAdj {
pub fn new(src: u64, dst: u64) -> Self {
Self {
src_le: src.to_le(),
dst_le: dst.to_le(),
}
}
pub fn src(&self) -> u64 {
u64::from_le(self.src_le)
}
pub fn dst(&self) -> u64 {
u64::from_le(self.dst_le)
}
}
#[repr(C)]
#[derive(Copy, Clone, Pod, Zeroable)]
pub struct WireArrow {
pub src_le: u64,
pub dst_le: u64,
}
impl WireArrow {
pub fn new(src: u64, dst: u64) -> Self {
Self {
src_le: src.to_le(),
dst_le: dst.to_le(),
}
}
pub fn src(&self) -> u64 {
u64::from_le(self.src_le)
}
pub fn dst(&self) -> u64 {
u64::from_le(self.dst_le)
}
}
#[repr(C)]
#[derive(Copy, Clone, Pod, Zeroable)]
pub struct WireArrowTriple {
pub src_le: u64,
pub dst_le: u64,
pub remote_point_le: u64,
pub rank_le: u32, pub _pad: u32, }
impl WireArrowTriple {
pub const SIZE: usize = 32; pub fn new(src: u64, dst: u64, remote: u64, rank: u32) -> Self {
Self {
src_le: src.to_le(),
dst_le: dst.to_le(),
remote_point_le: remote.to_le(),
rank_le: rank.to_le(),
_pad: 0,
}
}
pub fn decode(&self) -> (u64, u64, u64, u32) {
(
u64::from_le(self.src_le),
u64::from_le(self.dst_le),
u64::from_le(self.remote_point_le),
u32::from_le(self.rank_le),
)
}
}
pub const WIRE_PAYLOAD_MAX: usize = 16;
#[repr(C)]
#[derive(Copy, Clone, Pod, Zeroable)]
pub struct WireStackTriple {
pub base_le: u64,
pub cap_le: u64,
pub pay: [u8; WIRE_PAYLOAD_MAX],
}
impl WireStackTriple {
pub fn new(base: u64, cap: u64, pay: &[u8]) -> Self {
let mut buf = [0u8; WIRE_PAYLOAD_MAX];
let n = pay.len().min(WIRE_PAYLOAD_MAX);
buf[..n].copy_from_slice(&pay[..n]);
Self {
base_le: base.to_le(),
cap_le: cap.to_le(),
pay: buf,
}
}
pub fn base(&self) -> u64 {
u64::from_le(self.base_le)
}
pub fn cap(&self) -> u64 {
u64::from_le(self.cap_le)
}
}
const _: () = {
assert!(size_of::<WireHdr>() == 8);
assert!(size_of::<WireCount>() == 4);
assert!(size_of::<WirePointRepr>() == 8);
assert!(size_of::<WireAdj>() == 16);
assert!(size_of::<WireArrow>() == 16);
assert!(size_of::<WireArrowTriple>() == WireArrowTriple::SIZE);
assert!(align_of::<WireArrowTriple>() == 8);
};
impl WirePoint for crate::topology::point::PointId {
#[inline]
fn to_wire(self) -> u64 {
self.get()
}
#[inline]
fn from_wire(w: u64) -> Self {
crate::topology::point::PointId::new(w).expect("invalid PointId on wire")
}
}
#[cfg(test)]
mod tests {
use super::*;
use bytemuck::{cast_slice, cast_slice_mut};
#[test]
fn roundtrip_adj() {
let v = vec![WireAdj::new(1, 2), WireAdj::new(3, 4)];
let bytes: Vec<u8> = cast_slice(&v).to_vec();
let mut out = vec![WireAdj::zeroed(); v.len()];
cast_slice_mut(&mut out).copy_from_slice(&bytes);
assert_eq!(out[0].src(), 1);
assert_eq!(out[1].dst(), 4);
}
#[test]
fn roundtrip_wire_arrow() {
let v = vec![WireArrow::new(10, 20), WireArrow::new(30, 40)];
let bytes: Vec<u8> = cast_slice(&v).to_vec();
let mut out = vec![WireArrow::zeroed(); v.len()];
cast_slice_mut(&mut out).copy_from_slice(&bytes);
assert_eq!(out[0].src(), 10);
assert_eq!(out[1].dst(), 40);
}
#[test]
fn roundtrip_arrow() {
let t = WireArrowTriple::new(1, 2, 3, 4);
let bytes: Vec<u8> = cast_slice(&[t]).to_vec();
let mut out = vec![WireArrowTriple::zeroed(); 1];
cast_slice_mut(&mut out).copy_from_slice(&bytes);
assert_eq!(out[0].decode(), (1, 2, 3, 4));
assert_eq!(
WireArrowTriple::SIZE,
std::mem::size_of::<WireArrowTriple>()
);
}
#[test]
fn roundtrip_stack() {
let pay = [1u8, 2, 3, 4];
let t = WireStackTriple::new(10, 20, &pay);
let bytes: Vec<u8> = cast_slice(&[t]).to_vec();
let mut out = vec![WireStackTriple::zeroed(); 1];
cast_slice_mut(&mut out).copy_from_slice(&bytes);
assert_eq!(out[0].base(), 10);
assert_eq!(out[0].cap(), 20);
assert_eq!(&out[0].pay[..4], &pay);
}
#[test]
fn version_guard() {
let hdr = WireHdr::new(1);
assert_eq!(hdr.version(), WIRE_VERSION);
}
}