musli_json/parser/
slice_parser.rs

1use musli::{Buf, Context};
2
3use crate::error::ErrorMessage;
4use crate::parser::{Parser, StringReference, Token};
5
6use lexical::parse_float_options::JSON;
7
8const FORMAT: u128 = lexical::format::STANDARD;
9
10/// An efficient [`Parser`] wrapper around a slice.
11pub(crate) struct SliceParser<'de> {
12    pub(crate) slice: &'de [u8],
13    pub(crate) index: usize,
14}
15
16impl<'de> SliceParser<'de> {
17    /// Construct a new instance around the specified slice.
18    #[inline]
19    pub(crate) fn new(slice: &'de [u8]) -> Self {
20        Self { slice, index: 0 }
21    }
22}
23
24impl<'de> Parser<'de> for SliceParser<'de> {
25    type Mut<'this> = &'this mut SliceParser<'de> where Self: 'this;
26
27    #[inline]
28    fn borrow_mut(&mut self) -> Self::Mut<'_> {
29        self
30    }
31
32    #[inline]
33    fn parse_string<'scratch, C, S>(
34        &mut self,
35        cx: &C,
36        validate: bool,
37        scratch: &'scratch mut S,
38    ) -> Result<StringReference<'de, 'scratch>, C::Error>
39    where
40        C: ?Sized + Context,
41        S: ?Sized + Buf,
42    {
43        let start = cx.mark();
44        let actual = self.peek(cx)?;
45
46        if !matches!(actual, Token::String) {
47            return Err(cx.marked_message(start, format_args!("Expected string, found {actual}")));
48        }
49
50        self.skip(cx, 1)?;
51        let out =
52            crate::parser::string::parse_string_slice_reader(cx, self, validate, start, scratch);
53        out
54    }
55
56    #[inline]
57    fn read_byte<C>(&mut self, cx: &C) -> Result<u8, C::Error>
58    where
59        C: ?Sized + Context,
60    {
61        let mut byte = [0];
62        self.read(cx, &mut byte[..])?;
63        Ok(byte[0])
64    }
65
66    #[inline]
67    fn skip<C>(&mut self, cx: &C, n: usize) -> Result<(), C::Error>
68    where
69        C: ?Sized + Context,
70    {
71        let outcome = self.index.wrapping_add(n);
72
73        if outcome > self.slice.len() || outcome < self.index {
74            return Err(cx.message("Buffer underflow"));
75        }
76
77        self.index = outcome;
78        cx.advance(n);
79        Ok(())
80    }
81
82    #[inline]
83    fn read<C>(&mut self, cx: &C, buf: &mut [u8]) -> Result<(), C::Error>
84    where
85        C: ?Sized + Context,
86    {
87        let outcome = self.index.wrapping_add(buf.len());
88
89        if outcome > self.slice.len() || outcome < self.index {
90            return Err(cx.message("Buffer underflow"));
91        }
92
93        buf.copy_from_slice(&self.slice[self.index..outcome]);
94        self.index = outcome;
95        cx.advance(buf.len());
96        Ok(())
97    }
98
99    #[inline]
100    fn skip_whitespace<C>(&mut self, cx: &C) -> Result<(), C::Error>
101    where
102        C: ?Sized + Context,
103    {
104        while matches!(
105            self.slice.get(self.index),
106            Some(b' ' | b'\n' | b'\t' | b'\r')
107        ) {
108            self.index = self.index.wrapping_add(1);
109            cx.advance(1);
110        }
111
112        Ok(())
113    }
114
115    #[inline]
116    fn pos(&self) -> u32 {
117        self.index as u32
118    }
119
120    #[inline]
121    fn peek_byte<C>(&mut self, _: &C) -> Result<Option<u8>, C::Error>
122    where
123        C: ?Sized + Context,
124    {
125        Ok(self.slice.get(self.index).copied())
126    }
127
128    fn parse_f32<C>(&mut self, cx: &C) -> Result<f32, C::Error>
129    where
130        C: ?Sized + Context,
131    {
132        let (value, read) = match lexical::parse_partial_with_options::<f32, _, FORMAT>(
133            &self.slice[self.index..],
134            &JSON,
135        ) {
136            Ok(out) => out,
137            Err(error) => {
138                return Err(cx.custom(ErrorMessage::ParseFloat(error)));
139            }
140        };
141
142        self.index += read;
143        cx.advance(read);
144        Ok(value)
145    }
146
147    fn parse_f64<C>(&mut self, cx: &C) -> Result<f64, C::Error>
148    where
149        C: ?Sized + Context,
150    {
151        let (value, read) = match lexical::parse_partial_with_options::<f64, _, FORMAT>(
152            &self.slice[self.index..],
153            &JSON,
154        ) {
155            Ok(out) => out,
156            Err(error) => {
157                return Err(cx.custom(ErrorMessage::ParseFloat(error)));
158            }
159        };
160
161        self.index += read;
162        cx.advance(read);
163        Ok(value)
164    }
165}