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