/rust/registry/src/index.crates.io-6f17d22bba15001f/ciborium-ll-0.2.2/src/seg.rs
Line | Count | Source (jump to first uncovered line) |
1 | | use super::*; |
2 | | |
3 | | use ciborium_io::Read; |
4 | | |
5 | | use core::marker::PhantomData; |
6 | | |
7 | | /// A parser for incoming segments |
8 | | pub trait Parser: Default { |
9 | | /// The type of item that is parsed |
10 | | type Item: ?Sized; |
11 | | |
12 | | /// The parsing error that may occur |
13 | | type Error; |
14 | | |
15 | | /// The main parsing function |
16 | | /// |
17 | | /// This function processes the incoming bytes and returns the item. |
18 | | /// |
19 | | /// One important detail that **MUST NOT** be overlooked is that the |
20 | | /// parser may save data from a previous parsing attempt. The number of |
21 | | /// bytes saved is indicated by the `Parser::saved()` function. The saved |
22 | | /// bytes will be copied into the beginning of the `bytes` array before |
23 | | /// processing. Therefore, two requirements should be met. |
24 | | /// |
25 | | /// First, the incoming byte slice should be larger than the saved bytes. |
26 | | /// |
27 | | /// Second, the incoming byte slice should contain new bytes only after |
28 | | /// the saved byte prefix. |
29 | | /// |
30 | | /// If both criteria are met, this allows the parser to prepend its saved |
31 | | /// bytes without any additional allocation. |
32 | | fn parse<'a>(&mut self, bytes: &'a mut [u8]) -> Result<&'a Self::Item, Self::Error>; |
33 | | |
34 | | /// Indicates the number of saved bytes in the parser |
35 | 0 | fn saved(&self) -> usize { |
36 | 0 | 0 |
37 | 0 | } Unexecuted instantiation: <ciborium_ll::seg::Bytes as ciborium_ll::seg::Parser>::saved Unexecuted instantiation: <_ as ciborium_ll::seg::Parser>::saved |
38 | | } |
39 | | |
40 | | /// A bytes parser |
41 | | /// |
42 | | /// No actual processing is performed and the input bytes are directly |
43 | | /// returned. This implies that this parser never saves any bytes internally. |
44 | | #[derive(Default)] |
45 | | pub struct Bytes(()); |
46 | | |
47 | | impl Parser for Bytes { |
48 | | type Item = [u8]; |
49 | | type Error = core::convert::Infallible; |
50 | | |
51 | 0 | fn parse<'a>(&mut self, bytes: &'a mut [u8]) -> Result<&'a [u8], Self::Error> { |
52 | 0 | Ok(bytes) |
53 | 0 | } |
54 | | } |
55 | | |
56 | | /// A text parser |
57 | | /// |
58 | | /// This parser converts the input bytes to a `str`. This parser preserves |
59 | | /// trailing invalid UTF-8 sequences in the case that chunking fell in the |
60 | | /// middle of a valid UTF-8 character. |
61 | | #[derive(Default)] |
62 | | pub struct Text { |
63 | | stored: usize, |
64 | | buffer: [u8; 3], |
65 | | } |
66 | | |
67 | | impl Parser for Text { |
68 | | type Item = str; |
69 | | type Error = core::str::Utf8Error; |
70 | | |
71 | 0 | fn parse<'a>(&mut self, bytes: &'a mut [u8]) -> Result<&'a str, Self::Error> { |
72 | 0 | // If we cannot advance, return nothing. |
73 | 0 | if bytes.len() <= self.stored { |
74 | 0 | return Ok(""); |
75 | 0 | } |
76 | 0 |
|
77 | 0 | // Copy previously invalid data into place. |
78 | 0 | bytes[..self.stored].clone_from_slice(&self.buffer[..self.stored]); |
79 | 0 |
|
80 | 0 | Ok(match core::str::from_utf8(bytes) { |
81 | 0 | Ok(s) => { |
82 | 0 | self.stored = 0; |
83 | 0 | s |
84 | | } |
85 | 0 | Err(e) => { |
86 | 0 | let valid_len = e.valid_up_to(); |
87 | 0 | let invalid_len = bytes.len() - valid_len; |
88 | 0 |
|
89 | 0 | // If the size of the invalid UTF-8 is large enough to hold |
90 | 0 | // all valid UTF-8 characters, we have a syntax error. |
91 | 0 | if invalid_len > self.buffer.len() { |
92 | 0 | return Err(e); |
93 | 0 | } |
94 | 0 |
|
95 | 0 | // Otherwise, store the invalid bytes for the next read cycle. |
96 | 0 | self.buffer[..invalid_len].clone_from_slice(&bytes[valid_len..]); |
97 | 0 | self.stored = invalid_len; |
98 | 0 |
|
99 | 0 | // Decode the valid part of the string. |
100 | 0 | core::str::from_utf8(&bytes[..valid_len]).unwrap() |
101 | | } |
102 | | }) |
103 | 0 | } |
104 | | |
105 | 0 | fn saved(&self) -> usize { |
106 | 0 | self.stored |
107 | 0 | } |
108 | | } |
109 | | |
110 | | /// A CBOR segment |
111 | | /// |
112 | | /// This type represents a single bytes or text segment on the wire. It can be |
113 | | /// read out in parsed chunks based on the size of the input scratch buffer. |
114 | | pub struct Segment<'r, R: Read, P: Parser> { |
115 | | reader: &'r mut Decoder<R>, |
116 | | unread: usize, |
117 | | offset: usize, |
118 | | parser: P, |
119 | | } |
120 | | |
121 | | impl<'r, R: Read, P: Parser> Segment<'r, R, P> { |
122 | | /// Gets the number of unprocessed bytes |
123 | | #[inline] |
124 | 0 | pub fn left(&self) -> usize { |
125 | 0 | self.unread + self.parser.saved() |
126 | 0 | } |
127 | | |
128 | | /// Gets the next parsed chunk within the segment |
129 | | /// |
130 | | /// Returns `Ok(None)` when all chunks have been read. |
131 | | #[inline] |
132 | 0 | pub fn pull<'a>( |
133 | 0 | &mut self, |
134 | 0 | buffer: &'a mut [u8], |
135 | 0 | ) -> Result<Option<&'a P::Item>, Error<R::Error>> { |
136 | | use core::cmp::min; |
137 | | |
138 | 0 | let prev = self.parser.saved(); |
139 | 0 | match self.unread { |
140 | 0 | 0 if prev == 0 => return Ok(None), |
141 | 0 | 0 => return Err(Error::Syntax(self.offset)), |
142 | 0 | _ => (), |
143 | 0 | } |
144 | 0 |
|
145 | 0 | // Determine how many bytes to read. |
146 | 0 | let size = min(buffer.len(), prev + self.unread); |
147 | 0 | let full = &mut buffer[..size]; |
148 | 0 | let next = &mut full[min(size, prev)..]; |
149 | 0 |
|
150 | 0 | // Read additional bytes. |
151 | 0 | self.reader.read_exact(next)?; |
152 | 0 | self.unread -= next.len(); |
153 | 0 |
|
154 | 0 | self.parser |
155 | 0 | .parse(full) |
156 | 0 | .or(Err(Error::Syntax(self.offset))) |
157 | 0 | .map(Some) |
158 | 0 | } Unexecuted instantiation: <ciborium_ll::seg::Segment<&[u8], ciborium_ll::seg::Text>>::pull Unexecuted instantiation: <ciborium_ll::seg::Segment<&[u8], ciborium_ll::seg::Bytes>>::pull Unexecuted instantiation: <ciborium_ll::seg::Segment<_, _>>::pull |
159 | | } |
160 | | |
161 | | /// A sequence of CBOR segments |
162 | | /// |
163 | | /// CBOR allows for bytes or text items to be segmented. This type represents |
164 | | /// the state of that segmented input stream. |
165 | | pub struct Segments<'r, R: Read, P: Parser> { |
166 | | reader: &'r mut Decoder<R>, |
167 | | finish: bool, |
168 | | nested: usize, |
169 | | parser: PhantomData<P>, |
170 | | unwrap: fn(Header) -> Result<Option<usize>, ()>, |
171 | | } |
172 | | |
173 | | impl<'r, R: Read, P: Parser> Segments<'r, R, P> { |
174 | | #[inline] |
175 | 0 | pub(crate) fn new( |
176 | 0 | decoder: &'r mut Decoder<R>, |
177 | 0 | unwrap: fn(Header) -> Result<Option<usize>, ()>, |
178 | 0 | ) -> Self { |
179 | 0 | Self { |
180 | 0 | reader: decoder, |
181 | 0 | finish: false, |
182 | 0 | nested: 0, |
183 | 0 | parser: PhantomData, |
184 | 0 | unwrap, |
185 | 0 | } |
186 | 0 | } Unexecuted instantiation: <ciborium_ll::seg::Segments<&[u8], ciborium_ll::seg::Text>>::new Unexecuted instantiation: <ciborium_ll::seg::Segments<&[u8], ciborium_ll::seg::Bytes>>::new Unexecuted instantiation: <ciborium_ll::seg::Segments<_, _>>::new |
187 | | |
188 | | /// Gets the next segment in the stream |
189 | | /// |
190 | | /// Returns `Ok(None)` at the conclusion of the stream. |
191 | | #[inline] |
192 | 0 | pub fn pull(&mut self) -> Result<Option<Segment<R, P>>, Error<R::Error>> { |
193 | 0 | while !self.finish { |
194 | 0 | let offset = self.reader.offset(); |
195 | 0 | match self.reader.pull()? { |
196 | 0 | Header::Break if self.nested == 1 => return Ok(None), |
197 | 0 | Header::Break if self.nested > 1 => self.nested -= 1, |
198 | 0 | header => match (self.unwrap)(header) { |
199 | 0 | Err(..) => return Err(Error::Syntax(offset)), |
200 | 0 | Ok(None) => self.nested += 1, |
201 | 0 | Ok(Some(len)) => { |
202 | 0 | self.finish = self.nested == 0; |
203 | 0 | return Ok(Some(Segment { |
204 | 0 | reader: self.reader, |
205 | 0 | unread: len, |
206 | 0 | offset, |
207 | 0 | parser: P::default(), |
208 | 0 | })); |
209 | | } |
210 | | }, |
211 | | } |
212 | | } |
213 | | |
214 | 0 | Ok(None) |
215 | 0 | } Unexecuted instantiation: <ciborium_ll::seg::Segments<&[u8], ciborium_ll::seg::Text>>::pull Unexecuted instantiation: <ciborium_ll::seg::Segments<&[u8], ciborium_ll::seg::Bytes>>::pull Unexecuted instantiation: <ciborium_ll::seg::Segments<_, _>>::pull |
216 | | } |