#![forbid(unsafe_code)]
include!(concat!(env!("OUT_DIR"), "/domains_generated.rs"));
#[inline]
pub fn domain_count() -> usize {
DOMAINS.len()
}
pub fn is_disposable_domain(domain: &str) -> bool {
let d = domain.trim().trim_end_matches('.').to_ascii_lowercase();
if d.is_empty() {
return false;
}
DOMAINS.binary_search(&d.as_str()).is_ok()
}
pub fn is_disposable_email(email: &str) -> bool {
match email.rsplit_once('@') {
Some((_, domain)) if !domain.is_empty() => is_disposable_domain(domain),
_ => false,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn list_is_substantial_and_sorted() {
assert!(domain_count() > 50_000, "blocklist looks too small");
assert!(
DOMAINS.windows(2).all(|w| w[0] < w[1]),
"DOMAINS must be sorted + deduped for binary_search"
);
}
#[test]
fn flags_known_disposable() {
for d in ["mailinator.com", "guerrillamail.com", "10minutemail.com"] {
assert!(is_disposable_domain(d), "{d} should be disposable");
}
}
#[test]
fn allows_real_domains() {
for d in ["gmail.com", "spider.cloud", "gottem.dev", "outlook.com"] {
assert!(!is_disposable_domain(d), "{d} should not be disposable");
}
}
#[test]
fn case_and_trailing_dot_insensitive() {
assert!(is_disposable_domain("MAILINATOR.COM"));
assert!(is_disposable_domain("mailinator.com."));
}
#[test]
fn email_form() {
assert!(is_disposable_email("a@mailinator.com"));
assert!(is_disposable_email("weird+tag@guerrillamail.com"));
assert!(!is_disposable_email("jeff@gmail.com"));
assert!(!is_disposable_email("garbage"));
assert!(!is_disposable_email("trailing@"));
}
}