litrs/byte/
mod.rs

1use core::fmt;
2
3use crate::{
4    err::{perr, ParseErrorKind::*},
5    escape::unescape,
6    parse::check_suffix,
7    Buffer, ParseError,
8};
9
10
11/// A (single) byte literal, e.g. `b'k'` or `b'!'`.
12///
13/// See [the reference][ref] for more information.
14///
15/// [ref]: https://doc.rust-lang.org/reference/tokens.html#byte-literals
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub struct ByteLit<B: Buffer> {
18    raw: B,
19    /// Start index of the suffix or `raw.len()` if there is no suffix.
20    start_suffix: usize,
21    value: u8,
22}
23
24impl<B: Buffer> ByteLit<B> {
25    /// Parses the input as a byte literal. Returns an error if the input is
26    /// invalid or represents a different kind of literal.
27    pub fn parse(input: B) -> Result<Self, ParseError> {
28        if input.is_empty() {
29            return Err(perr(None, Empty));
30        }
31        if !input.starts_with("b'") {
32            return Err(perr(None, InvalidByteLiteralStart));
33        }
34
35        let (value, start_suffix) = parse_impl(&input)?;
36        Ok(Self { raw: input, value, start_suffix })
37    }
38
39    /// Returns the byte value that this literal represents.
40    pub fn value(&self) -> u8 {
41        self.value
42    }
43
44    /// The optional suffix. Returns `""` if the suffix is empty/does not exist.
45    pub fn suffix(&self) -> &str {
46        &(*self.raw)[self.start_suffix..]
47    }
48
49    /// Returns the raw input that was passed to `parse`.
50    pub fn raw_input(&self) -> &str {
51        &self.raw
52    }
53
54    /// Returns the raw input that was passed to `parse`, potentially owned.
55    pub fn into_raw_input(self) -> B {
56        self.raw
57    }
58}
59
60impl ByteLit<&str> {
61    /// Makes a copy of the underlying buffer and returns the owned version of
62    /// `Self`.
63    pub fn to_owned(&self) -> ByteLit<String> {
64        ByteLit {
65            raw: self.raw.to_owned(),
66            start_suffix: self.start_suffix,
67            value: self.value,
68        }
69    }
70}
71
72impl<B: Buffer> fmt::Display for ByteLit<B> {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        f.pad(&self.raw)
75    }
76}
77
78/// Precondition: must start with `b'`.
79#[inline(never)]
80pub(crate) fn parse_impl(input: &str) -> Result<(u8, usize), ParseError> {
81    let input_bytes = input.as_bytes();
82    let first = input_bytes
83        .get(2)
84        .ok_or(perr(None, UnterminatedByteLiteral))?;
85    let (c, len) = match first {
86        b'\'' if input_bytes.get(3) == Some(&b'\'') => return Err(perr(2, UnescapedSingleQuote)),
87        b'\'' => return Err(perr(None, EmptyByteLiteral)),
88        b'\n' | b'\t' | b'\r' => return Err(perr(2, UnescapedSpecialWhitespace)),
89        b'\\' => {
90            let (v, len) = unescape(&input[2..], false, true, true).map_err(|e| e.offset_span(2))?;
91            (v.unwrap_byte(), len)
92        }
93        other if other.is_ascii() => (*other, 1),
94        _ => return Err(perr(2, NonAsciiInByteLiteral)),
95    };
96
97    match input[2 + len..].find('\'') {
98        Some(0) => {}
99        Some(_) => return Err(perr(None, OverlongByteLiteral)),
100        None => return Err(perr(None, UnterminatedByteLiteral)),
101    }
102
103    let start_suffix = 2 + len + 1;
104    let suffix = &input[start_suffix..];
105    check_suffix(suffix).map_err(|kind| perr(start_suffix, kind))?;
106
107    Ok((c, start_suffix))
108}
109
110#[cfg(test)]
111mod tests;