cyclonedds_rs/
dds_topic.rs

1/*
2    Copyright 2020 Sojan James
3
4    Licensed under the Apache License, Version 2.0 (the "License");
5    you may not use this file except in compliance with the License.
6    You may obtain a copy of the License at
7
8        http://www.apache.org/licenses/LICENSE-2.0
9
10    Unless required by applicable law or agreed to in writing, software
11    distributed under the License is distributed on an "AS IS" BASIS,
12    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    See the License for the specific language governing permissions and
14    limitations under the License.
15*/
16
17use crate::{dds_listener::DdsListener, dds_participant::DdsParticipant, dds_qos::DdsQos, Entity};
18
19use std::convert::From;
20use std::ffi::CString;
21use std::marker::PhantomData;
22
23use crate::serdes::{SerType, TopicType};
24pub use cyclonedds_sys::{ddsi_sertype, DDSError, DdsEntity};
25
26pub struct TopicBuilder<T: TopicType> {
27    maybe_qos: Option<DdsQos>,
28    maybe_listener: Option<DdsListener>,
29    topic_name: String,
30    phantom: PhantomData<T>,
31}
32
33impl<T> TopicBuilder<T>
34where
35    T: TopicType,
36{
37    pub fn new() -> Self {
38        Self {
39            maybe_qos: None,
40            maybe_listener: None,
41            topic_name: T::topic_name(None),
42            phantom: PhantomData,
43        }
44    }
45
46    pub fn with_name(mut self, name: String) -> Self {
47        self.topic_name = name;
48        self
49    }
50
51    pub fn with_name_prefix(mut self, mut prefix_name: String) -> Self {
52        prefix_name.push_str(self.topic_name.as_str());
53        self.topic_name = prefix_name;
54        self
55    }
56
57    pub fn with_qos(mut self, qos: DdsQos) -> Self {
58        self.maybe_qos = Some(qos);
59        self
60    }
61
62    pub fn with_listener(mut self, listener: DdsListener) -> Self {
63        self.maybe_listener = Some(listener);
64        self
65    }
66
67    pub fn create(self, participant: &DdsParticipant) -> Result<DdsTopic<T>, DDSError> {
68        DdsTopic::<T>::create(
69            participant,
70            self.topic_name.as_str(),
71            self.maybe_qos,
72            self.maybe_listener,
73        )
74    }
75}
76
77pub struct DdsTopic<T: Sized + TopicType>(DdsEntity, PhantomData<T>, Option<DdsListener>);
78
79impl<T> DdsTopic<T>
80where
81    T: std::marker::Sized + TopicType,
82{
83    pub fn create(
84        participant: &DdsParticipant,
85        name: &str,
86        maybe_qos: Option<DdsQos>,
87        maybe_listener: Option<DdsListener>,
88    ) -> Result<Self, DDSError> {
89        let t = SerType::<T>::new();
90        let mut t = SerType::into_sertype(t);
91        let tt = &mut t as *mut *mut ddsi_sertype;
92
93        unsafe {
94            let strname = CString::new(name).expect("CString::new failed");
95            let topic = cyclonedds_sys::dds_create_topic_sertype(
96                participant.entity().entity(),
97                strname.as_ptr(),
98                tt,
99                maybe_qos.map_or(std::ptr::null(), |q| q.into()),
100                maybe_listener
101                    .as_ref()
102                    .map_or(std::ptr::null(), |l| l.into()),
103                std::ptr::null_mut(),
104            );
105
106            if topic >= 0 {
107                Ok(DdsTopic(DdsEntity::new(topic), PhantomData, maybe_listener))
108            } else {
109                Err(DDSError::from(topic))
110            }
111        }
112    }
113}
114
115impl<T> Entity for DdsTopic<T>
116where
117    T: std::marker::Sized + TopicType,
118{
119    fn entity(&self) -> &DdsEntity {
120        &self.0
121    }
122}
123
124impl<T> Clone for DdsTopic<T>
125where
126    T: std::marker::Sized + TopicType,
127{
128    fn clone(&self) -> Self {
129        Self(self.0.clone(), PhantomData, self.2.clone())
130    }
131}
132
133#[cfg(test)]
134mod test {
135    use super::*;
136    use crate::SampleBuffer;
137    use crate::{DdsPublisher, DdsWriter};
138    use cdds_derive::Topic;
139    use serde_derive::{Deserialize, Serialize};
140    use std::sync::Arc;
141    #[test]
142    fn test_topic_creation() {
143        #[derive(Default, Deserialize, Serialize, Topic)]
144        struct MyTopic {
145            #[topic_key]
146            a: u32,
147            b: u32,
148            c: String,
149            d: u32,
150        }
151
152        assert_eq!(
153            MyTopic::topic_name(None),
154            String::from("/dds_topic/test/test_topic_creation/MyTopic")
155        );
156        assert_eq!(
157            MyTopic::topic_name(Some("prefix")),
158            String::from("prefix/dds_topic/test/test_topic_creation/MyTopic")
159        );
160
161        let participant = DdsParticipant::create(None, None, None).unwrap();
162        let topic = MyTopic::create_topic(&participant, None, None, None).unwrap();
163        let publisher =
164            DdsPublisher::create(&participant, None, None).expect("Unable to create publisher");
165        let mut writer = DdsWriter::create(&publisher, topic, None, None).unwrap();
166
167        // MyTopic::create_writer()
168
169        let data = Arc::new(MyTopic {
170            a: 1,
171            b: 32,
172            c: "my_data_sample".to_owned(),
173            d: 546,
174        });
175
176        writer.write(data).unwrap();
177    }
178}