Skip to main content

nt_client/topic/
collection.rs

1//! Collection of topics that can be used to subscribe to multiple topics at once.
2
3use std::{fmt::Debug, iter::FusedIterator};
4
5use crate::{ClientHandle, error::ConnectionClosedError, subscribe::{Subscriber, SubscriptionOptions}};
6
7use super::Topic;
8
9/// Represents a collection of topics.
10///
11/// This is used to subscribe to multiple topics at once.
12///
13/// # Examples
14/// ```no_run
15/// use nt_client::Client;
16///
17/// # tokio_test::block_on(async {
18/// let client = Client::new(Default::default());
19///
20/// client.connect_setup(setup).await.unwrap();
21/// # });
22///
23/// fn setup(client: &Client) {
24///     let topics = client.topics(vec![
25///         "/topic".to_owned(),
26///         "/nested/topic".to_owned(),
27///         "/deeply/nested/topic".to_owned(),
28///     ]);
29///     tokio::spawn(async move {
30///         let subscriber = topics.subscribe(Default::default()).await;
31///
32///         // do something with subscriber...
33///     });
34/// }
35/// ```
36#[derive(Debug, Clone)]
37pub struct TopicCollection {
38    names: Vec<String>,
39    handle: ClientHandle,
40}
41
42impl IntoIterator for TopicCollection {
43    type Item = Topic;
44    type IntoIter = IntoIter;
45
46    fn into_iter(self) -> Self::IntoIter {
47        IntoIter::new(self)
48    }
49}
50
51impl PartialEq for TopicCollection {
52    fn eq(&self, other: &Self) -> bool {
53        self.names == other.names
54    }
55}
56
57impl Eq for TopicCollection { }
58
59impl TopicCollection {
60    pub(crate) fn new(
61        names: Vec<String>,
62        handle: ClientHandle,
63    ) -> Self {
64        Self { names, handle }
65    }
66
67    /// Returns a slice of topic names this collection contains.
68    pub fn names(&self) -> &Vec<String> {
69        &self.names
70    }
71
72    /// Returns a mutable slice of topic names this collection contains.
73    pub fn names_mut(&mut self) -> &mut Vec<String> {
74        &mut self.names
75    }
76
77    /// Subscribes to this collection of topics.
78    ///
79    /// This method does not require the [`Client`] websocket connection to be made.
80    ///
81    /// [`Client`]: crate::Client
82    pub async fn subscribe(&self, options: SubscriptionOptions) -> Result<Subscriber, ConnectionClosedError> {
83        Subscriber::new(self.names.clone(), options, self.handle.announced_topics.clone(), self.handle.server_send.clone(), self.handle.client_send.subscribe()).await
84    }
85}
86
87/// Iterator that iterates over [`Topic`]s in a [`TopicCollection`].
88///
89/// This is obtained by the [`TopicCollection::into_iter`] method.
90pub struct IntoIter {
91    name_iter: std::vec::IntoIter<String>,
92    handle: ClientHandle,
93}
94
95impl Iterator for IntoIter {
96    type Item = Topic;
97
98    fn next(&mut self) -> Option<Self::Item> {
99        self.name_iter.next()
100            .map(|name| Topic::new(name, self.handle.clone()))
101    }
102}
103
104impl DoubleEndedIterator for IntoIter {
105    fn next_back(&mut self) -> Option<Self::Item> {
106        self.name_iter.next_back()
107            .map(|name| Topic::new(name, self.handle.clone()))
108    }
109}
110
111impl ExactSizeIterator for IntoIter {
112    fn len(&self) -> usize {
113        self.name_iter.len()
114    }
115}
116
117impl FusedIterator for IntoIter { }
118
119impl IntoIter {
120    pub(self) fn new(collection: TopicCollection) -> Self {
121        IntoIter {
122            name_iter: collection.names.into_iter(),
123            handle: collection.handle,
124        }
125    }
126}
127