Skip to content

Commit 993f2c9

Browse files
authored
RUST-760 Refactor the StreamAddress struct to ServerAddress enum (#339)
1 parent 93c4554 commit 993f2c9

File tree

36 files changed

+299
-230
lines changed

36 files changed

+299
-230
lines changed

src/client/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use derivative::Derivative;
1010
use std::time::Instant;
1111

1212
#[cfg(test)]
13-
use crate::options::StreamAddress;
13+
use crate::options::ServerAddress;
1414
use crate::{
1515
bson::Document,
1616
concern::{ReadConcern, WriteConcern},
@@ -263,7 +263,7 @@ impl Client {
263263
pub(crate) async fn test_select_server(
264264
&self,
265265
criteria: Option<&SelectionCriteria>,
266-
) -> Result<StreamAddress> {
266+
) -> Result<ServerAddress> {
267267
let server = self.select_server(criteria).await?;
268268
Ok(server.address.clone())
269269
}

src/client/options/mod.rs

Lines changed: 132 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ lazy_static! {
101101

102102
/// A hostname:port address pair.
103103
#[derive(Clone, Debug, Eq)]
104+
#[deprecated = "This type has been renamed to `ServerAddress` and will be removed in the 2.0.0 \
105+
stable release"]
104106
pub struct StreamAddress {
105107
/// The hostname of the address.
106108
pub hostname: String,
@@ -111,7 +113,44 @@ pub struct StreamAddress {
111113
pub port: Option<u16>,
112114
}
113115

114-
impl<'de> Deserialize<'de> for StreamAddress {
116+
#[allow(deprecated)]
117+
impl PartialEq for StreamAddress {
118+
fn eq(&self, other: &Self) -> bool {
119+
self.hostname == other.hostname && self.port.unwrap_or(27017) == other.port.unwrap_or(27017)
120+
}
121+
}
122+
123+
#[allow(deprecated)]
124+
impl Hash for StreamAddress {
125+
fn hash<H>(&self, state: &mut H)
126+
where
127+
H: Hasher,
128+
{
129+
self.hostname.hash(state);
130+
self.port.unwrap_or(27017).hash(state);
131+
}
132+
}
133+
134+
/// An enum representing the address of a MongoDB server.
135+
///
136+
/// Currently this just supports addresses that can be connected to over TCP, but alternative
137+
/// address types may be supported in the future (e.g. Unix Domain Socket paths).
138+
#[derive(Clone, Debug, Eq)]
139+
#[non_exhaustive]
140+
pub enum ServerAddress {
141+
/// A TCP/IP host and port combination.
142+
Tcp {
143+
/// The hostname or IP address where the MongoDB server can be found.
144+
host: String,
145+
146+
/// The TCP port that the MongoDB server is listening on.
147+
///
148+
/// The default is 27017.
149+
port: Option<u16>,
150+
},
151+
}
152+
153+
impl<'de> Deserialize<'de> for ServerAddress {
115154
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
116155
where
117156
D: Deserializer<'de>,
@@ -121,32 +160,54 @@ impl<'de> Deserialize<'de> for StreamAddress {
121160
}
122161
}
123162

124-
impl Default for StreamAddress {
163+
impl Default for ServerAddress {
125164
fn default() -> Self {
126-
Self {
127-
hostname: "localhost".into(),
165+
Self::Tcp {
166+
host: "localhost".into(),
128167
port: None,
129168
}
130169
}
131170
}
132171

133-
impl PartialEq for StreamAddress {
172+
impl PartialEq for ServerAddress {
134173
fn eq(&self, other: &Self) -> bool {
135-
self.hostname == other.hostname && self.port.unwrap_or(27017) == other.port.unwrap_or(27017)
174+
match (self, other) {
175+
(
176+
Self::Tcp { host, port },
177+
Self::Tcp {
178+
host: other_host,
179+
port: other_port,
180+
},
181+
) => host == other_host && port.unwrap_or(27017) == other_port.unwrap_or(27017),
182+
}
136183
}
137184
}
138185

139-
impl Hash for StreamAddress {
186+
impl Hash for ServerAddress {
140187
fn hash<H>(&self, state: &mut H)
141188
where
142189
H: Hasher,
143190
{
144-
self.hostname.hash(state);
145-
self.port.unwrap_or(27017).hash(state);
191+
match self {
192+
Self::Tcp { host, port } => {
193+
host.hash(state);
194+
port.unwrap_or(27017).hash(state);
195+
}
196+
}
146197
}
147198
}
148199

149-
impl StreamAddress {
200+
#[allow(deprecated)]
201+
impl From<StreamAddress> for ServerAddress {
202+
fn from(sa: StreamAddress) -> Self {
203+
Self::Tcp {
204+
host: sa.hostname,
205+
port: sa.port,
206+
}
207+
}
208+
}
209+
210+
impl ServerAddress {
150211
/// Parses an address string into a `StreamAddress`.
151212
pub fn parse(address: impl AsRef<str>) -> Result<Self> {
152213
let address = address.as_ref();
@@ -186,36 +247,44 @@ impl StreamAddress {
186247
None => None,
187248
};
188249

189-
Ok(StreamAddress {
190-
hostname: hostname.to_string(),
250+
Ok(ServerAddress::Tcp {
251+
host: hostname.to_string(),
191252
port,
192253
})
193254
}
194255

195256
#[cfg(all(test, not(feature = "sync")))]
196-
pub(crate) fn into_document(mut self) -> Document {
197-
let mut doc = Document::new();
198-
199-
doc.insert("host", &self.hostname);
257+
pub(crate) fn into_document(self) -> Document {
258+
match self {
259+
Self::Tcp { host, port } => {
260+
doc! {
261+
"host": host,
262+
"port": port.map(|i| Bson::Int32(i.into())).unwrap_or(Bson::Null)
263+
}
264+
}
265+
}
266+
}
200267

201-
if let Some(i) = self.port.take() {
202-
doc.insert("port", i32::from(i));
203-
} else {
204-
doc.insert("port", Bson::Null);
268+
pub(crate) fn host(&self) -> &str {
269+
match self {
270+
Self::Tcp { host, .. } => host.as_str(),
205271
}
272+
}
206273

207-
doc
274+
pub(crate) fn port(&self) -> Option<u16> {
275+
match self {
276+
Self::Tcp { port, .. } => *port,
277+
}
208278
}
209279
}
210280

211-
impl fmt::Display for StreamAddress {
281+
impl fmt::Display for ServerAddress {
212282
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
213-
write!(
214-
fmt,
215-
"{}:{}",
216-
self.hostname,
217-
self.port.unwrap_or(DEFAULT_PORT)
218-
)
283+
match self {
284+
Self::Tcp { host, port } => {
285+
write!(fmt, "{}:{}", host, port.unwrap_or(DEFAULT_PORT))
286+
}
287+
}
219288
}
220289
}
221290

@@ -291,12 +360,12 @@ pub struct ClientOptions {
291360
/// Note that by default, the driver will autodiscover other nodes in the cluster. To connect
292361
/// directly to a single server (rather than autodiscovering the rest of the cluster), set the
293362
/// `direct` field to `true`.
294-
#[builder(default_code = "vec![ StreamAddress {
295-
hostname: \"localhost\".to_string(),
363+
#[builder(default_code = "vec![ServerAddress::Tcp {
364+
host: \"localhost\".to_string(),
296365
port: Some(27017),
297366
}]")]
298367
#[serde(default = "default_hosts")]
299-
pub hosts: Vec<StreamAddress>,
368+
pub hosts: Vec<ServerAddress>,
300369

301370
/// The application name that the Client will send to the server as part of the handshake. This
302371
/// can be used in combination with the server logs to determine which Client is connected to a
@@ -472,11 +541,8 @@ pub struct ClientOptions {
472541
pub(crate) heartbeat_freq_test: Option<Duration>,
473542
}
474543

475-
fn default_hosts() -> Vec<StreamAddress> {
476-
vec![StreamAddress {
477-
hostname: "localhost".to_string(),
478-
port: Some(27017),
479-
}]
544+
fn default_hosts() -> Vec<ServerAddress> {
545+
vec![ServerAddress::default()]
480546
}
481547

482548
impl Default for ClientOptions {
@@ -487,7 +553,7 @@ impl Default for ClientOptions {
487553

488554
#[derive(Debug, Default, PartialEq)]
489555
struct ClientOptionsParser {
490-
pub hosts: Vec<StreamAddress>,
556+
pub hosts: Vec<ServerAddress>,
491557
pub srv: bool,
492558
pub app_name: Option<String>,
493559
pub tls: Option<Tls>,
@@ -825,11 +891,11 @@ impl ClientOptions {
825891
if srv {
826892
let mut resolver = SrvResolver::new(resolver_config.map(|config| config.inner)).await?;
827893
let mut config = resolver
828-
.resolve_client_options(&options.hosts[0].hostname)
894+
.resolve_client_options(&options.hosts[0].host())
829895
.await?;
830896

831897
// Save the original SRV hostname to allow mongos polling.
832-
options.original_srv_hostname = Some(options.hosts[0].hostname.clone());
898+
options.original_srv_hostname = Some(options.hosts[0].host().to_string());
833899

834900
// Set the ClientOptions hosts to those found during the SRV lookup.
835901
options.hosts = config.hosts;
@@ -1123,8 +1189,8 @@ impl ClientOptionsParser {
11231189
Some(p)
11241190
};
11251191

1126-
Ok(StreamAddress {
1127-
hostname: hostname.to_lowercase(),
1192+
Ok(ServerAddress::Tcp {
1193+
host: hostname.to_lowercase(),
11281194
port,
11291195
})
11301196
})
@@ -1140,7 +1206,7 @@ impl ClientOptionsParser {
11401206
.into());
11411207
}
11421208

1143-
if hosts[0].port.is_some() {
1209+
if hosts[0].port().is_some() {
11441210
return Err(ErrorKind::InvalidArgument {
11451211
message: "a port cannot be specified with 'mongodb+srv'".into(),
11461212
}
@@ -1722,7 +1788,7 @@ mod tests {
17221788

17231789
use pretty_assertions::assert_eq;
17241790

1725-
use super::{ClientOptions, StreamAddress};
1791+
use super::{ClientOptions, ServerAddress};
17261792
use crate::{
17271793
concern::{Acknowledgment, ReadConcernLevel, WriteConcern},
17281794
selection_criteria::{ReadPreference, ReadPreferenceOptions},
@@ -1745,9 +1811,9 @@ mod tests {
17451811
}
17461812
}
17471813

1748-
fn host_without_port(hostname: &str) -> StreamAddress {
1749-
StreamAddress {
1750-
hostname: hostname.to_string(),
1814+
fn host_without_port(hostname: &str) -> ServerAddress {
1815+
ServerAddress::Tcp {
1816+
host: hostname.to_string(),
17511817
port: None,
17521818
}
17531819
}
@@ -1822,8 +1888,8 @@ mod tests {
18221888
assert_eq!(
18231889
ClientOptions::parse(uri).await.unwrap(),
18241890
ClientOptions {
1825-
hosts: vec![StreamAddress {
1826-
hostname: "localhost".to_string(),
1891+
hosts: vec![ServerAddress::Tcp {
1892+
host: "localhost".to_string(),
18271893
port: Some(27017),
18281894
}],
18291895
original_uri: Some(uri.into()),
@@ -1840,8 +1906,8 @@ mod tests {
18401906
assert_eq!(
18411907
ClientOptions::parse(uri).await.unwrap(),
18421908
ClientOptions {
1843-
hosts: vec![StreamAddress {
1844-
hostname: "localhost".to_string(),
1909+
hosts: vec![ServerAddress::Tcp {
1910+
host: "localhost".to_string(),
18451911
port: Some(27017),
18461912
}],
18471913
original_uri: Some(uri.into()),
@@ -1858,8 +1924,8 @@ mod tests {
18581924
assert_eq!(
18591925
ClientOptions::parse(uri).await.unwrap(),
18601926
ClientOptions {
1861-
hosts: vec![StreamAddress {
1862-
hostname: "localhost".to_string(),
1927+
hosts: vec![ServerAddress::Tcp {
1928+
host: "localhost".to_string(),
18631929
port: Some(27017),
18641930
}],
18651931
read_concern: Some(ReadConcernLevel::Custom("foo".to_string()).into()),
@@ -1886,8 +1952,8 @@ mod tests {
18861952
assert_eq!(
18871953
ClientOptions::parse(uri).await.unwrap(),
18881954
ClientOptions {
1889-
hosts: vec![StreamAddress {
1890-
hostname: "localhost".to_string(),
1955+
hosts: vec![ServerAddress::Tcp {
1956+
host: "localhost".to_string(),
18911957
port: Some(27017),
18921958
}],
18931959
write_concern: Some(write_concern),
@@ -1908,8 +1974,8 @@ mod tests {
19081974
assert_eq!(
19091975
ClientOptions::parse(uri).await.unwrap(),
19101976
ClientOptions {
1911-
hosts: vec![StreamAddress {
1912-
hostname: "localhost".to_string(),
1977+
hosts: vec![ServerAddress::Tcp {
1978+
host: "localhost".to_string(),
19131979
port: Some(27017),
19141980
}],
19151981
write_concern: Some(write_concern),
@@ -1938,8 +2004,8 @@ mod tests {
19382004
assert_eq!(
19392005
ClientOptions::parse(uri).await.unwrap(),
19402006
ClientOptions {
1941-
hosts: vec![StreamAddress {
1942-
hostname: "localhost".to_string(),
2007+
hosts: vec![ServerAddress::Tcp {
2008+
host: "localhost".to_string(),
19432009
port: Some(27017),
19442010
}],
19452011
write_concern: Some(write_concern),
@@ -1980,8 +2046,8 @@ mod tests {
19802046
assert_eq!(
19812047
ClientOptions::parse(uri).await.unwrap(),
19822048
ClientOptions {
1983-
hosts: vec![StreamAddress {
1984-
hostname: "localhost".to_string(),
2049+
hosts: vec![ServerAddress::Tcp {
2050+
host: "localhost".to_string(),
19852051
port: Some(27017),
19862052
}],
19872053
write_concern: Some(write_concern),
@@ -2004,8 +2070,8 @@ mod tests {
20042070
assert_eq!(
20052071
ClientOptions::parse(uri).await.unwrap(),
20062072
ClientOptions {
2007-
hosts: vec![StreamAddress {
2008-
hostname: "localhost".to_string(),
2073+
hosts: vec![ServerAddress::Tcp {
2074+
host: "localhost".to_string(),
20092075
port: Some(27017),
20102076
}],
20112077
write_concern: Some(write_concern),
@@ -2037,12 +2103,12 @@ mod tests {
20372103
ClientOptions::parse(uri).await.unwrap(),
20382104
ClientOptions {
20392105
hosts: vec![
2040-
StreamAddress {
2041-
hostname: "localhost".to_string(),
2106+
ServerAddress::Tcp {
2107+
host: "localhost".to_string(),
20422108
port: None,
20432109
},
2044-
StreamAddress {
2045-
hostname: "localhost".to_string(),
2110+
ServerAddress::Tcp {
2111+
host: "localhost".to_string(),
20462112
port: Some(27018),
20472113
},
20482114
],

0 commit comments

Comments
 (0)