@@ -96,9 +96,6 @@ lazy_static! {
96
96
}
97
97
98
98
/// An enum representing the address of a MongoDB server.
99
- ///
100
- /// Currently this just supports addresses that can be connected to over TCP, but alternative
101
- /// address types may be supported in the future (e.g. Unix Domain Socket paths).
102
99
#[ derive( Clone , Debug , Eq , Serialize ) ]
103
100
#[ non_exhaustive]
104
101
pub enum ServerAddress {
@@ -112,6 +109,12 @@ pub enum ServerAddress {
112
109
/// The default is 27017.
113
110
port : Option < u16 > ,
114
111
} ,
112
+ /// A Unix Domain Socket path.
113
+ #[ cfg( unix) ]
114
+ Unix {
115
+ /// The path to the Unix Domain Socket.
116
+ path : PathBuf ,
117
+ } ,
115
118
}
116
119
117
120
impl < ' de > Deserialize < ' de > for ServerAddress {
@@ -144,6 +147,10 @@ impl PartialEq for ServerAddress {
144
147
port : other_port,
145
148
} ,
146
149
) => host == other_host && port. unwrap_or ( 27017 ) == other_port. unwrap_or ( 27017 ) ,
150
+ #[ cfg( unix) ]
151
+ ( Self :: Unix { path } , Self :: Unix { path : other_path } ) => path == other_path,
152
+ #[ cfg( unix) ]
153
+ _ => false ,
147
154
}
148
155
}
149
156
}
@@ -158,6 +165,8 @@ impl Hash for ServerAddress {
158
165
host. hash ( state) ;
159
166
port. unwrap_or ( 27017 ) . hash ( state) ;
160
167
}
168
+ #[ cfg( unix) ]
169
+ Self :: Unix { path } => path. hash ( state) ,
161
170
}
162
171
}
163
172
}
@@ -173,6 +182,15 @@ impl ServerAddress {
173
182
/// Parses an address string into a `ServerAddress`.
174
183
pub fn parse ( address : impl AsRef < str > ) -> Result < Self > {
175
184
let address = address. as_ref ( ) ;
185
+ // checks if the address is a unix domain socket
186
+ #[ cfg( unix) ]
187
+ {
188
+ if address. starts_with ( '/' ) {
189
+ return Ok ( ServerAddress :: Unix {
190
+ path : PathBuf :: from ( address) ,
191
+ } ) ;
192
+ }
193
+ }
176
194
let mut parts = address. split ( ':' ) ;
177
195
let hostname = match parts. next ( ) {
178
196
Some ( part) => {
@@ -243,18 +261,28 @@ impl ServerAddress {
243
261
"port" : port. map( |i| Bson :: Int32 ( i. into( ) ) ) . unwrap_or( Bson :: Null )
244
262
}
245
263
}
264
+ #[ cfg( unix) ]
265
+ Self :: Unix { path } => {
266
+ doc ! {
267
+ "path" : path. to_str( ) . unwrap( ) ,
268
+ }
269
+ }
246
270
}
247
271
}
248
272
249
273
pub ( crate ) fn host ( & self ) -> & str {
250
274
match self {
251
275
Self :: Tcp { host, .. } => host. as_str ( ) ,
276
+ #[ cfg( unix) ]
277
+ Self :: Unix { path } => path. to_str ( ) . unwrap ( ) ,
252
278
}
253
279
}
254
280
255
281
pub ( crate ) fn port ( & self ) -> Option < u16 > {
256
282
match self {
257
283
Self :: Tcp { port, .. } => * port,
284
+ #[ cfg( unix) ]
285
+ Self :: Unix { .. } => None ,
258
286
}
259
287
}
260
288
}
@@ -265,6 +293,8 @@ impl fmt::Display for ServerAddress {
265
293
Self :: Tcp { host, port } => {
266
294
write ! ( fmt, "{}:{}" , host, port. unwrap_or( DEFAULT_PORT ) )
267
295
}
296
+ #[ cfg( unix) ]
297
+ Self :: Unix { path } => write ! ( fmt, "{}" , path. display( ) ) ,
268
298
}
269
299
}
270
300
}
@@ -1592,16 +1622,26 @@ impl ConnectionString {
1592
1622
}
1593
1623
. into ( ) ) ;
1594
1624
}
1595
- // Unwrap safety: the `len` check above guarantees this can't fail.
1596
- let ServerAddress :: Tcp { host, port } = host_list. into_iter ( ) . next ( ) . unwrap ( ) ;
1597
1625
1598
- if port. is_some ( ) {
1599
- return Err ( ErrorKind :: InvalidArgument {
1600
- message : "a port cannot be specified with 'mongodb+srv'" . into ( ) ,
1626
+ // Unwrap safety: the `len` check above guarantees this can't fail.
1627
+ match host_list. into_iter ( ) . next ( ) . unwrap ( ) {
1628
+ ServerAddress :: Tcp { host, port } => {
1629
+ if port. is_some ( ) {
1630
+ return Err ( ErrorKind :: InvalidArgument {
1631
+ message : "a port cannot be specified with 'mongodb+srv'" . into ( ) ,
1632
+ }
1633
+ . into ( ) ) ;
1634
+ }
1635
+ HostInfo :: DnsRecord ( host)
1636
+ }
1637
+ #[ cfg( unix) ]
1638
+ ServerAddress :: Unix { .. } => {
1639
+ return Err ( ErrorKind :: InvalidArgument {
1640
+ message : "unix sockets cannot be used with 'mongodb+srv'" . into ( ) ,
1641
+ }
1642
+ . into ( ) ) ;
1601
1643
}
1602
- . into ( ) ) ;
1603
1644
}
1604
- HostInfo :: DnsRecord ( host)
1605
1645
} else {
1606
1646
HostInfo :: HostIdentifiers ( host_list)
1607
1647
} ;
@@ -2299,18 +2339,39 @@ mod tests {
2299
2339
#[ test]
2300
2340
fn test_parse_address_with_from_str ( ) {
2301
2341
let x = "localhost:27017" . parse :: < ServerAddress > ( ) . unwrap ( ) ;
2302
- let ServerAddress :: Tcp { host, port } = x;
2303
- assert_eq ! ( host, "localhost" ) ;
2304
- assert_eq ! ( port, Some ( 27017 ) ) ;
2342
+ match x {
2343
+ ServerAddress :: Tcp { host, port } => {
2344
+ assert_eq ! ( host, "localhost" ) ;
2345
+ assert_eq ! ( port, Some ( 27017 ) ) ;
2346
+ }
2347
+ #[ cfg( unix) ]
2348
+ _ => panic ! ( "expected ServerAddress::Tcp" ) ,
2349
+ }
2305
2350
2306
2351
// Port defaults to 27017 (so this doesn't fail)
2307
2352
let x = "localhost" . parse :: < ServerAddress > ( ) . unwrap ( ) ;
2308
- let ServerAddress :: Tcp { host, port } = x;
2309
- assert_eq ! ( host, "localhost" ) ;
2310
- assert_eq ! ( port, None ) ;
2353
+ match x {
2354
+ ServerAddress :: Tcp { host, port } => {
2355
+ assert_eq ! ( host, "localhost" ) ;
2356
+ assert_eq ! ( port, None ) ;
2357
+ }
2358
+ #[ cfg( unix) ]
2359
+ _ => panic ! ( "expected ServerAddress::Tcp" ) ,
2360
+ }
2311
2361
2312
2362
let x = "localhost:not a number" . parse :: < ServerAddress > ( ) ;
2313
2363
assert ! ( x. is_err( ) ) ;
2364
+
2365
+ #[ cfg( unix) ]
2366
+ {
2367
+ let x = "/path/to/socket.sock" . parse :: < ServerAddress > ( ) . unwrap ( ) ;
2368
+ match x {
2369
+ ServerAddress :: Unix { path } => {
2370
+ assert_eq ! ( path. to_str( ) . unwrap( ) , "/path/to/socket.sock" ) ;
2371
+ }
2372
+ _ => panic ! ( "expected ServerAddress::Unix" ) ,
2373
+ }
2374
+ }
2314
2375
}
2315
2376
2316
2377
#[ cfg_attr( feature = "tokio-runtime" , tokio:: test) ]
0 commit comments