zerodds_qos/policies/
generic_data.rs1use alloc::vec::Vec;
9
10use zerodds_cdr::{BufferReader, BufferWriter, DecodeError, EncodeError};
11
12pub const MAX_OPAQUE_LEN: usize = 64 * 1024;
17
18fn encode_opaque(w: &mut BufferWriter, bytes: &[u8]) -> Result<(), EncodeError> {
20 let len = u32::try_from(bytes.len()).map_err(|_| EncodeError::ValueOutOfRange {
21 message: "opaque data length exceeds u32::MAX",
22 })?;
23 w.write_u32(len)?;
24 w.write_bytes(bytes)
25}
26
27fn decode_opaque(r: &mut BufferReader<'_>) -> Result<Vec<u8>, DecodeError> {
28 let len = r.read_u32()? as usize;
29 if len > MAX_OPAQUE_LEN {
31 return Err(DecodeError::LengthExceeded {
32 announced: len,
33 remaining: MAX_OPAQUE_LEN,
34 offset: 0,
35 });
36 }
37 Ok(r.read_bytes(len)?.to_vec())
41}
42
43#[derive(Debug, Clone, PartialEq, Eq, Default)]
45pub struct UserDataQosPolicy {
46 pub value: Vec<u8>,
48}
49
50impl UserDataQosPolicy {
51 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
56 encode_opaque(w, &self.value)
57 }
58
59 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
64 Ok(Self {
65 value: decode_opaque(r)?,
66 })
67 }
68}
69
70#[derive(Debug, Clone, PartialEq, Eq, Default)]
72pub struct TopicDataQosPolicy {
73 pub value: Vec<u8>,
75}
76
77impl TopicDataQosPolicy {
78 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
83 encode_opaque(w, &self.value)
84 }
85
86 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
91 Ok(Self {
92 value: decode_opaque(r)?,
93 })
94 }
95}
96
97#[derive(Debug, Clone, PartialEq, Eq, Default)]
99pub struct GroupDataQosPolicy {
100 pub value: Vec<u8>,
102}
103
104impl GroupDataQosPolicy {
105 pub fn encode_into(&self, w: &mut BufferWriter) -> Result<(), EncodeError> {
110 encode_opaque(w, &self.value)
111 }
112
113 pub fn decode_from(r: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
118 Ok(Self {
119 value: decode_opaque(r)?,
120 })
121 }
122}
123
124#[cfg(test)]
125#[allow(clippy::unwrap_used)]
126mod tests {
127 use super::*;
128 use zerodds_cdr::Endianness;
129
130 #[test]
131 fn user_data_roundtrip() {
132 let p = UserDataQosPolicy {
133 value: alloc::vec![1, 2, 3, 4],
134 };
135 let mut w = BufferWriter::new(Endianness::Little);
136 p.encode_into(&mut w).unwrap();
137 let bytes = w.into_bytes();
138 let mut r = BufferReader::new(&bytes, Endianness::Little);
139 assert_eq!(UserDataQosPolicy::decode_from(&mut r).unwrap(), p);
140 }
141
142 #[test]
143 fn empty_data_roundtrip() {
144 let p = TopicDataQosPolicy::default();
145 let mut w = BufferWriter::new(Endianness::Little);
146 p.encode_into(&mut w).unwrap();
147 let bytes = w.into_bytes();
148 let mut r = BufferReader::new(&bytes, Endianness::Little);
149 assert_eq!(TopicDataQosPolicy::decode_from(&mut r).unwrap(), p);
150 }
151
152 #[test]
153 fn decoder_rejects_oversized_opaque() {
154 let mut bytes = alloc::vec::Vec::new();
155 bytes.extend_from_slice(&(MAX_OPAQUE_LEN as u32 + 1).to_le_bytes());
156 let mut r = BufferReader::new(&bytes, Endianness::Little);
157 let err = UserDataQosPolicy::decode_from(&mut r).unwrap_err();
158 assert!(matches!(err, DecodeError::LengthExceeded { .. }));
159 }
160
161 #[test]
162 fn group_data_large_payload() {
163 let p = GroupDataQosPolicy {
164 value: (0..200u8).collect(),
165 };
166 let mut w = BufferWriter::new(Endianness::Little);
167 p.encode_into(&mut w).unwrap();
168 let bytes = w.into_bytes();
169 let mut r = BufferReader::new(&bytes, Endianness::Little);
170 assert_eq!(GroupDataQosPolicy::decode_from(&mut r).unwrap(), p);
171 }
172}