ruststream_gcp_pubsub/
subscription.rs1use std::time::Duration;
9
10use ruststream::SubscriptionSource;
11
12use crate::broker::ConnectedPubSubBroker;
13use crate::error::PubSubError;
14use crate::subscriber::PubSubSubscriber;
15
16#[derive(Debug, Clone, PartialEq, Eq)]
31#[must_use]
32pub struct PubSubSubscription {
33 name: String,
34 create_with_topic: Option<String>,
35 max_outstanding: Option<i64>,
36 ack_extension: Option<Duration>,
37}
38
39impl PubSubSubscription {
40 pub fn new(name: impl Into<String>) -> Self {
43 Self {
44 name: name.into(),
45 create_with_topic: None,
46 max_outstanding: None,
47 ack_extension: None,
48 }
49 }
50
51 pub fn create_with_topic(mut self, topic: impl Into<String>) -> Self {
55 self.create_with_topic = Some(topic.into());
56 self
57 }
58
59 pub fn max_outstanding(mut self, messages: i64) -> Self {
62 self.max_outstanding = Some(messages);
63 self
64 }
65
66 pub fn ack_extension(mut self, extension: Duration) -> Self {
69 self.ack_extension = Some(extension);
70 self
71 }
72
73 #[must_use]
75 pub fn subscription(&self) -> &str {
76 &self.name
77 }
78
79 pub(crate) fn create_topic_ref(&self) -> Option<&str> {
80 self.create_with_topic.as_deref()
81 }
82
83 pub(crate) fn max_outstanding_value(&self) -> Option<i64> {
84 self.max_outstanding
85 }
86
87 pub(crate) fn ack_extension_value(&self) -> Option<Duration> {
88 self.ack_extension
89 }
90
91 pub(crate) fn validate(&self) -> Result<(), PubSubError> {
93 if self.name.is_empty() {
94 return Err(PubSubError::InvalidDescriptor(
95 "subscription name must be non-empty".into(),
96 ));
97 }
98 if self.create_with_topic.as_deref() == Some("") {
99 return Err(PubSubError::InvalidDescriptor(
100 "topic name must be non-empty".into(),
101 ));
102 }
103 Ok(())
104 }
105}
106
107impl SubscriptionSource<ConnectedPubSubBroker> for PubSubSubscription {
108 type Subscriber = PubSubSubscriber;
109
110 fn name(&self) -> &str {
111 self.subscription()
112 }
113
114 async fn subscribe(
115 self,
116 connected: &ConnectedPubSubBroker,
117 ) -> Result<PubSubSubscriber, PubSubError> {
118 connected.subscribe_descriptor(self).await
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn empty_subscription_name_is_rejected_before_io() {
128 assert!(matches!(
129 PubSubSubscription::new("").validate(),
130 Err(PubSubError::InvalidDescriptor(_))
131 ));
132 }
133
134 #[test]
135 fn empty_topic_name_is_rejected_before_io() {
136 assert!(matches!(
137 PubSubSubscription::new("s")
138 .create_with_topic("")
139 .validate(),
140 Err(PubSubError::InvalidDescriptor(_))
141 ));
142 }
143}