use crate::{ENVELOPE_BYTES, Envelope, EnvelopeLimits, Opcode, Packet, data::CodecError};
pub const SAMPLE_BYTES: usize = 8;
pub fn encode_sample(
envelope: Envelope,
wall_millis: u64,
limits: EnvelopeLimits,
) -> Result<([u8; ENVELOPE_BYTES], [u8; SAMPLE_BYTES]), CodecError> {
check(envelope)?;
let header = envelope.encode_header(SAMPLE_BYTES, 0, limits)?;
Ok((header, wall_millis.to_be_bytes()))
}
pub fn decode_sample(packet: Packet<'_>, limits: EnvelopeLimits) -> Result<u64, CodecError> {
check(packet.envelope)?;
packet
.envelope
.validate_frames(packet.metadata.len(), packet.payload.len(), limits)?;
if !packet.payload.is_empty() {
return Err(CodecError::Length);
}
let wall: [u8; SAMPLE_BYTES] = packet.metadata.try_into().map_err(|_| CodecError::Length)?;
Ok(u64::from_be_bytes(wall))
}
fn check(envelope: Envelope) -> Result<(), CodecError> {
if envelope.opcode != Opcode::ClockSample
|| envelope.response
|| envelope.request_id.is_some()
|| envelope.session.is_none()
{
return Err(CodecError::Profile);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{LinkSessionId, NodeId, RequestId, decode_packet};
fn envelope() -> Envelope {
Envelope {
opcode: Opcode::ClockSample,
response: false,
request_id: None,
sender: NodeId::from_bytes([1; 16]),
session: Some(LinkSessionId::from_bytes([2; 16])),
}
}
#[test]
fn a_sample_round_trips_in_network_order() {
let limits = EnvelopeLimits::default();
let (header, metadata) = encode_sample(envelope(), 0x0102_0304_0506_0708, limits).unwrap();
assert_eq!(metadata, [1, 2, 3, 4, 5, 6, 7, 8]);
let packet = decode_packet(&[&header, &metadata, &[]], limits).unwrap();
assert_eq!(packet.envelope, envelope());
assert_eq!(
decode_sample(packet, limits).unwrap(),
0x0102_0304_0506_0708
);
}
#[test]
fn a_wrong_shape_is_refused() {
let limits = EnvelopeLimits::default();
for wrong in [
Envelope {
opcode: Opcode::Commit,
..envelope()
},
Envelope {
request_id: Some(RequestId::from_bytes([3; 16])),
..envelope()
},
Envelope {
response: true,
request_id: Some(RequestId::from_bytes([3; 16])),
..envelope()
},
] {
assert!(encode_sample(wrong, 1, limits).is_err());
}
let (header, metadata) = encode_sample(envelope(), 1, limits).unwrap();
let short = envelope().encode_header(4, 0, limits).unwrap();
let packet = decode_packet(&[&short, &metadata[..4], &[]], limits).unwrap();
assert!(decode_sample(packet, limits).is_err());
let padded = envelope().encode_header(8, 1, limits).unwrap();
let packet = decode_packet(&[&padded, &metadata, &[0]], limits).unwrap();
assert!(decode_sample(packet, limits).is_err());
assert!(decode_packet(&[&header, &metadata, &[]], limits).is_ok());
}
}