use std::fmt;
use std::io;
use std::net::{SocketAddr, ToSocketAddrs};
use std::vec::IntoIter;
use crate::errors::{Error, Result};
use crate::net::parser::Parser;
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct Host {
pub name: String,
pub tls_name: Option<String>,
pub port: u16,
}
impl Host {
pub fn new(name: &str, port: u16) -> Self {
Host {
name: name.to_string(),
tls_name: None,
port,
}
}
pub fn new_tls(name: &str, tls_name: &str, port: u16) -> Self {
let tls_name = match tls_name.trim().len() {
0 => None,
_ => Some(tls_name.into()),
};
Host {
name: name.to_string(),
tls_name,
port,
}
}
pub fn address(&self) -> String {
format!("{}:{}", self.name, self.port)
}
}
impl ToSocketAddrs for Host {
type Iter = IntoIter<SocketAddr>;
fn to_socket_addrs(&self) -> io::Result<IntoIter<SocketAddr>> {
(self.name.as_str(), self.port).to_socket_addrs()
}
}
impl fmt::Display for Host {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}:{}", self.name, self.port)
}
}
pub trait ToHosts {
fn to_hosts(&self) -> Result<Vec<Host>>;
}
impl ToHosts for Vec<Host> {
fn to_hosts(&self) -> Result<Vec<Host>> {
Ok(self.clone())
}
}
impl ToHosts for String {
fn to_hosts(&self) -> Result<Vec<Host>> {
let parser = Parser::new(self, 3000);
parser.read_hosts().map_err(|e| {
e.wrap(Error::InvalidArgument(format!(
"Invalid hosts list: '{self}'"
)))
})
}
}
impl ToHosts for &str {
fn to_hosts(&self) -> Result<Vec<Host>> {
(*self).to_string().to_hosts()
}
}
#[cfg(test)]
mod tests {
use super::{Host, ToHosts};
#[test]
fn to_hosts() {
assert_eq!(
vec![Host::new("foo", 3000)],
String::from("foo").to_hosts().unwrap()
);
assert_eq!(vec![Host::new("foo", 3000)], "foo".to_hosts().unwrap());
assert_eq!(vec![Host::new("foo", 1234)], "foo:1234".to_hosts().unwrap());
assert_eq!(
vec![Host::new("foo", 1234), Host::new("bar", 1234)],
"foo:1234,bar:1234".to_hosts().unwrap()
);
}
}