1use crate::builtin_interfaces::Time;
10use crate::cdr::*;
11
12#[derive(PartialEq, Clone, Copy, Debug)]
15pub struct ColorRGBA {
16 pub r: f32,
17 pub g: f32,
18 pub b: f32,
19 pub a: f32,
20}
21
22impl CdrFixed for ColorRGBA {
23 const CDR_SIZE: usize = 16; fn read_cdr(cursor: &mut CdrCursor<'_>) -> Result<Self, CdrError> {
25 Ok(ColorRGBA {
26 r: cursor.read_f32()?,
27 g: cursor.read_f32()?,
28 b: cursor.read_f32()?,
29 a: cursor.read_f32()?,
30 })
31 }
32 fn write_cdr(&self, writer: &mut CdrWriter<'_>) {
33 writer.write_f32(self.r);
34 writer.write_f32(self.g);
35 writer.write_f32(self.b);
36 writer.write_f32(self.a);
37 }
38 fn size_cdr(sizer: &mut CdrSizer) {
39 sizer.size_f32();
40 sizer.size_f32();
41 sizer.size_f32();
42 sizer.size_f32();
43 }
44}
45
46pub struct Header<B> {
56 buf: B,
57 offsets: [usize; 1],
58}
59
60impl<B> Header<B> {
61 #[inline]
63 pub fn map_buffer<C>(self, f: impl FnOnce(B) -> C) -> Header<C> {
64 Header {
65 buf: f(self.buf),
66 offsets: self.offsets,
67 }
68 }
69}
70
71impl<B: AsRef<[u8]>> Header<B> {
72 pub fn from_cdr(buf: B) -> Result<Self, CdrError> {
73 let mut c = CdrCursor::new(buf.as_ref())?;
74 c.skip(8)?;
76 let _ = c.read_string()?;
77 Ok(Header {
78 offsets: [c.offset()],
79 buf,
80 })
81 }
82
83 pub fn stamp(&self) -> Time {
84 rd_time(self.buf.as_ref(), CDR_HEADER_SIZE)
85 }
86
87 pub fn frame_id(&self) -> &str {
88 rd_string(self.buf.as_ref(), CDR_HEADER_SIZE + 8).0
89 }
90
91 pub fn end_offset(&self) -> usize {
93 self.offsets[0]
94 }
95
96 pub fn as_cdr(&self) -> &[u8] {
97 self.buf.as_ref()
98 }
99
100 pub fn cdr_size(&self) -> usize {
101 self.buf.as_ref().len()
102 }
103
104 pub fn to_cdr(&self) -> Vec<u8> {
105 self.buf.as_ref().to_vec()
106 }
107}
108
109impl Header<Vec<u8>> {
110 #[deprecated(
111 since = "3.2.0",
112 note = "use Header::builder() for allocation-free buffer reuse; Header::new will be removed in 4.0"
113 )]
114 pub fn new(stamp: Time, frame_id: &str) -> Result<Self, CdrError> {
115 let mut sizer = CdrSizer::new();
116 Time::size_cdr(&mut sizer);
117 sizer.size_string(frame_id);
118
119 let mut buf = vec![0u8; sizer.size()];
120 let mut w = CdrWriter::new(&mut buf)?;
121 stamp.write_cdr(&mut w);
122 w.write_string(frame_id);
123 let offsets = [w.offset()];
124 w.finish()?;
125 Ok(Header { buf, offsets })
126 }
127
128 pub fn into_cdr(self) -> Vec<u8> {
129 self.buf
130 }
131
132 pub fn builder<'a>() -> HeaderBuilder<'a> {
138 HeaderBuilder::new()
139 }
140}
141
142pub struct HeaderBuilder<'a> {
151 stamp: Time,
152 frame_id: std::borrow::Cow<'a, str>,
153}
154
155impl<'a> Default for HeaderBuilder<'a> {
156 fn default() -> Self {
157 Self {
158 stamp: Time { sec: 0, nanosec: 0 },
159 frame_id: std::borrow::Cow::Borrowed(""),
160 }
161 }
162}
163
164impl<'a> HeaderBuilder<'a> {
165 pub fn new() -> Self {
166 Self::default()
167 }
168
169 pub fn stamp(&mut self, t: Time) -> &mut Self {
170 self.stamp = t;
171 self
172 }
173
174 pub fn frame_id(&mut self, s: impl Into<std::borrow::Cow<'a, str>>) -> &mut Self {
175 self.frame_id = s.into();
176 self
177 }
178
179 fn size(&self) -> usize {
180 let mut s = CdrSizer::new();
181 Time::size_cdr(&mut s);
182 s.size_string(&self.frame_id);
183 s.size()
184 }
185
186 fn write_into(&self, buf: &mut [u8]) -> Result<(), CdrError> {
187 let mut w = CdrWriter::new(buf)?;
188 self.stamp.write_cdr(&mut w);
189 w.write_string(&self.frame_id);
190 w.finish()
191 }
192
193 pub fn build(&self) -> Result<Header<Vec<u8>>, CdrError> {
195 let mut buf = vec![0u8; self.size()];
196 self.write_into(&mut buf)?;
197 Header::from_cdr(buf)
198 }
199
200 pub fn encode_into_vec(&self, buf: &mut Vec<u8>) -> Result<(), CdrError> {
204 buf.resize(self.size(), 0);
205 self.write_into(buf)
206 }
207
208 pub fn encode_into_slice(&self, buf: &mut [u8]) -> Result<usize, CdrError> {
212 let need = self.size();
213 if buf.len() < need {
214 return Err(CdrError::BufferTooShort {
215 need,
216 have: buf.len(),
217 });
218 }
219 self.write_into(&mut buf[..need])?;
220 Ok(need)
221 }
222}
223
224impl<B: AsRef<[u8]> + AsMut<[u8]>> Header<B> {
225 pub fn set_stamp(&mut self, t: Time) -> Result<(), CdrError> {
226 let b = self.buf.as_mut();
227 wr_i32(b, CDR_HEADER_SIZE, t.sec)?;
228 wr_u32(b, CDR_HEADER_SIZE + 4, t.nanosec)
229 }
230}
231
232pub fn is_type_supported(type_name: &str) -> bool {
236 matches!(type_name, "Header" | "ColorRGBA")
237}
238
239pub fn list_types() -> &'static [&'static str] {
241 &["std_msgs/msg/Header", "std_msgs/msg/ColorRGBA"]
242}
243
244use crate::schema_registry::SchemaType;
246
247impl SchemaType for ColorRGBA {
248 const SCHEMA_NAME: &'static str = "std_msgs/msg/ColorRGBA";
249}
250
251#[cfg(test)]
252#[allow(deprecated)]
253mod tests {
254 use super::*;
255 use crate::builtin_interfaces::Time;
256
257 #[test]
258 fn header_roundtrip() {
259 let cases = [
260 (0, 0, "", "empty"),
261 (100, 500_000_000, "camera", "typical"),
262 (42, 0, "a]long_frame_id", "with special chars"),
263 (1, 0, "camera/optical_frame", "path separator"),
264 (i32::MAX, 999_999_999, "max_frame", "max time"),
265 ];
266 for (sec, nanosec, frame_id, name) in cases {
267 let header = Header::new(Time::new(sec, nanosec), frame_id).unwrap();
268 assert_eq!(
269 header.stamp(),
270 Time::new(sec, nanosec),
271 "stamp failed: {}",
272 name
273 );
274 assert_eq!(header.frame_id(), frame_id, "frame_id failed: {}", name);
275
276 let bytes = header.to_cdr();
278 let decoded = Header::from_cdr(bytes).unwrap();
279 assert_eq!(
280 decoded.stamp(),
281 Time::new(sec, nanosec),
282 "rt stamp failed: {}",
283 name
284 );
285 assert_eq!(decoded.frame_id(), frame_id, "rt frame_id failed: {}", name);
286 }
287 }
288
289 #[test]
290 fn header_set_stamp() {
291 let mut header = Header::new(Time::new(0, 0), "test").unwrap();
292 header.set_stamp(Time::new(42, 123)).unwrap();
293 assert_eq!(header.stamp(), Time::new(42, 123));
294 }
295
296 #[test]
297 fn color_rgba_roundtrip() {
298 use crate::cdr::{decode_fixed, encode_fixed};
299
300 let cases = [
301 (0.0, 0.0, 0.0, 0.0, "zero/transparent"),
302 (1.0, 0.0, 0.0, 1.0, "red"),
303 (0.0, 1.0, 0.0, 1.0, "green"),
304 (0.0, 0.0, 1.0, 1.0, "blue"),
305 (1.0, 1.0, 1.0, 1.0, "white"),
306 (0.5, 0.5, 0.5, 0.5, "gray semi-transparent"),
307 ];
308 for (r, g, b, a, name) in cases {
309 let color = ColorRGBA { r, g, b, a };
310 let bytes = encode_fixed(&color).unwrap();
311 let decoded: ColorRGBA = decode_fixed(&bytes).unwrap();
312 assert_eq!(color, decoded, "failed for case: {}", name);
313 }
314 }
315}