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