1 #[cfg(feature = "std")]
2 use std::{error::Error, fmt};
3 
4 #[cfg(not(feature = "std"))]
5 use core::fmt;
6 
7 use crate::{MacAddr, MacAddr6, MacAddr8};
8 
9 /// An error which can be returned when parsing MAC address.
10 ///
11 /// This error is used as the error type for the `FromStr` implementation
12 /// for [MacAddr6] and [MacAddr8].
13 ///
14 /// [MacAddr6]: ./struct.MacAddr6.html
15 /// [MacAddr8]: ./struct.MacAddr8.html
16 #[derive(Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
17 pub enum ParseError {
18     /// Provided string can't be parsed into the given type,
19     /// because it is either too short or too long.
20     ///
21     /// For example, any trailing symbols will result in the error,
22     /// as in `"12-34-56-78-9A-BC\n"`.
23     ///
24     /// This enum member will contain the provided string length when returned.
25     InvalidLength(usize),
26 
27     /// Invalid character occurred in the provided string.
28     ///
29     /// Allowed characters are `0123456789abcdefABCDEF-:.`.
30     ///
31     /// This enum member will contain the wrong char and it's position when returned.
32     InvalidCharacter(char, usize),
33 }
34 
35 impl fmt::Display for ParseError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result36     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37         match self {
38             ParseError::InvalidLength(len) => f.write_fmt(format_args!("Invalid length of {} characters", len,)),
39             ParseError::InvalidCharacter(chr, pos) => {
40                 f.write_fmt(format_args!("Unexpected character '{}' at position {}", chr, pos,))
41             }
42         }
43     }
44 }
45 
46 #[cfg(feature = "std")]
47 impl Error for ParseError {}
48 
49 #[derive(Debug, Eq, PartialEq)]
50 enum Delimiter {
51     Hyphen,
52     Colon,
53     Dot,
54 }
55 
56 // Heavily based on the Rust' `std/net/parser.rs` sources.
57 #[derive(Debug)]
58 pub struct Parser<'a> {
59     source: &'a [u8],
60     pos: usize,
61     delimiter: Option<Delimiter>,
62 }
63 
64 impl<'a> Parser<'a> {
new(s: &'a str) -> Parser<'a>65     pub fn new(s: &'a str) -> Parser<'a> {
66         Parser {
67             source: s.as_bytes(),
68             pos: 0,
69             delimiter: None,
70         }
71     }
72 
is_eof(&self) -> bool73     fn is_eof(&self) -> bool {
74         self.pos == self.source.len()
75     }
76 
move_next(&mut self)77     fn move_next(&mut self) {
78         if !self.is_eof() {
79             self.pos += 1;
80         }
81     }
82 
peek_char(&mut self) -> Option<char>83     fn peek_char(&mut self) -> Option<char> {
84         if self.is_eof() {
85             None
86         } else {
87             Some(self.source[self.pos] as char)
88         }
89     }
90 
read_char(&mut self) -> Result<char, ParseError>91     fn read_char(&mut self) -> Result<char, ParseError> {
92         if self.is_eof() {
93             Err(ParseError::InvalidLength(self.pos))
94         } else {
95             let r = self.source[self.pos] as char;
96             self.pos += 1;
97             Ok(r)
98         }
99     }
100 
read_digit(&mut self) -> Result<u8, ParseError>101     fn read_digit(&mut self) -> Result<u8, ParseError> {
102         let chr = self.read_char()?;
103 
104         match chr as u8 {
105             byte @ b'0'..=b'9' => Ok(byte - b'0'),
106             byte @ b'a'..=b'f' => Ok(byte - b'a' + 10),
107             byte @ b'A'..=b'F' => Ok(byte - b'A' + 10),
108             _ => Err(ParseError::InvalidCharacter(chr, self.pos)),
109         }
110     }
111 
probe_delimiter(&mut self) -> Result<Option<()>, ParseError>112     fn probe_delimiter(&mut self) -> Result<Option<()>, ParseError> {
113         match self.peek_char() {
114             Some('-') if self.delimiter.is_none() => {
115                 self.delimiter = Some(Delimiter::Hyphen);
116                 Ok(Some(()))
117             }
118             Some('-') if self.delimiter != Some(Delimiter::Hyphen) => Err(ParseError::InvalidCharacter('-', self.pos)),
119             Some('-') => Ok(Some(())),
120 
121             Some(':') if self.delimiter.is_none() => {
122                 self.delimiter = Some(Delimiter::Colon);
123                 Ok(Some(()))
124             }
125             Some(':') if self.delimiter != Some(Delimiter::Colon) => Err(ParseError::InvalidCharacter(':', self.pos)),
126             Some(':') => Ok(Some(())),
127 
128             Some('.') if self.delimiter.is_none() => {
129                 self.delimiter = Some(Delimiter::Dot);
130                 Ok(Some(()))
131             }
132             Some('.') if self.delimiter != Some(Delimiter::Dot) => Err(ParseError::InvalidCharacter('.', self.pos)),
133             Some('.') => Ok(Some(())),
134             _ => Ok(None),
135         }
136     }
137 
read_v6_addr(&mut self) -> Result<MacAddr6, ParseError>138     pub fn read_v6_addr(&mut self) -> Result<MacAddr6, ParseError> {
139         let mut bytes = [0; 6];
140         let mut i = 0;
141 
142         while i < 6 {
143             if self.probe_delimiter()?.is_some() {
144                 self.move_next();
145             }
146 
147             let mut digit = self.read_digit()? * 16;
148             digit += self.read_digit()?;
149 
150             bytes[i] = digit;
151 
152             i += 1;
153         }
154 
155         if self.is_eof() {
156             Ok(MacAddr6::from(bytes))
157         } else {
158             Err(ParseError::InvalidLength(self.source.len()))
159         }
160     }
161 
read_v8_addr(&mut self) -> Result<MacAddr8, ParseError>162     pub fn read_v8_addr(&mut self) -> Result<MacAddr8, ParseError> {
163         let mut bytes = [0; 8];
164         let mut i = 0;
165 
166         while i < 8 {
167             if self.probe_delimiter()?.is_some() {
168                 self.move_next();
169             }
170 
171             let mut digit = self.read_digit()? * 16;
172             digit += self.read_digit()?;
173 
174             bytes[i] = digit;
175 
176             i += 1;
177         }
178 
179         if self.is_eof() {
180             Ok(MacAddr8::from(bytes))
181         } else {
182             Err(ParseError::InvalidLength(self.source.len()))
183         }
184     }
185 
read_addr(&mut self) -> Result<MacAddr, ParseError>186     pub fn read_addr(&mut self) -> Result<MacAddr, ParseError> {
187         match self.read_v6_addr() {
188             Ok(addr) => return Ok(addr.into()),
189             Err(err @ ParseError::InvalidCharacter(..)) => return Err(err),
190             Err(ParseError::InvalidLength(..)) => {}
191         }
192 
193         // Rolling back to the start.
194         self.pos = 0;
195 
196         self.read_v8_addr().map(Into::into)
197     }
198 }
199 
200 #[cfg(test)]
201 mod tests;
202