litrs/byte/
mod.rs

1use core::fmt;
2
3use crate::{
4    Buffer, ParseError,
5    err::{perr, ParseErrorKind::*},
6    escape::unescape,
7};
8
9
10/// A (single) byte literal, e.g. `b'k'` or `b'!'`.
11///
12/// See [the reference][ref] for more information.
13///
14/// [ref]: https://doc.rust-lang.org/reference/tokens.html#byte-literals
15#[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    /// Parses the input as a byte literal. Returns an error if the input is
23    /// invalid or represents a different kind of literal.
24    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    /// Returns the byte value that this literal represents.
36    pub fn value(&self) -> u8 {
37        self.value
38    }
39
40    /// Precondition: must start with `b'`.
41    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    /// Makes a copy of the underlying buffer and returns the owned version of
75    /// `Self`.
76    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;