monovm-whois-rust 1.0.0

Domain WHOIS and RDAP lookups with availability detection, structured record parsing, referral chasing, caching and rate limiting.
Documentation
//! Value objects: the vocabulary the rest of the crate is written in.
//!
//! Everything here is immutable, validated at construction, and free of I/O.
//! A [`DomainName`] that exists is queryable; a [`Tld`] that exists is a
//! normalised suffix. Later layers never re-validate, and never have to decide
//! which spelling of a name they are holding.

mod availability;
pub(crate) mod idn;
mod name;
mod tld;

pub use availability::Availability;
pub use name::{DomainName, SuffixSplit};
pub use tld::Tld;

use serde::de::{self, Deserializer};
use serde::ser::Serializer;
use serde::{Deserialize, Serialize};

// Both value objects serialise as their punycode string rather than as a struct,
// so a JSON document produced by this crate stays readable and a hand-written
// one stays writable.

impl Serialize for DomainName {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_str(self.as_ascii())
    }
}

impl<'de> Deserialize<'de> for DomainName {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let raw = String::deserialize(deserializer)?;
        DomainName::parse(&raw).map_err(de::Error::custom)
    }
}

impl Serialize for Tld {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_str(self.ascii())
    }
}

impl<'de> Deserialize<'de> for Tld {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let raw = String::deserialize(deserializer)?;
        Tld::parse(&raw).map_err(de::Error::custom)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn domain_name_round_trips_through_json() {
        let name = DomainName::parse("münchen.de").unwrap();
        let json = serde_json::to_string(&name).unwrap();
        assert_eq!(json, "\"xn--mnchen-3ya.de\"");
        assert_eq!(serde_json::from_str::<DomainName>(&json).unwrap(), name);
    }

    #[test]
    fn tld_round_trips_through_json() {
        let tld = Tld::parse(".CO.UK").unwrap();
        let json = serde_json::to_string(&tld).unwrap();
        assert_eq!(json, "\"co.uk\"");
        assert_eq!(serde_json::from_str::<Tld>(&json).unwrap(), tld);
    }

    #[test]
    fn deserialising_junk_fails_rather_than_panicking() {
        assert!(serde_json::from_str::<DomainName>("\"localhost\"").is_err());
        assert!(serde_json::from_str::<Tld>("\"\"").is_err());
    }
}