zerodds_qos/policies/
reliability.rs1use zerodds_cdr::{BufferReader, BufferWriter, DecodeError, EncodeError};
9
10use crate::duration::Duration;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
17#[repr(u32)]
18pub enum ReliabilityKind {
19 BestEffort = 1,
21 Reliable = 2,
23}
24
25impl Default for ReliabilityKind {
26 fn default() -> Self {
30 Self::BestEffort
31 }
32}
33
34impl ReliabilityKind {
35 #[must_use]
37 pub const fn try_from_u32(v: u32) -> Option<Self> {
38 match v {
39 1 => Some(Self::BestEffort),
40 2 => Some(Self::Reliable),
41 _ => None,
42 }
43 }
44
45 #[must_use]
47 pub const fn from_u32(v: u32) -> Self {
48 match v {
49 2 => Self::Reliable,
50 _ => Self::BestEffort,
51 }
52 }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub struct ReliabilityQosPolicy {
58 pub kind: ReliabilityKind,
60 pub max_blocking_time: Duration,
66}
67
68impl Default for ReliabilityQosPolicy {
69 fn default() -> Self {
70 Self {
71 kind: ReliabilityKind::BestEffort,
72 max_blocking_time: Duration::from_millis(100),
74 }
75 }
76}
77
78impl ReliabilityQosPolicy {
79 pub fn encode_into(self, w: &mut BufferWriter) -> Result<(), EncodeError> {
84 w.write_u32(self.kind as u32)?;
85 self.max_blocking_time.encode_into(w)
86 }
87
88 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
93 let v = r.read_u32()?;
94 let kind = ReliabilityKind::try_from_u32(v).ok_or(DecodeError::InvalidEnum {
95 kind: "ReliabilityKind",
96 value: v,
97 })?;
98 let max_blocking_time = Duration::decode_from(r)?;
99 Ok(Self {
100 kind,
101 max_blocking_time,
102 })
103 }
104}
105
106#[cfg(test)]
107#[allow(clippy::unwrap_used)]
108mod tests {
109 use super::*;
110 use zerodds_cdr::Endianness;
111
112 #[test]
113 fn best_effort_lt_reliable() {
114 assert!(ReliabilityKind::BestEffort < ReliabilityKind::Reliable);
115 }
116
117 #[test]
118 fn try_from_u32_is_strict() {
119 assert_eq!(ReliabilityKind::try_from_u32(0), None);
120 assert_eq!(
121 ReliabilityKind::try_from_u32(1),
122 Some(ReliabilityKind::BestEffort)
123 );
124 assert_eq!(
125 ReliabilityKind::try_from_u32(2),
126 Some(ReliabilityKind::Reliable)
127 );
128 assert_eq!(ReliabilityKind::try_from_u32(3), None);
129 }
130
131 #[test]
132 fn encode_decode_roundtrip() {
133 let p = ReliabilityQosPolicy {
134 kind: ReliabilityKind::Reliable,
135 max_blocking_time: Duration::from_millis(250),
136 };
137 let mut w = BufferWriter::new(Endianness::Little);
138 p.encode_into(&mut w).unwrap();
139 let bytes = w.into_bytes();
140 assert_eq!(bytes.len(), 12);
141 let mut r = BufferReader::new(&bytes, Endianness::Little);
142 assert_eq!(ReliabilityQosPolicy::decode_from(&mut r).unwrap(), p);
143 }
144
145 #[test]
146 fn default_is_best_effort_100ms() {
147 let d = ReliabilityQosPolicy::default();
148 assert_eq!(d.kind, ReliabilityKind::BestEffort);
149 assert_eq!(d.max_blocking_time, Duration::from_millis(100));
150 }
151
152 #[test]
154 fn from_u32_forward_compatible() {
155 assert_eq!(ReliabilityKind::from_u32(1), ReliabilityKind::BestEffort);
156 assert_eq!(ReliabilityKind::from_u32(2), ReliabilityKind::Reliable);
157 assert_eq!(ReliabilityKind::from_u32(0), ReliabilityKind::BestEffort);
160 assert_eq!(ReliabilityKind::from_u32(99), ReliabilityKind::BestEffort);
161 }
162
163 #[test]
166 fn best_effort_roundtrip_with_custom_blocking() {
167 let p = ReliabilityQosPolicy {
168 kind: ReliabilityKind::BestEffort,
169 max_blocking_time: Duration::from_millis(2500),
170 };
171 let mut w = BufferWriter::new(Endianness::Little);
172 p.encode_into(&mut w).unwrap();
173 let bytes = w.into_bytes();
174 assert_eq!(bytes.len(), 12);
175 assert_eq!(&bytes[0..4], &[1u8, 0, 0, 0]);
177 let mut r = BufferReader::new(&bytes, Endianness::Little);
178 assert_eq!(ReliabilityQosPolicy::decode_from(&mut r).unwrap(), p);
179 }
180
181 #[test]
183 fn debug_and_clone_work() {
184 let p = ReliabilityQosPolicy {
185 kind: ReliabilityKind::Reliable,
186 max_blocking_time: Duration::from_secs(1),
187 };
188 #[allow(clippy::clone_on_copy)]
189 let p2 = p.clone();
190 assert_eq!(p, p2);
191 let dbg = alloc::format!("{p:?}");
192 assert!(dbg.contains("Reliable"), "debug: {dbg}");
193 }
194
195 #[test]
197 fn decode_unknown_kind_errors() {
198 let mut w = BufferWriter::new(Endianness::Little);
199 w.write_u32(5).unwrap();
200 Duration::ZERO.encode_into(&mut w).unwrap();
201 let bytes = w.into_bytes();
202 let mut r = BufferReader::new(&bytes, Endianness::Little);
203 let err = ReliabilityQosPolicy::decode_from(&mut r).unwrap_err();
204 assert!(matches!(
205 err,
206 zerodds_cdr::DecodeError::InvalidEnum {
207 kind: "ReliabilityKind",
208 value: 5
209 }
210 ));
211 }
212
213 #[test]
216 fn decode_short_buffer_no_duration_errors() {
217 let mut w = BufferWriter::new(Endianness::Little);
218 w.write_u32(2).unwrap(); let bytes = w.into_bytes();
220 let mut r = BufferReader::new(&bytes, Endianness::Little);
221 assert!(ReliabilityQosPolicy::decode_from(&mut r).is_err());
222 }
223
224 #[test]
227 fn ordering_reliable_higher_than_besteffort() {
228 assert!(ReliabilityKind::Reliable > ReliabilityKind::BestEffort);
229 }
230}