• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use core::fmt;
2 
3 use crate::{
4     Buffer, ParseError,
5     err::{perr, ParseErrorKind::*},
6     escape::unescape,
7     parse::check_suffix,
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)]
17 pub 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 
24 impl<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.
parse(input: B) -> Result<Self, ParseError>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.
value(&self) -> u840     pub fn value(&self) -> u8 {
41         self.value
42     }
43 
44     /// The optional suffix. Returns `""` if the suffix is empty/does not exist.
suffix(&self) -> &str45     pub fn suffix(&self) -> &str {
46         &(*self.raw)[self.start_suffix..]
47     }
48 
49     /// Returns the raw input that was passed to `parse`.
raw_input(&self) -> &str50     pub fn raw_input(&self) -> &str {
51         &self.raw
52     }
53 
54     /// Returns the raw input that was passed to `parse`, potentially owned.
into_raw_input(self) -> B55     pub fn into_raw_input(self) -> B {
56         self.raw
57     }
58 
59 }
60 
61 impl ByteLit<&str> {
62     /// Makes a copy of the underlying buffer and returns the owned version of
63     /// `Self`.
to_owned(&self) -> ByteLit<String>64     pub fn to_owned(&self) -> ByteLit<String> {
65         ByteLit {
66             raw: self.raw.to_owned(),
67             start_suffix: self.start_suffix,
68             value: self.value,
69         }
70     }
71 }
72 
73 impl<B: Buffer> fmt::Display for ByteLit<B> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result74     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75         f.pad(&self.raw)
76     }
77 }
78 
79 /// Precondition: must start with `b'`.
80 #[inline(never)]
parse_impl(input: &str) -> Result<(u8, usize), ParseError>81 pub(crate) fn parse_impl(input: &str) -> Result<(u8, usize), ParseError> {
82     let input_bytes = input.as_bytes();
83     let first = input_bytes.get(2).ok_or(perr(None, UnterminatedByteLiteral))?;
84     let (c, len) = match first {
85         b'\'' if input_bytes.get(3) == Some(&b'\'') => return Err(perr(2, UnescapedSingleQuote)),
86         b'\'' => return Err(perr(None, EmptyByteLiteral)),
87         b'\n' | b'\t' | b'\r' => return Err(perr(2, UnescapedSpecialWhitespace)),
88         b'\\' => unescape::<u8>(&input[2..], 2)?,
89         other if other.is_ascii() => (*other, 1),
90         _ => return Err(perr(2, NonAsciiInByteLiteral)),
91     };
92 
93     match input[2 + len..].find('\'') {
94         Some(0) => {}
95         Some(_) => return Err(perr(None, OverlongByteLiteral)),
96         None => return Err(perr(None, UnterminatedByteLiteral)),
97     }
98 
99     let start_suffix = 2 + len + 1;
100     let suffix = &input[start_suffix..];
101     check_suffix(suffix).map_err(|kind| perr(start_suffix, kind))?;
102 
103     Ok((c, start_suffix))
104 }
105 
106 #[cfg(test)]
107 mod tests;
108