dns_message_parser/
label.rs1use std::{
2 convert::TryFrom,
3 fmt::{Display, Formatter, Result as FmtResult},
4 hash::{Hash, Hasher},
5 str::FromStr,
6};
7use thiserror::Error;
8
9pub const LABEL_MAX_LENGTH: usize = 64;
10
11#[derive(Debug, PartialEq, Eq, Error)]
12pub enum LabelError {
13 #[error("Label is too big: {LABEL_MAX_LENGTH} <= {0}")]
14 Length(usize),
15 #[error("Label is empty")]
16 Empty,
17}
18
19#[derive(Debug, Clone, Eq)]
20pub struct Label(pub(super) String);
21
22#[inline]
23fn check_label(label: &str) -> Result<(), LabelError> {
24 let label_length = label.len();
25 if label_length == 0 {
26 Err(LabelError::Empty)
27 } else if label_length < LABEL_MAX_LENGTH {
28 Ok(())
29 } else {
30 Err(LabelError::Length(label_length))
31 }
32}
33
34impl Label {
35 pub fn len(&self) -> usize {
36 self.0.len()
37 }
38}
39
40impl TryFrom<String> for Label {
41 type Error = LabelError;
42
43 fn try_from(label: String) -> Result<Self, <Self as TryFrom<String>>::Error> {
44 check_label(&label)?;
45 Ok(Label(label))
46 }
47}
48
49impl FromStr for Label {
50 type Err = LabelError;
51
52 fn from_str(label: &str) -> Result<Self, <Self as FromStr>::Err> {
53 check_label(label)?;
54 Ok(Label(label.to_owned()))
55 }
56}
57
58impl Display for Label {
59 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
60 write!(f, "{}", self.0)
61 }
62}
63
64impl AsRef<str> for Label {
65 fn as_ref(&self) -> &str {
66 &self.0
67 }
68}
69
70impl PartialEq<&str> for Label {
71 fn eq(&self, other: &&str) -> bool {
72 self.0.to_lowercase() == other.to_lowercase()
73 }
74}
75
76impl PartialEq<Label> for Label {
77 fn eq(&self, other: &Label) -> bool {
78 self.0.to_lowercase() == other.0.to_lowercase()
79 }
80}
81
82impl Hash for Label {
83 fn hash<H: Hasher>(&self, state: &mut H) {
84 self.0.to_lowercase().hash(state);
85 }
86}