1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#![no_std]
#![cfg_attr(feature = "dynamic", crate_type = "dylib")]
#[cfg(feature = "list")]
extern crate serde;
#[cfg(feature = "list")]
#[macro_use]
extern crate psl_codegen;
#[cfg(feature = "list")]
mod list;
use core::{str, fmt};
#[cfg(feature = "list")]
pub use list::List;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum Type {
Icann,
Private,
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Info {
pub len: usize,
pub typ: Option<Type>,
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Suffix<'a> {
str: &'a str,
typ: Option<Type>,
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Domain<'a> {
str: &'a str,
suf: Suffix<'a>,
}
pub trait Psl {
fn find(&self, domain: &str) -> Info;
fn suffix<'a>(&self, domain: &'a str) -> Option<Suffix<'a>> {
let Info { len, typ } = self.find(domain);
if len == 0 {
return None;
}
let offset = domain.len() - len;
let bytes = domain.as_bytes();
let str = str::from_utf8(&bytes[offset..]).ok()?;
Some(Suffix { str, typ })
}
fn domain<'a>(&self, domain: &'a str) -> Option<Domain<'a>> {
let suf = self.suffix(domain)?;
let mut labels = domain
.trim_right_matches(suf.as_str())
.split('.')
.rev();
labels.next()?;
let offset = domain.len() - (suf.as_str().len() + labels.next()?.len() + 1);
let bytes = domain.as_bytes();
let str = str::from_utf8(&bytes[offset..]).ok()?;
Some(Domain { str, suf })
}
}
impl<'a> Suffix<'a> {
pub fn as_str(&self) -> &str {
&self.str
}
pub fn typ(&self) -> Option<Type> {
self.typ
}
pub fn is_known(&self) -> bool {
self.typ.is_some()
}
}
impl<'a> fmt::Display for Suffix<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.str)
}
}
impl<'a> Domain<'a> {
pub fn as_str(&self) -> &str {
&self.str
}
pub fn suffix(&self) -> Suffix<'a> {
self.suf
}
}
impl<'a> fmt::Display for Domain<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.str)
}
}
impl Default for Type {
fn default() -> Self {
Type::Icann
}
}