use zerodds_cdr::{BufferReader, BufferWriter, DecodeError, EncodeError};
use crate::duration::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
#[repr(u32)]
pub enum LivelinessKind {
#[default]
Automatic = 0,
ManualByParticipant = 1,
ManualByTopic = 2,
}
impl LivelinessKind {
#[must_use]
pub const fn try_from_u32(v: u32) -> Option<Self> {
match v {
0 => Some(Self::Automatic),
1 => Some(Self::ManualByParticipant),
2 => Some(Self::ManualByTopic),
_ => None,
}
}
#[must_use]
pub const fn from_u32(v: u32) -> Self {
match v {
1 => Self::ManualByParticipant,
2 => Self::ManualByTopic,
_ => Self::Automatic,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LivelinessQosPolicy {
pub kind: LivelinessKind,
pub lease_duration: Duration,
}
impl Default for LivelinessQosPolicy {
fn default() -> Self {
Self {
kind: LivelinessKind::Automatic,
lease_duration: Duration::INFINITE,
}
}
}
impl LivelinessQosPolicy {
pub fn encode_into(self, w: &mut BufferWriter) -> Result<(), EncodeError> {
w.write_u32(self.kind as u32)?;
self.lease_duration.encode_into(w)
}
pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
let v = r.read_u32()?;
let kind = LivelinessKind::try_from_u32(v).ok_or(DecodeError::InvalidEnum {
kind: "LivelinessKind",
value: v,
})?;
let lease_duration = Duration::decode_from(r)?;
Ok(Self {
kind,
lease_duration,
})
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
use zerodds_cdr::Endianness;
#[test]
fn default_automatic_infinite() {
let d = LivelinessQosPolicy::default();
assert_eq!(d.kind, LivelinessKind::Automatic);
assert!(d.lease_duration.is_infinite());
}
#[test]
fn kind_ordering() {
use LivelinessKind::*;
assert!(Automatic < ManualByParticipant);
assert!(ManualByParticipant < ManualByTopic);
}
#[test]
fn try_from_u32_strict() {
assert_eq!(LivelinessKind::try_from_u32(3), None);
assert_eq!(
LivelinessKind::try_from_u32(2),
Some(LivelinessKind::ManualByTopic)
);
}
#[test]
fn roundtrip() {
for kind in [
LivelinessKind::Automatic,
LivelinessKind::ManualByParticipant,
LivelinessKind::ManualByTopic,
] {
let p = LivelinessQosPolicy {
kind,
lease_duration: Duration::from_millis(1234),
};
let mut w = BufferWriter::new(Endianness::Little);
p.encode_into(&mut w).unwrap();
let bytes = w.into_bytes();
assert_eq!(bytes.len(), 12);
let mut r = BufferReader::new(&bytes, Endianness::Little);
assert_eq!(LivelinessQosPolicy::decode_from(&mut r).unwrap(), p);
}
}
#[test]
fn from_u32_forward_compatible() {
assert_eq!(LivelinessKind::from_u32(0), LivelinessKind::Automatic);
assert_eq!(
LivelinessKind::from_u32(1),
LivelinessKind::ManualByParticipant
);
assert_eq!(LivelinessKind::from_u32(2), LivelinessKind::ManualByTopic);
assert_eq!(LivelinessKind::from_u32(3), LivelinessKind::Automatic);
assert_eq!(
LivelinessKind::from_u32(u32::MAX),
LivelinessKind::Automatic
);
}
#[test]
fn decode_unknown_kind_errors() {
let mut w = BufferWriter::new(Endianness::Little);
w.write_u32(7).unwrap();
Duration::from_millis(10).encode_into(&mut w).unwrap();
let bytes = w.into_bytes();
let mut r = BufferReader::new(&bytes, Endianness::Little);
let err = LivelinessQosPolicy::decode_from(&mut r).unwrap_err();
assert!(matches!(
err,
zerodds_cdr::DecodeError::InvalidEnum {
kind: "LivelinessKind",
value: 7
}
));
}
#[test]
fn decode_short_buffer_no_lease_errors() {
let mut w = BufferWriter::new(Endianness::Little);
w.write_u32(0).unwrap();
let bytes = w.into_bytes();
let mut r = BufferReader::new(&bytes, Endianness::Little);
assert!(LivelinessQosPolicy::decode_from(&mut r).is_err());
}
#[test]
fn default_debug_contains_infinite() {
let d = LivelinessQosPolicy::default();
assert!(d.lease_duration.is_infinite());
let dbg = alloc::format!("{d:?}");
assert!(dbg.contains("Automatic"), "debug: {dbg}");
}
#[test]
fn policy_is_copy() {
let p = LivelinessQosPolicy::default();
let q = p;
assert_eq!(p, q);
}
}