1use core::fmt::Write;
19
20use crate::error::CppGenError;
21
22pub fn emit_dcps_header(out: &mut String) -> Result<(), CppGenError> {
27 writeln!(
28 out,
29 "// Block-H: DCPS-Entity-Header-Stubs (dds-psm-cxx-1.0 §8.1)."
30 )
31 .map_err(fmt_err)?;
32 writeln!(out).map_err(fmt_err)?;
33
34 emit_entity_base(out)?;
35 emit_domain_participant(out)?;
36 emit_topic(out)?;
37 emit_publisher(out)?;
38 emit_subscriber(out)?;
39 emit_data_writer(out)?;
40 emit_data_reader(out)?;
41
42 Ok(())
43}
44
45#[must_use]
47pub fn dcps_class_names() -> Vec<&'static str> {
48 vec![
49 "dds::core::Entity",
50 "dds::domain::DomainParticipant",
51 "dds::topic::Topic",
52 "dds::pub::Publisher",
53 "dds::sub::Subscriber",
54 "dds::pub::DataWriter",
55 "dds::sub::DataReader",
56 ]
57}
58
59fn emit_entity_base(out: &mut String) -> Result<(), CppGenError> {
60 writeln!(out, "namespace dds {{ namespace core {{").map_err(fmt_err)?;
61 writeln!(out).map_err(fmt_err)?;
62 writeln!(
63 out,
64 "/// Basisklasse aller DCPS-Entitaeten (dds-psm-cxx-1.0 §7.5.1)."
65 )
66 .map_err(fmt_err)?;
67 writeln!(out, "class Entity {{").map_err(fmt_err)?;
68 writeln!(out, "public:").map_err(fmt_err)?;
69 writeln!(out, " virtual ~Entity() = default;").map_err(fmt_err)?;
70 writeln!(out, " void enable();").map_err(fmt_err)?;
71 writeln!(out, " void close();").map_err(fmt_err)?;
72 writeln!(
73 out,
74 " const ::dds::core::InstanceHandle& instance_handle() const;"
75 )
76 .map_err(fmt_err)?;
77 writeln!(out, "}};").map_err(fmt_err)?;
78 writeln!(out).map_err(fmt_err)?;
79 writeln!(out, "}} }} // namespace dds::core").map_err(fmt_err)?;
80 writeln!(out).map_err(fmt_err)?;
81 Ok(())
82}
83
84fn emit_domain_participant(out: &mut String) -> Result<(), CppGenError> {
85 writeln!(out, "namespace dds {{ namespace domain {{").map_err(fmt_err)?;
86 writeln!(out).map_err(fmt_err)?;
87 writeln!(out, "/// DomainParticipant (dds-psm-cxx-1.0 §8.1.1).").map_err(fmt_err)?;
88 writeln!(
89 out,
90 "class DomainParticipant : public ::dds::core::Entity {{"
91 )
92 .map_err(fmt_err)?;
93 writeln!(out, "public:").map_err(fmt_err)?;
94 writeln!(out, " explicit DomainParticipant(int32_t domain_id);").map_err(fmt_err)?;
95 writeln!(
96 out,
97 " DomainParticipant(int32_t domain_id, const ::dds::domain::qos::DomainParticipantQos& qos);"
98 )
99 .map_err(fmt_err)?;
100 writeln!(out, " ~DomainParticipant() override;").map_err(fmt_err)?;
101 writeln!(out).map_err(fmt_err)?;
102 writeln!(out, " int32_t domain_id() const;").map_err(fmt_err)?;
103 writeln!(
104 out,
105 " const ::dds::domain::qos::DomainParticipantQos& qos() const;"
106 )
107 .map_err(fmt_err)?;
108 writeln!(
109 out,
110 " void qos(const ::dds::domain::qos::DomainParticipantQos& q);"
111 )
112 .map_err(fmt_err)?;
113 writeln!(out, " void assert_liveliness();").map_err(fmt_err)?;
114 writeln!(out, "}};").map_err(fmt_err)?;
115 writeln!(out).map_err(fmt_err)?;
116 writeln!(out, "}} }} // namespace dds::domain").map_err(fmt_err)?;
117 writeln!(out).map_err(fmt_err)?;
118 Ok(())
119}
120
121fn emit_topic(out: &mut String) -> Result<(), CppGenError> {
122 writeln!(out, "namespace dds {{ namespace topic {{").map_err(fmt_err)?;
123 writeln!(out).map_err(fmt_err)?;
124 writeln!(out, "/// Topic<T> (dds-psm-cxx-1.0 §8.1.2).").map_err(fmt_err)?;
125 writeln!(out, "template <typename T>").map_err(fmt_err)?;
126 writeln!(out, "class Topic : public ::dds::core::Entity {{").map_err(fmt_err)?;
127 writeln!(out, "public:").map_err(fmt_err)?;
128 writeln!(
129 out,
130 " Topic(::dds::domain::DomainParticipant& dp, const std::string& name);"
131 )
132 .map_err(fmt_err)?;
133 writeln!(
134 out,
135 " Topic(::dds::domain::DomainParticipant& dp, const std::string& name, const ::dds::topic::qos::TopicQos& qos);"
136 )
137 .map_err(fmt_err)?;
138 writeln!(out, " ~Topic() override;").map_err(fmt_err)?;
139 writeln!(out).map_err(fmt_err)?;
140 writeln!(out, " const std::string& name() const;").map_err(fmt_err)?;
141 writeln!(out, " const std::string& type_name() const;").map_err(fmt_err)?;
142 writeln!(out, " const ::dds::topic::qos::TopicQos& qos() const;").map_err(fmt_err)?;
143 writeln!(out, " void qos(const ::dds::topic::qos::TopicQos& q);").map_err(fmt_err)?;
144 writeln!(out, "}};").map_err(fmt_err)?;
145 writeln!(out).map_err(fmt_err)?;
146 writeln!(out, "}} }} // namespace dds::topic").map_err(fmt_err)?;
147 writeln!(out).map_err(fmt_err)?;
148 Ok(())
149}
150
151fn emit_publisher(out: &mut String) -> Result<(), CppGenError> {
152 writeln!(out, "namespace dds {{ namespace pub {{").map_err(fmt_err)?;
153 writeln!(out).map_err(fmt_err)?;
154 writeln!(out, "/// Publisher (dds-psm-cxx-1.0 §8.1.3).").map_err(fmt_err)?;
155 writeln!(out, "class Publisher : public ::dds::core::Entity {{").map_err(fmt_err)?;
156 writeln!(out, "public:").map_err(fmt_err)?;
157 writeln!(
158 out,
159 " explicit Publisher(::dds::domain::DomainParticipant& dp);"
160 )
161 .map_err(fmt_err)?;
162 writeln!(
163 out,
164 " Publisher(::dds::domain::DomainParticipant& dp, const ::dds::pub::qos::PublisherQos& qos);"
165 )
166 .map_err(fmt_err)?;
167 writeln!(out, " ~Publisher() override;").map_err(fmt_err)?;
168 writeln!(out).map_err(fmt_err)?;
169 writeln!(out, " const ::dds::pub::qos::PublisherQos& qos() const;").map_err(fmt_err)?;
170 writeln!(out, " void qos(const ::dds::pub::qos::PublisherQos& q);").map_err(fmt_err)?;
171 writeln!(
172 out,
173 " void wait_for_acknowledgments(const ::dds::core::Duration& timeout);"
174 )
175 .map_err(fmt_err)?;
176 writeln!(out, "}};").map_err(fmt_err)?;
177 writeln!(out).map_err(fmt_err)?;
178 writeln!(out, "}} }} // namespace dds::pub").map_err(fmt_err)?;
179 writeln!(out).map_err(fmt_err)?;
180 Ok(())
181}
182
183fn emit_subscriber(out: &mut String) -> Result<(), CppGenError> {
184 writeln!(out, "namespace dds {{ namespace sub {{").map_err(fmt_err)?;
185 writeln!(out).map_err(fmt_err)?;
186 writeln!(out, "/// Subscriber (dds-psm-cxx-1.0 §8.1.4).").map_err(fmt_err)?;
187 writeln!(out, "class Subscriber : public ::dds::core::Entity {{").map_err(fmt_err)?;
188 writeln!(out, "public:").map_err(fmt_err)?;
189 writeln!(
190 out,
191 " explicit Subscriber(::dds::domain::DomainParticipant& dp);"
192 )
193 .map_err(fmt_err)?;
194 writeln!(
195 out,
196 " Subscriber(::dds::domain::DomainParticipant& dp, const ::dds::sub::qos::SubscriberQos& qos);"
197 )
198 .map_err(fmt_err)?;
199 writeln!(out, " ~Subscriber() override;").map_err(fmt_err)?;
200 writeln!(out).map_err(fmt_err)?;
201 writeln!(
202 out,
203 " const ::dds::sub::qos::SubscriberQos& qos() const;"
204 )
205 .map_err(fmt_err)?;
206 writeln!(
207 out,
208 " void qos(const ::dds::sub::qos::SubscriberQos& q);"
209 )
210 .map_err(fmt_err)?;
211 writeln!(out, " void notify_datareaders();").map_err(fmt_err)?;
212 writeln!(out, "}};").map_err(fmt_err)?;
213 writeln!(out).map_err(fmt_err)?;
214 writeln!(out, "}} }} // namespace dds::sub").map_err(fmt_err)?;
215 writeln!(out).map_err(fmt_err)?;
216 Ok(())
217}
218
219fn emit_data_writer(out: &mut String) -> Result<(), CppGenError> {
220 writeln!(out, "namespace dds {{ namespace pub {{").map_err(fmt_err)?;
221 writeln!(out).map_err(fmt_err)?;
222 writeln!(out, "/// DataWriter<T> (dds-psm-cxx-1.0 §8.1.5).").map_err(fmt_err)?;
223 writeln!(out, "template <typename T>").map_err(fmt_err)?;
224 writeln!(out, "class DataWriter : public ::dds::core::Entity {{").map_err(fmt_err)?;
225 writeln!(out, "public:").map_err(fmt_err)?;
226 writeln!(
227 out,
228 " DataWriter(::dds::pub::Publisher& pub, ::dds::topic::Topic<T>& topic);"
229 )
230 .map_err(fmt_err)?;
231 writeln!(
232 out,
233 " DataWriter(::dds::pub::Publisher& pub, ::dds::topic::Topic<T>& topic, const ::dds::pub::qos::DataWriterQos& qos);"
234 )
235 .map_err(fmt_err)?;
236 writeln!(out, " ~DataWriter() override;").map_err(fmt_err)?;
237 writeln!(out).map_err(fmt_err)?;
238 writeln!(out, " void write(const T& sample);").map_err(fmt_err)?;
239 writeln!(
240 out,
241 " void write(const T& sample, const ::dds::core::Time& src_time);"
242 )
243 .map_err(fmt_err)?;
244 writeln!(
245 out,
246 " ::dds::core::InstanceHandle register_instance(const T& key);"
247 )
248 .map_err(fmt_err)?;
249 writeln!(
250 out,
251 " void unregister_instance(const ::dds::core::InstanceHandle& h);"
252 )
253 .map_err(fmt_err)?;
254 writeln!(
255 out,
256 " void dispose_instance(const ::dds::core::InstanceHandle& h);"
257 )
258 .map_err(fmt_err)?;
259 writeln!(
260 out,
261 " void wait_for_acknowledgments(const ::dds::core::Duration& timeout);"
262 )
263 .map_err(fmt_err)?;
264 writeln!(
265 out,
266 " ::dds::core::status::PublicationMatchedStatus publication_matched_status();"
267 )
268 .map_err(fmt_err)?;
269 writeln!(out, "}};").map_err(fmt_err)?;
270 writeln!(out).map_err(fmt_err)?;
271 writeln!(out, "}} }} // namespace dds::pub").map_err(fmt_err)?;
272 writeln!(out).map_err(fmt_err)?;
273 Ok(())
274}
275
276fn emit_data_reader(out: &mut String) -> Result<(), CppGenError> {
277 writeln!(out, "namespace dds {{ namespace sub {{").map_err(fmt_err)?;
278 writeln!(out).map_err(fmt_err)?;
279 writeln!(out, "/// DataReader<T> (dds-psm-cxx-1.0 §8.1.6).").map_err(fmt_err)?;
280 writeln!(out, "template <typename T>").map_err(fmt_err)?;
281 writeln!(out, "class DataReader : public ::dds::core::Entity {{").map_err(fmt_err)?;
282 writeln!(out, "public:").map_err(fmt_err)?;
283 writeln!(
284 out,
285 " DataReader(::dds::sub::Subscriber& sub, ::dds::topic::Topic<T>& topic);"
286 )
287 .map_err(fmt_err)?;
288 writeln!(
289 out,
290 " DataReader(::dds::sub::Subscriber& sub, ::dds::topic::Topic<T>& topic, const ::dds::sub::qos::DataReaderQos& qos);"
291 )
292 .map_err(fmt_err)?;
293 writeln!(out, " ~DataReader() override;").map_err(fmt_err)?;
294 writeln!(out).map_err(fmt_err)?;
295 writeln!(out, " std::vector<::dds::sub::Sample<T>> take();").map_err(fmt_err)?;
296 writeln!(out, " std::vector<::dds::sub::Sample<T>> read();").map_err(fmt_err)?;
297 writeln!(
298 out,
299 " ::dds::core::status::SubscriptionMatchedStatus subscription_matched_status();"
300 )
301 .map_err(fmt_err)?;
302 writeln!(
303 out,
304 " ::dds::core::status::SampleLostStatus sample_lost_status();"
305 )
306 .map_err(fmt_err)?;
307 writeln!(
308 out,
309 " ::dds::core::status::SampleRejectedStatus sample_rejected_status();"
310 )
311 .map_err(fmt_err)?;
312 writeln!(out, "}};").map_err(fmt_err)?;
313 writeln!(out).map_err(fmt_err)?;
314 writeln!(out, "}} }} // namespace dds::sub").map_err(fmt_err)?;
315 writeln!(out).map_err(fmt_err)?;
316 Ok(())
317}
318
319fn fmt_err(_: core::fmt::Error) -> CppGenError {
320 CppGenError::Internal("string formatting failed".into())
321}
322
323#[cfg(test)]
324mod tests {
325 #![allow(clippy::expect_used, clippy::panic)]
326 use super::*;
327
328 fn render() -> String {
329 let mut s = String::new();
330 emit_dcps_header(&mut s).expect("emit");
331 s
332 }
333
334 #[test]
335 fn entity_base_class_emitted_in_dds_core() {
336 let s = render();
337 assert!(s.contains("namespace dds { namespace core {"));
338 assert!(s.contains("class Entity {"));
339 assert!(s.contains("virtual ~Entity() = default;"));
340 }
341
342 #[test]
343 fn domain_participant_class_declaration_is_generated() {
344 let s = render();
345 assert!(s.contains("namespace dds { namespace domain {"));
346 assert!(s.contains("class DomainParticipant : public ::dds::core::Entity {"));
347 assert!(s.contains("explicit DomainParticipant(int32_t domain_id);"));
348 assert!(s.contains("int32_t domain_id() const;"));
349 }
350
351 #[test]
352 fn publisher_and_subscriber_emitted() {
353 let s = render();
354 assert!(s.contains("namespace dds { namespace pub {"));
355 assert!(s.contains("class Publisher : public ::dds::core::Entity {"));
356 assert!(s.contains("namespace dds { namespace sub {"));
357 assert!(s.contains("class Subscriber : public ::dds::core::Entity {"));
358 }
359
360 #[test]
361 fn topic_template_with_t_parameter() {
362 let s = render();
363 assert!(s.contains("namespace dds { namespace topic {"));
364 assert!(s.contains("template <typename T>"));
365 assert!(s.contains("class Topic : public ::dds::core::Entity {"));
366 }
367
368 #[test]
369 fn data_writer_and_data_reader_templates() {
370 let s = render();
371 assert!(s.contains("class DataWriter : public ::dds::core::Entity {"));
372 assert!(s.contains("class DataReader : public ::dds::core::Entity {"));
373 assert!(s.contains("void write(const T& sample);"));
374 assert!(s.contains("std::vector<::dds::sub::Sample<T>> take();"));
375 assert!(s.contains("std::vector<::dds::sub::Sample<T>> read();"));
376 }
377
378 #[test]
379 fn data_writer_has_status_accessor_for_publication_matched() {
380 let s = render();
381 assert!(s.contains(
382 "::dds::core::status::PublicationMatchedStatus publication_matched_status();"
383 ));
384 }
385
386 #[test]
387 fn dcps_class_names_count_seven() {
388 let names = dcps_class_names();
389 assert_eq!(names.len(), 7);
390 assert!(names.contains(&"dds::domain::DomainParticipant"));
391 assert!(names.contains(&"dds::topic::Topic"));
392 }
393}