use bytes::{BufMut, BytesMut};
use serde::{Deserialize, Serialize};
use crate::WireError;
use crate::codec::{WireDecode, WireEncode, read_u64_le};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct TransitionPartitionHistoryRequest {
pub incarnation: u64,
pub metadata_op: u64,
}
impl TransitionPartitionHistoryRequest {
pub const ENCODED_SIZE: usize = 2 * size_of::<u64>();
}
impl WireEncode for TransitionPartitionHistoryRequest {
fn encoded_size(&self) -> usize {
Self::ENCODED_SIZE
}
fn encode(&self, buf: &mut BytesMut) {
buf.put_u64_le(self.incarnation);
buf.put_u64_le(self.metadata_op);
}
}
impl WireDecode for TransitionPartitionHistoryRequest {
fn decode_from(buf: &[u8]) -> Result<Self, WireError> {
let (request, consumed) = Self::decode(buf)?;
if consumed != buf.len() {
return Err(WireError::Validation(
"trailing history transition bytes".into(),
));
}
Ok(request)
}
fn decode(buf: &[u8]) -> Result<(Self, usize), WireError> {
let incarnation = read_u64_le(buf, 0)?;
let metadata_op = read_u64_le(buf, size_of::<u64>())?;
if metadata_op == 0 {
return Err(WireError::Validation(
"missing history transition identity".into(),
));
}
Ok((
Self {
incarnation,
metadata_op,
},
Self::ENCODED_SIZE,
))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn history_fence_round_trip_and_malformed_frames() {
let request = TransitionPartitionHistoryRequest {
incarnation: 17,
metadata_op: 52,
};
let encoded = request.to_bytes();
assert_eq!(
encoded.len(),
TransitionPartitionHistoryRequest::ENCODED_SIZE
);
assert_eq!(&encoded[0..8], &17_u64.to_le_bytes());
assert_eq!(&encoded[8..16], &52_u64.to_le_bytes());
assert_eq!(
TransitionPartitionHistoryRequest::decode_from(&encoded).unwrap(),
request
);
for length in 0..encoded.len() {
assert!(TransitionPartitionHistoryRequest::decode_from(&encoded[..length]).is_err());
}
let mut trailing = encoded.to_vec();
trailing.push(0);
assert!(TransitionPartitionHistoryRequest::decode_from(&trailing).is_err());
let mut no_metadata_op = encoded.to_vec();
no_metadata_op[8..16].fill(0);
assert!(TransitionPartitionHistoryRequest::decode_from(&no_metadata_op).is_err());
}
}