litrs/byte/
mod.rs
1use core::fmt;
2
3use crate::{
4 Buffer, ParseError,
5 err::{perr, ParseErrorKind::*},
6 escape::unescape,
7};
8
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub struct ByteLit<B: Buffer> {
17 raw: B,
18 value: u8,
19}
20
21impl<B: Buffer> ByteLit<B> {
22 pub fn parse(input: B) -> Result<Self, ParseError> {
25 if input.is_empty() {
26 return Err(perr(None, Empty));
27 }
28 if !input.starts_with("b'") {
29 return Err(perr(None, InvalidByteLiteralStart));
30 }
31
32 Self::parse_impl(input)
33 }
34
35 pub fn value(&self) -> u8 {
37 self.value
38 }
39
40 pub(crate) fn parse_impl(input: B) -> Result<Self, ParseError> {
42 if input.len() == 2 {
43 return Err(perr(None, UnterminatedByteLiteral));
44 }
45 if *input.as_bytes().last().unwrap() != b'\'' {
46 return Err(perr(None, UnterminatedByteLiteral));
47 }
48
49 let inner = &input[2..input.len() - 1];
50 let first = inner.as_bytes().get(0).ok_or(perr(None, EmptyByteLiteral))?;
51 let (c, len) = match first {
52 b'\'' => return Err(perr(2, UnescapedSingleQuote)),
53 b'\n' | b'\t' | b'\r'
54 => return Err(perr(2, UnescapedSpecialWhitespace)),
55
56 b'\\' => unescape::<u8>(inner, 2)?,
57 other if other.is_ascii() => (*other, 1),
58 _ => return Err(perr(2, NonAsciiInByteLiteral)),
59 };
60 let rest = &inner[len..];
61
62 if !rest.is_empty() {
63 return Err(perr(len + 2..input.len() - 1, OverlongByteLiteral));
64 }
65
66 Ok(Self {
67 raw: input,
68 value: c,
69 })
70 }
71}
72
73impl ByteLit<&str> {
74 pub fn to_owned(&self) -> ByteLit<String> {
77 ByteLit {
78 raw: self.raw.to_owned(),
79 value: self.value,
80 }
81 }
82}
83
84impl<B: Buffer> fmt::Display for ByteLit<B> {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 f.pad(&self.raw)
87 }
88}
89
90#[cfg(test)]
91mod tests;