use crate::core::{DataHeader, Error, ErrorKind, MessageId, Result};
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct MessageKey {
pub message_id: MessageId,
}
impl MessageKey {
#[must_use]
pub const fn new(message_id: MessageId) -> Self {
Self { message_id }
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct FragmentRange {
pub offset: u32,
pub len: u32,
}
impl FragmentRange {
#[must_use]
pub const fn new(offset: u32, len: u32) -> Self {
Self { offset, len }
}
#[must_use]
pub const fn end(self) -> u32 {
self.offset.saturating_add(self.len)
}
#[must_use]
pub const fn is_empty(self) -> bool {
self.len == 0
}
#[must_use]
pub const fn fits_in(self, message_len: u32) -> bool {
self.offset <= message_len && self.end() <= message_len
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct MessageFragment {
pub key: MessageKey,
pub message_len: u32,
pub range: FragmentRange,
}
impl MessageFragment {
#[must_use]
pub const fn new(key: MessageKey, message_len: u32, range: FragmentRange) -> Self {
Self {
key,
message_len,
range,
}
}
pub fn try_from_data_header(header: DataHeader, payload_len: usize) -> Result<Self> {
let len = u32::try_from(payload_len).map_err(|_| Error::new(ErrorKind::Reliability))?;
let message_len =
u32::try_from(header.message_len).map_err(|_| Error::new(ErrorKind::Reliability))?;
let fragment_offset = u32::try_from(header.fragment_offset)
.map_err(|_| Error::new(ErrorKind::Reliability))?;
let range = FragmentRange::new(fragment_offset, len);
if !range.fits_in(message_len) {
return Err(Error::new(ErrorKind::Reliability));
}
Ok(Self::new(
MessageKey::new(header.message_id),
message_len,
range,
))
}
}
#[cfg(test)]
mod tests {
use crate::core::{DataHeader, Flags, MessageId, PacketIndex};
use super::{FragmentRange, MessageFragment, MessageKey};
#[test]
fn fragment_range_must_fit_message_len() {
assert!(FragmentRange::new(2, 3).fits_in(5));
assert!(!FragmentRange::new(3, 3).fits_in(5));
}
#[test]
fn packet_header_maps_to_message_fragment() {
let header = DataHeader::new(
Flags::ACK_ELICITING,
MessageId::new(9),
PacketIndex::new(3),
8,
2,
);
let fragment = MessageFragment::try_from_data_header(header, 3).unwrap();
assert_eq!(fragment.key, MessageKey::new(MessageId::new(9)));
assert_eq!(fragment.range, FragmentRange::new(2, 3));
}
}