hdds_micro/core/
writer.rs1use crate::error::{Error, Result};
7use crate::rtps::submessages::Data;
8use crate::rtps::{EntityId, GuidPrefix, Locator, RtpsHeader, SequenceNumber, GUID};
9use crate::transport::Transport;
10use crate::MAX_PACKET_SIZE;
11
12#[derive(Debug, PartialEq)]
43pub struct MicroWriter {
44 guid: GUID,
46
47 topic_name: [u8; 64],
49 topic_len: usize,
50
51 dest_locator: Locator,
53
54 sequence_number: SequenceNumber,
56}
57
58impl MicroWriter {
59 pub fn new(
68 guid_prefix: GuidPrefix,
69 entity_id: EntityId,
70 topic_name: &str,
71 dest_locator: Locator,
72 ) -> Result<Self> {
73 if topic_name.len() > 63 {
74 return Err(Error::InvalidParameter);
75 }
76
77 let mut topic_name_buf = [0u8; 64];
78 topic_name_buf[0..topic_name.len()].copy_from_slice(topic_name.as_bytes());
79
80 Ok(Self {
81 guid: GUID::new(guid_prefix, entity_id),
82 topic_name: topic_name_buf,
83 topic_len: topic_name.len(),
84 dest_locator,
85 sequence_number: SequenceNumber::MIN,
86 })
87 }
88
89 pub const fn guid(&self) -> GUID {
91 self.guid
92 }
93
94 pub fn topic_name(&self) -> &str {
96 core::str::from_utf8(&self.topic_name[0..self.topic_len]).unwrap_or("")
97 }
98
99 pub const fn sequence_number(&self) -> SequenceNumber {
101 self.sequence_number
102 }
103
104 pub fn write<T: Transport>(&mut self, payload: &[u8], transport: &mut T) -> Result<()> {
111 let mut packet = [0u8; MAX_PACKET_SIZE];
113
114 let header = RtpsHeader::new(
116 crate::rtps::ProtocolVersion::RTPS_2_5,
117 crate::rtps::VendorId::HDDS,
118 self.guid.prefix,
119 );
120 let header_len = header.encode(&mut packet)?;
121
122 let data = Data::new(
124 EntityId::UNKNOWN, self.guid.entity_id,
126 self.sequence_number,
127 );
128 let data_len = data.encode_header(&mut packet[header_len..])?;
129
130 let payload_offset = header_len + data_len;
132 if payload_offset + payload.len() > MAX_PACKET_SIZE {
133 return Err(Error::BufferTooSmall);
134 }
135 packet[payload_offset..payload_offset + payload.len()].copy_from_slice(payload);
136
137 let total_len = payload_offset + payload.len();
138
139 let octets_to_next = (20 + payload.len()) as u16;
142 packet[header_len + 2] = (octets_to_next & 0xff) as u8;
143 packet[header_len + 3] = ((octets_to_next >> 8) & 0xff) as u8;
144
145 transport.send(&packet[0..total_len], &self.dest_locator)?;
147
148 self.sequence_number.increment();
150
151 Ok(())
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158 use crate::cdr::CdrEncoder;
159 use crate::transport::NullTransport;
160
161 #[test]
162 fn test_writer_creation() {
163 let writer = MicroWriter::new(
164 GuidPrefix::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
165 EntityId::new([0, 0, 0, 0xc2]),
166 "TestTopic",
167 Locator::udpv4([239, 255, 0, 1], 7400),
168 )
169 .unwrap();
170
171 assert_eq!(writer.topic_name(), "TestTopic");
172 assert_eq!(writer.sequence_number(), SequenceNumber::MIN);
173 }
174
175 #[test]
176 fn test_writer_write() {
177 let mut writer = MicroWriter::new(
178 GuidPrefix::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
179 EntityId::new([0, 0, 0, 0xc2]),
180 "TestTopic",
181 Locator::udpv4([239, 255, 0, 1], 7400),
182 )
183 .unwrap();
184
185 let mut transport = NullTransport::default();
186
187 let mut buf = [0u8; 128];
189 let mut encoder = CdrEncoder::new(&mut buf);
190 encoder.encode_f32(23.5).unwrap();
191 let payload = encoder.finish();
192
193 writer.write(payload, &mut transport).unwrap();
195
196 assert_eq!(writer.sequence_number(), SequenceNumber::new(2));
198 }
199
200 #[test]
201 fn test_writer_topic_name_too_long() {
202 let long_name = "a".repeat(100);
203 let result = MicroWriter::new(
204 GuidPrefix::default(),
205 EntityId::default(),
206 &long_name,
207 Locator::default(),
208 );
209
210 assert_eq!(result, Err(Error::InvalidParameter));
211 }
212}