1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#![cfg_attr(docsrs, feature(doc_cfg))]

#[cfg(feature = "tokio")]
#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
pub mod tokio;

use std::fmt;
use std::str::FromStr;

#[cfg(unix)]
use std::path::PathBuf;


/// Protocol selection enum.
#[derive(Debug, Clone)]
pub enum ProtAddr {
  /// Connect over TCP/IP.  The `String` is a socket address in the form
  /// `<host>:<port>`.
  Tcp(String),

  /// Connect over unix local domain sockets.  The `PathBuf` is a file system
  /// socket path.
  #[cfg(unix)]
  Uds(PathBuf)
}

impl ProtAddr {
  #[cfg(unix)]
  pub fn is_uds(&self) -> bool {
    match self {
      ProtAddr::Tcp(_) => false,
      ProtAddr::Uds(_) => true
    }
  }

  #[cfg(windows)]
  pub fn is_uds() -> bool {
    false
  }

  /// Returns `true` is this objects represents a TCP/IP address.
  pub fn is_tcp(&self) -> bool {
    match self {
      ProtAddr::Tcp(_) => true,
      #[cfg(unix)]
      _ => false
    }
  }
}

impl FromStr for ProtAddr {
  type Err = ();

  /// Parse a `&str` and turn it into a `ProtAddr`.
  ///
  /// On unixy platforms if the `addr` contains one or more slashes (`/`) it is
  /// assumed the address is a unix local domain socket address.  Otherwise
  /// it is assumed the address is an IP socket address, in the form
  /// `<host>:<port>`.
  fn from_str(addr: &str) -> Result<Self, Self::Err> {
    #[cfg(unix)]
    if addr.find('/').is_some() {
      // Assume local domain socket
      Ok(ProtAddr::Uds(PathBuf::from(addr)))
    } else {
      // Assume IP socket address
      Ok(ProtAddr::Tcp(addr.to_string()))
    }

    #[cfg(windows)]
    Ok(ProtAddr::Tcp(addr.to_string()))
  }
}

impl fmt::Display for ProtAddr {
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    match self {
      #[cfg(unix)]
      ProtAddr::Uds(sa) => {
        // ToDo: Return error if it's not really a valid Unicode string.
        write!(f, "{}", sa.display())
      }
      ProtAddr::Tcp(sa) => {
        write!(f, "{}", sa)
      }
    }
  }
}

// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :