@@ -96,9 +96,6 @@ lazy_static! {
9696}
9797
9898/// 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).
10299#[ derive( Clone , Debug , Eq , Serialize ) ]
103100#[ non_exhaustive]
104101pub enum ServerAddress {
@@ -112,6 +109,12 @@ pub enum ServerAddress {
112109 /// The default is 27017.
113110 port : Option < u16 > ,
114111 } ,
112+ /// A Unix Domain Socket path.
113+ #[ cfg( unix) ]
114+ Unix {
115+ /// The path to the Unix Domain Socket.
116+ path : PathBuf ,
117+ } ,
115118}
116119
117120impl < ' de > Deserialize < ' de > for ServerAddress {
@@ -144,6 +147,10 @@ impl PartialEq for ServerAddress {
144147 port : other_port,
145148 } ,
146149 ) => 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 ,
147154 }
148155 }
149156}
@@ -158,6 +165,8 @@ impl Hash for ServerAddress {
158165 host. hash ( state) ;
159166 port. unwrap_or ( 27017 ) . hash ( state) ;
160167 }
168+ #[ cfg( unix) ]
169+ Self :: Unix { path } => path. hash ( state) ,
161170 }
162171 }
163172}
@@ -173,6 +182,15 @@ impl ServerAddress {
173182 /// Parses an address string into a `ServerAddress`.
174183 pub fn parse ( address : impl AsRef < str > ) -> Result < Self > {
175184 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+ }
176194 let mut parts = address. split ( ':' ) ;
177195 let hostname = match parts. next ( ) {
178196 Some ( part) => {
@@ -243,18 +261,28 @@ impl ServerAddress {
243261 "port" : port. map( |i| Bson :: Int32 ( i. into( ) ) ) . unwrap_or( Bson :: Null )
244262 }
245263 }
264+ #[ cfg( unix) ]
265+ Self :: Unix { path } => {
266+ doc ! {
267+ "path" : path. to_str( ) . unwrap( ) ,
268+ }
269+ }
246270 }
247271 }
248272
249273 pub ( crate ) fn host ( & self ) -> & str {
250274 match self {
251275 Self :: Tcp { host, .. } => host. as_str ( ) ,
276+ #[ cfg( unix) ]
277+ Self :: Unix { path } => path. to_str ( ) . unwrap ( ) ,
252278 }
253279 }
254280
255281 pub ( crate ) fn port ( & self ) -> Option < u16 > {
256282 match self {
257283 Self :: Tcp { port, .. } => * port,
284+ #[ cfg( unix) ]
285+ Self :: Unix { .. } => None ,
258286 }
259287 }
260288}
@@ -265,6 +293,8 @@ impl fmt::Display for ServerAddress {
265293 Self :: Tcp { host, port } => {
266294 write ! ( fmt, "{}:{}" , host, port. unwrap_or( DEFAULT_PORT ) )
267295 }
296+ #[ cfg( unix) ]
297+ Self :: Unix { path } => write ! ( fmt, "{}" , path. display( ) ) ,
268298 }
269299 }
270300}
@@ -1592,16 +1622,26 @@ impl ConnectionString {
15921622 }
15931623 . into ( ) ) ;
15941624 }
1595- // Unwrap safety: the `len` check above guarantees this can't fail.
1596- let ServerAddress :: Tcp { host, port } = host_list. into_iter ( ) . next ( ) . unwrap ( ) ;
15971625
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 ( ) ) ;
16011643 }
1602- . into ( ) ) ;
16031644 }
1604- HostInfo :: DnsRecord ( host)
16051645 } else {
16061646 HostInfo :: HostIdentifiers ( host_list)
16071647 } ;
@@ -2299,18 +2339,39 @@ mod tests {
22992339 #[ test]
23002340 fn test_parse_address_with_from_str ( ) {
23012341 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+ }
23052350
23062351 // Port defaults to 27017 (so this doesn't fail)
23072352 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, Some ( 27017 ) ) ;
2357+ }
2358+ #[ cfg( unix) ]
2359+ _ => panic ! ( "expected ServerAddress::Tcp" ) ,
2360+ }
23112361
23122362 let x = "localhost:not a number" . parse :: < ServerAddress > ( ) ;
23132363 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+ }
23142375 }
23152376
23162377 #[ cfg_attr( feature = "tokio-runtime" , tokio:: test) ]
0 commit comments