dbus_message_parser/value/bus/
well_known_bus_name.rs1use crate::value::MAXIMUM_NAME_LENGTH;
2use std::cmp::{Eq, PartialEq};
3use std::convert::{From, TryFrom};
4use std::fmt::{Display, Formatter, Result as FmtResult};
5use thiserror::Error;
6
7enum Input {
8 AlphabeticAndUnderscoreAndHyphen,
10 Digit,
12 Dot,
14}
15
16impl TryFrom<u8> for Input {
17 type Error = WellKnownBusNameError;
18
19 fn try_from(c: u8) -> Result<Self, Self::Error> {
20 if c.is_ascii_alphabetic() || c == b'_' || c == b'-' {
21 Ok(Input::AlphabeticAndUnderscoreAndHyphen)
22 } else if c.is_ascii_digit() {
23 Ok(Input::Digit)
24 } else if c == b'.' {
25 Ok(Input::Dot)
26 } else {
27 Err(WellKnownBusNameError::InvalidChar(c))
28 }
29 }
30}
31
32enum State {
33 Start,
35 FirstElement,
37 Dot,
39 SubsequentElement,
41}
42
43impl State {
44 fn consume(self, i: Input) -> Result<State, WellKnownBusNameError> {
45 match self {
46 State::Start => match i {
47 Input::AlphabeticAndUnderscoreAndHyphen => Ok(State::FirstElement),
48 Input::Digit => Err(WellKnownBusNameError::BeginDigit),
49 Input::Dot => Err(WellKnownBusNameError::BeginDot),
50 },
51 State::FirstElement => match i {
52 Input::AlphabeticAndUnderscoreAndHyphen => Ok(State::FirstElement),
53 Input::Digit => Ok(State::FirstElement),
54 Input::Dot => Ok(State::Dot),
55 },
56 State::Dot => match i {
57 Input::AlphabeticAndUnderscoreAndHyphen => Ok(State::SubsequentElement),
58 Input::Digit => Err(WellKnownBusNameError::ElementBeginDigit),
59 Input::Dot => Err(WellKnownBusNameError::ElementBeginDot),
60 },
61 State::SubsequentElement => match i {
62 Input::AlphabeticAndUnderscoreAndHyphen => Ok(State::SubsequentElement),
63 Input::Digit => Ok(State::SubsequentElement),
64 Input::Dot => Ok(State::Dot),
65 },
66 }
67 }
68}
69
70fn check(well_known_bus_name: &[u8]) -> Result<(), WellKnownBusNameError> {
74 let error_len = well_known_bus_name.len();
75 if MAXIMUM_NAME_LENGTH < error_len {
76 return Err(WellKnownBusNameError::ExceedMaximum(error_len));
77 }
78
79 let mut state = State::Start;
80 for c in well_known_bus_name {
81 let i = Input::try_from(*c)?;
82 state = state.consume(i)?;
83 }
84
85 match state {
86 State::Start => Err(WellKnownBusNameError::Empty),
87 State::FirstElement => Err(WellKnownBusNameError::Elements),
88 State::Dot => Err(WellKnownBusNameError::EndDot),
89 State::SubsequentElement => Ok(()),
90 }
91}
92
93#[derive(Debug, Clone, PartialOrd, PartialEq, Ord, Eq)]
97pub struct WellKnownBusName(String);
98
99#[derive(Debug, PartialEq, Eq, Error)]
101pub enum WellKnownBusNameError {
102 #[error("Well-known bus name must not begin with a digit")]
103 BeginDigit,
104 #[error("Well-known bus name must not begin with a '.'")]
105 BeginDot,
106 #[error("Well-known bus name must not end with '.'")]
107 EndDot,
108 #[error("Well-known bus name element must not begin with a digit")]
109 ElementBeginDigit,
110 #[error("Well-known bus name element must not begin with a '.'")]
111 ElementBeginDot,
112 #[error("Well-known bus name is empty")]
113 Empty,
114 #[error("Well-known bus name have to be composed of 2 or more elements")]
115 Elements,
116 #[error("Well-known bus name must not exceed the maximum length: {MAXIMUM_NAME_LENGTH} < {0}")]
117 ExceedMaximum(usize),
118 #[error("Bus must only contain '[A-Z][a-z][0-9]_-.': {0}")]
119 InvalidChar(u8),
120}
121
122impl From<WellKnownBusName> for String {
123 fn from(well_known_bus_name: WellKnownBusName) -> Self {
124 well_known_bus_name.0
125 }
126}
127
128impl TryFrom<String> for WellKnownBusName {
129 type Error = WellKnownBusNameError;
130
131 fn try_from(well_known_bus_name: String) -> Result<Self, Self::Error> {
132 check(well_known_bus_name.as_bytes())?;
133 Ok(WellKnownBusName(well_known_bus_name))
134 }
135}
136
137impl TryFrom<&str> for WellKnownBusName {
138 type Error = WellKnownBusNameError;
139
140 fn try_from(well_known_bus_name: &str) -> Result<Self, Self::Error> {
141 check(well_known_bus_name.as_bytes())?;
142 Ok(WellKnownBusName(well_known_bus_name.to_owned()))
143 }
144}
145
146impl TryFrom<&[u8]> for WellKnownBusName {
147 type Error = WellKnownBusNameError;
148
149 fn try_from(well_known_bus_name: &[u8]) -> Result<Self, Self::Error> {
150 check(well_known_bus_name)?;
151 let well_known_bus_name = well_known_bus_name.to_vec();
152 unsafe {
155 Ok(WellKnownBusName(String::from_utf8_unchecked(
156 well_known_bus_name,
157 )))
158 }
159 }
160}
161
162impl Display for WellKnownBusName {
163 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
164 write!(f, "{}", self.0)
165 }
166}
167
168impl AsRef<str> for WellKnownBusName {
169 fn as_ref(&self) -> &str {
170 &self.0
171 }
172}
173
174impl PartialEq<str> for WellKnownBusName {
175 fn eq(&self, other: &str) -> bool {
176 self.as_ref() == other
177 }
178}