use std::fmt;
use std::sync::Arc;
use crate::transport::{Query, RawResponse};
mod memory;
mod null;
pub use memory::MemoryCache;
pub use null::NullCache;
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct CacheKey {
pub endpoint: String,
pub name: String,
}
impl CacheKey {
pub fn new(endpoint: impl Into<String>, name: impl Into<String>) -> Self {
CacheKey {
endpoint: endpoint.into(),
name: name.into(),
}
}
pub fn of(query: &Query) -> Self {
CacheKey::new(query.endpoint.address(), query.wire_name.clone())
}
}
impl fmt::Display for CacheKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}|{}", self.endpoint, self.name)
}
}
pub trait ResponseCache: fmt::Debug + Send + Sync {
fn get(&self, key: &CacheKey) -> Option<RawResponse>;
fn put(&self, key: CacheKey, response: RawResponse);
fn clear(&self);
fn len(&self) -> Option<usize> {
None
}
fn is_empty(&self) -> Option<bool> {
self.len().map(|count| count == 0)
}
}
impl<T: ResponseCache + ?Sized> ResponseCache for Arc<T> {
fn get(&self, key: &CacheKey) -> Option<RawResponse> {
(**self).get(key)
}
fn put(&self, key: CacheKey, response: RawResponse) {
(**self).put(key, response)
}
fn clear(&self) {
(**self).clear()
}
fn len(&self) -> Option<usize> {
(**self).len()
}
fn is_empty(&self) -> Option<bool> {
(**self).is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::domain::Tld;
use crate::registry::Endpoint;
#[test]
fn a_key_distinguishes_endpoints() {
let registry = CacheKey::new("whois.verisign-grs.com", "example.com");
let registrar = CacheKey::new("whois.registrar.example", "example.com");
assert_ne!(registry, registrar);
}
#[test]
fn a_key_is_derived_from_the_query() {
let query = Query::new(
Endpoint::whois("whois.nic.uk"),
"example.co.uk",
Tld::parse("co.uk").unwrap(),
);
let key = CacheKey::of(&query);
assert_eq!(key.endpoint, "whois.nic.uk");
assert_eq!(key.name, "example.co.uk");
assert_eq!(key.to_string(), "whois.nic.uk|example.co.uk");
}
}