dns_message_parser/
label.rs

1use 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}