1#[cfg(feature = "io")]
3use std::io::Read;
4
5use deser_core::Error;
6#[cfg(feature = "io")]
7use deser_core::de::DeserializeOwned;
8use deser_core::de::{self, DeserializeDriver, Frame};
9#[cfg(feature = "io")]
10use deser_core::{Atom, ErrorKind};
11
12use crate::de::{Deserializer, DeserializerConfig};
13
14#[derive(PartialEq, Eq)]
16enum Line {
17 DocumentStart,
19 DocumentEnd,
21 Other,
23 Content,
25}
26
27fn classify(line: &[u8]) -> Line {
29 let line = line.strip_prefix(b"\xef\xbb\xbf").unwrap_or(line);
31 let is_marker = |marker: &[u8]| {
32 line.starts_with(marker) && matches!(line.get(3), None | Some(b' ' | b'\t' | b'\r' | b'\n'))
33 };
34 if is_marker(b"---") {
35 return Line::DocumentStart;
36 }
37 if is_marker(b"...") {
38 return Line::DocumentEnd;
39 }
40 match line
41 .iter()
42 .find(|&&b| !matches!(b, b' ' | b'\t' | b'\r' | b'\n'))
43 {
44 None | Some(b'#') => Line::Other,
45 Some(b'%') if line[0] == b'%' => Line::Other,
46 Some(_) => Line::Content,
47 }
48}
49
50#[derive(Debug, Default)]
52struct StreamState {
53 pos: usize,
55 has_document: bool,
57}
58
59impl StreamState {
60 fn document(&mut self, end: usize) -> Frame {
61 self.pos = 0;
62 self.has_document = false;
63 Frame::Value {
64 start: 0,
65 end,
66 consumed: end,
67 }
68 }
69}
70
71#[derive(Debug)]
98pub struct StreamDeserializer {
99 config: DeserializerConfig,
100 state: StreamState,
101}
102
103impl Default for StreamDeserializer {
104 fn default() -> StreamDeserializer {
105 StreamDeserializer::new()
106 }
107}
108
109impl StreamDeserializer {
110 pub fn new() -> StreamDeserializer {
112 StreamDeserializer::with_config(DeserializerConfig::new())
113 }
114
115 pub fn with_config(config: DeserializerConfig) -> StreamDeserializer {
117 StreamDeserializer {
118 config,
119 state: StreamState::default(),
120 }
121 }
122
123 pub fn config(&self) -> &DeserializerConfig {
125 &self.config
126 }
127}
128
129impl de::StreamDeserializer for StreamDeserializer {
130 fn context(&self) -> deser_core::Context {
131 self.config.context().clone()
132 }
133
134 fn frame(&mut self, input: &[u8], eof: bool) -> Result<Frame, Error> {
135 let state = &mut self.state;
136 loop {
137 let line_end = match input[state.pos..]
140 .iter()
141 .position(|&b| b == b'\n' || b == b'\r')
142 {
143 Some(index) => state.pos + index + 1,
144 None if eof => input.len(),
145 None => return Ok(Frame::Incomplete { consumed: 0 }),
147 };
148 if line_end == state.pos {
149 if state.has_document {
151 return Ok(state.document(input.len()));
152 }
153 if !input.is_empty() {
157 Deserializer::from_slice_with_config(input, self.config.clone()).end()?;
158 }
159 return Ok(Frame::End);
160 }
161 match classify(&input[state.pos..line_end]) {
162 Line::DocumentStart if state.has_document => return Ok(state.document(state.pos)),
163 Line::DocumentStart | Line::Content => state.has_document = true,
164 Line::DocumentEnd if state.has_document => return Ok(state.document(line_end)),
165 Line::DocumentEnd | Line::Other => {}
166 }
167 state.pos = line_end;
168 }
169 }
170
171 fn drive_frame<'de>(
172 &mut self,
173 frame: &'de [u8],
174 driver: &mut DeserializeDriver<'_, 'de>,
175 ) -> Result<(), Error> {
176 let mut de = Deserializer::from_slice_with_config(frame, self.config.without_context());
177 de.drive(driver)?;
178 de.end()
179 }
180
181 fn is_text(&self) -> bool {
182 true
183 }
184}
185
186#[cfg(feature = "io")]
187impl DeserializerConfig {
188 pub fn reader<R: Read>(&self, reader: R) -> deser_core::io::Reader<R, StreamDeserializer> {
194 deser_core::io::Reader::new(reader, StreamDeserializer::with_config(self.clone()))
195 }
196
197 pub fn from_reader<T: DeserializeOwned, R: Read>(&self, reader: R) -> Result<T, Error> {
201 let mut reader = self.reader(reader);
202 let value = match reader.read()? {
203 Some(value) => value,
204 None => {
205 let mut out = None;
207 {
208 let mut driver = DeserializeDriver::new(&mut out);
209 driver.emit(Atom::Null)?;
210 }
211 out.ok_or_else(|| Error::new(ErrorKind::EndOfFile, "empty document"))?
212 }
213 };
214 reader.end()?;
215 Ok(value)
216 }
217}
218
219#[cfg(feature = "io")]
232pub fn from_reader<T: DeserializeOwned, R: Read>(reader: R) -> Result<T, Error> {
233 DeserializerConfig::new().from_reader(reader)
234}