serverstat 0.1.4

Get server info from QuakeWorld servers.
Documentation
use anyhow::{Result, anyhow as e};
use std::fmt::Display;

#[cfg(feature = "json")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};

#[derive(Clone, Debug, Default, Ord, PartialOrd, Eq, PartialEq)]
pub struct Hostport {
    pub host: String,
    pub port: u16,
}

impl Hostport {
    pub fn new(host: String, port: u16) -> Self {
        Self { host, port }
    }
}

impl TryFrom<&str> for Hostport {
    type Error = anyhow::Error;

    fn try_from(address: &str) -> Result<Self, Self::Error> {
        let (host, port_str) = address
            .split_once(':')
            .ok_or_else(|| e!("Invalid hostport format, expected host:port"))?;
        Ok(Self {
            host: host.to_string(),
            port: port_str.parse::<u16>()?,
        })
    }
}

impl Display for Hostport {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}:{}", self.host, self.port)
    }
}

#[cfg(feature = "json")]
impl Serialize for Hostport {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(&self.to_string())
    }
}

#[cfg(feature = "json")]
impl<'de> Deserialize<'de> for Hostport {
    fn deserialize<D>(deserializer: D) -> Result<Hostport, D::Error>
    where
        D: Deserializer<'de>,
    {
        let string_value = String::deserialize(deserializer)?;
        Hostport::try_from(string_value.as_str()).map_err(serde::de::Error::custom)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use anyhow::Result;
    use pretty_assertions::assert_eq;

    #[test]
    fn test_try_from_str() -> Result<()> {
        assert_eq!(Hostport::try_from("quake.se:28501")?, {
            Hostport {
                host: "quake.se".to_string(),
                port: 28501,
            }
        });
        Ok(())
    }

    #[test]
    fn test_display() {
        let hostport = Hostport {
            host: "quake.se".to_string(),
            port: 28501,
        };
        assert_eq!(hostport.to_string(), "quake.se:28501");
    }

    #[test]
    fn test_serialize() -> Result<()> {
        let hostport = Hostport {
            host: "quake.se".to_string(),
            port: 28501,
        };
        assert_eq!(
            serde_json::to_string(&hostport)?,
            r#""quake.se:28501""#.to_string(),
        );
        Ok(())
    }

    #[test]
    fn test_deserialize() -> Result<()> {
        assert_eq!(
            serde_json::from_str::<Hostport>(r#""quake.se:28501""#)?,
            Hostport {
                host: "quake.se".to_string(),
                port: 28501,
            }
        );
        Ok(())
    }
}