1use alloc::format;
2use alloc::string::String;
3use alloc::string::ToString;
4use alloc::sync::Arc;
5use alloc::vec::Vec;
6use core::marker::PhantomData;
7
8use deser_core::Text;
9use deser_core::de::{self, Deserialize, DeserializeDriver, Frame, LexicalRules};
10use deser_core::{Atom, Bytes, BytesFormat, ContainerShape, Error, ErrorKind, Event, Source};
11
12use crate::parser::{Dialect, Field, Options, QUOTED, Scan, Scanner, UNESCAPE, unescape};
13use crate::{Escape, Headers, Nulls, Terminator, Trim};
14
15#[derive(Debug, Clone, PartialEq, Eq)]
36pub struct DeserializerConfig {
37 pub(crate) delimiter: u8,
38 pub(crate) quote: Option<u8>,
39 pub(crate) double_quote: bool,
40 pub(crate) escape: Escape,
41 pub(crate) terminator: Terminator,
42 pub(crate) comment: Option<u8>,
43 pub(crate) headers: Headers,
44 pub(crate) trim: Trim,
45 pub(crate) nulls: Nulls,
46 pub(crate) skip_blank_lines: bool,
47 pub(crate) flexible: bool,
48 pub(crate) lenient_quotes: bool,
49 pub(crate) sep_line: bool,
50 pub(crate) max_record_len: usize,
51 pub(crate) bytes: BytesFormat,
52 pub(crate) track_locations: bool,
53}
54
55impl Default for DeserializerConfig {
56 fn default() -> DeserializerConfig {
57 DeserializerConfig::new()
58 }
59}
60
61impl DeserializerConfig {
62 pub const fn new() -> DeserializerConfig {
64 DeserializerConfig {
65 delimiter: b',',
66 quote: Some(b'"'),
67 double_quote: true,
68 escape: Escape::None,
69 terminator: Terminator::Newline,
70 comment: None,
71 headers: Headers::First,
72 trim: Trim::None,
73 nulls: Nulls::None,
74 skip_blank_lines: true,
75 flexible: false,
76 lenient_quotes: false,
77 sep_line: false,
78 max_record_len: 64 * 1024 * 1024,
79 bytes: BytesFormat::BASE64,
80 track_locations: false,
81 }
82 }
83
84 pub const fn tsv() -> DeserializerConfig {
112 DeserializerConfig::new()
113 .delimiter(b'\t')
114 .quote(None)
115 .escape(Escape::Backslash)
116 .nulls(Nulls::Text("\\N"))
117 }
118
119 pub const fn delimiter(mut self, delimiter: u8) -> DeserializerConfig {
124 self.delimiter = delimiter;
125 self
126 }
127
128 pub const fn quote(mut self, quote: Option<u8>) -> DeserializerConfig {
133 self.quote = quote;
134 self
135 }
136
137 pub const fn double_quote(mut self, yes: bool) -> DeserializerConfig {
143 self.double_quote = yes;
144 self
145 }
146
147 pub const fn escape(mut self, escape: Escape) -> DeserializerConfig {
149 self.escape = escape;
150 self
151 }
152
153 pub const fn terminator(mut self, terminator: Terminator) -> DeserializerConfig {
155 self.terminator = terminator;
156 self
157 }
158
159 pub const fn comment(mut self, comment: Option<u8>) -> DeserializerConfig {
164 self.comment = comment;
165 self
166 }
167
168 pub const fn headers(mut self, headers: Headers) -> DeserializerConfig {
174 self.headers = headers;
175 self
176 }
177
178 pub const fn trim(mut self, trim: Trim) -> DeserializerConfig {
183 self.trim = trim;
184 self
185 }
186
187 pub const fn nulls(mut self, nulls: Nulls) -> DeserializerConfig {
193 self.nulls = nulls;
194 self
195 }
196
197 pub const fn skip_blank_lines(mut self, yes: bool) -> DeserializerConfig {
202 self.skip_blank_lines = yes;
203 self
204 }
205
206 pub const fn flexible(mut self, yes: bool) -> DeserializerConfig {
215 self.flexible = yes;
216 self
217 }
218
219 pub const fn lenient_quotes(mut self, yes: bool) -> DeserializerConfig {
227 self.lenient_quotes = yes;
228 self
229 }
230
231 pub const fn sep_line(mut self, yes: bool) -> DeserializerConfig {
246 self.sep_line = yes;
247 self
248 }
249
250 pub const fn max_record_len(mut self, len: usize) -> DeserializerConfig {
258 self.max_record_len = len;
259 self
260 }
261
262 pub const fn bytes(mut self, format: BytesFormat) -> DeserializerConfig {
268 self.bytes = format;
269 self
270 }
271
272 pub const fn track_locations(mut self, yes: bool) -> DeserializerConfig {
279 self.track_locations = yes;
280 self
281 }
282
283 pub fn from_str<'de, T: Deserialize<'de>>(&self, s: &'de str) -> Result<T, Error> {
287 Deserializer::from_str_with_config(s, self).deserialize()
288 }
289
290 pub fn from_slice<'de, T: Deserialize<'de>>(&self, bytes: &'de [u8]) -> Result<T, Error> {
294 Deserializer::from_slice_with_config(bytes, self).deserialize()
295 }
296
297 fn options(&self, header: bool) -> Options {
299 Options {
300 trim: match self.trim {
301 Trim::None => false,
302 Trim::Headers => header,
303 Trim::Fields => !header,
304 Trim::All => true,
305 },
306 skip_blank_lines: self.skip_blank_lines,
307 lenient_quotes: self.lenient_quotes,
308 max_record_len: self.max_record_len,
309 }
310 }
311
312 fn dialect(&self, delimiter: u8) -> Result<Dialect, Error> {
313 Dialect::new(
314 delimiter,
315 self.quote,
316 self.double_quote,
317 self.escape,
318 self.terminator,
319 self.comment,
320 )
321 }
322}
323
324#[derive(Debug, Default)]
329pub(crate) struct StreamState {
330 dialect: Option<Dialect>,
332 scanner: Scanner,
333 names: Option<Vec<String>>,
334 has_names: bool,
336 expected_len: Option<usize>,
338 scratch: Vec<u8>,
340}
341
342impl StreamState {
343 pub(crate) fn with_headers(names: Vec<String>) -> StreamState {
346 StreamState {
347 names: Some(names),
348 has_names: true,
349 ..StreamState::default()
350 }
351 }
352
353 pub(crate) fn headers(&self) -> Option<&[String]> {
355 self.names.as_deref()
356 }
357
358 pub(crate) fn frame(
365 &mut self,
366 config: &DeserializerConfig,
367 input: &[u8],
368 eof: bool,
369 ) -> Result<Frame, Error> {
370 if self.dialect.is_none() {
371 match self.start(config, input, eof)? {
372 Frame::Incomplete { consumed: 0 } if self.dialect.is_some() => {}
373 frame => return Ok(frame),
374 }
375 }
376 let dialect = self.dialect.as_ref().unwrap();
377 let header = !self.has_names;
378 let options = config.options(header);
379 match self.scanner.scan(dialect, input, eof, options)? {
380 Scan::Record { end, consumed } => {
381 if header {
382 self.read_names(input)?;
383 return Ok(Frame::Incomplete { consumed });
384 }
385 if self.names.is_none() && self.expected_len.is_none() {
386 self.expected_len = Some(self.scanner.fields.len());
387 }
388 Ok(Frame::Value {
389 start: 0,
390 end,
391 consumed,
392 })
393 }
394 Scan::Skip { consumed } => Ok(Frame::Incomplete { consumed }),
395 Scan::Incomplete => Ok(Frame::Incomplete { consumed: 0 }),
396 Scan::End => Ok(Frame::End),
397 }
398 }
399
400 fn start(
403 &mut self,
404 config: &DeserializerConfig,
405 input: &[u8],
406 eof: bool,
407 ) -> Result<Frame, Error> {
408 const BOM: &[u8] = b"\xef\xbb\xbf";
409 const SEP: &[u8] = b"sep=";
410 if input.len() < BOM.len() && BOM.starts_with(input) && !eof {
411 return Ok(Frame::Incomplete { consumed: 0 });
412 }
413 if input.starts_with(b"\xff\xfe") || input.starts_with(b"\xfe\xff") {
414 return Err(Error::new(
415 ErrorKind::Unexpected,
416 "input is UTF-16, only UTF-8 is supported",
417 )
418 .with_offset(0));
419 }
420 let bom = if input.starts_with(BOM) { BOM.len() } else { 0 };
421 let rest = &input[bom..];
422 let prefix = rest.len().min(SEP.len());
423 if !config.sep_line || !rest[..prefix].eq_ignore_ascii_case(&SEP[..prefix]) {
424 return self.started(config, config.delimiter, bom);
425 }
426 let end = match rest.iter().position(|&b| b == b'\n' || b == b'\r') {
428 Some(end) if rest[end] == b'\r' && end + 1 == rest.len() && !eof => {
429 return Ok(Frame::Incomplete { consumed: 0 });
430 }
431 Some(end) => end,
432 None if eof => rest.len(),
433 None => return Ok(Frame::Incomplete { consumed: 0 }),
434 };
435 if end != SEP.len() + 1 {
436 return self.started(config, config.delimiter, bom);
437 }
438 let mut consumed = bom + end + 1;
439 if rest.get(end) == Some(&b'\r') && rest.get(end + 1) == Some(&b'\n') {
440 consumed += 1;
441 }
442 self.started(config, rest[SEP.len()], consumed.min(input.len()))
443 }
444
445 fn started(
446 &mut self,
447 config: &DeserializerConfig,
448 delimiter: u8,
449 consumed: usize,
450 ) -> Result<Frame, Error> {
451 self.dialect = Some(config.dialect(delimiter)?);
452 if !self.has_names {
453 match config.headers {
454 Headers::First | Headers::Skip => {}
455 Headers::None => self.has_names = true,
456 Headers::Given(names) => {
457 self.names = Some(names.iter().map(|name| name.to_string()).collect());
458 self.has_names = true;
459 }
460 }
461 }
462 Ok(Frame::Incomplete { consumed })
463 }
464
465 fn read_names(&mut self, record: &[u8]) -> Result<(), Error> {
467 if let Some((offset, msg)) = self.scanner.error {
468 return Err(Error::new(ErrorKind::Unexpected, msg).with_offset(offset));
469 }
470 let dialect = self.dialect.as_ref().unwrap();
471 let mut names = Vec::with_capacity(self.scanner.fields.len());
472 for field in &self.scanner.fields {
473 let text = &record[field.start..field.end];
474 let text = if field.flags & UNESCAPE != 0 {
475 unescape(dialect, text, field.flags & QUOTED != 0, &mut self.scratch);
476 &self.scratch[..]
477 } else {
478 text
479 };
480 match core::str::from_utf8(text) {
481 Ok(name) => names.push(name.to_string()),
482 Err(_) => {
483 return Err(Error::new(ErrorKind::Unexpected, "name is not valid UTF-8")
484 .with_offset(field.span_start));
485 }
486 }
487 }
488 self.names = Some(names);
489 self.has_names = true;
490 Ok(())
491 }
492
493 pub(crate) fn emit_record<'de>(
498 &mut self,
499 config: &DeserializerConfig,
500 record: &'de [u8],
501 base: usize,
502 driver: &mut DeserializeDriver<'_, 'de>,
503 ) -> Result<(), Error> {
504 let StreamState {
505 ref dialect,
506 ref scanner,
507 ref names,
508 expected_len,
509 ref mut scratch,
510 ..
511 } = *self;
512 let self_names_len = names.as_ref().map(Vec::len);
513 let dialect = dialect
514 .as_ref()
515 .expect("records are emitted after the start");
516 if let Some((offset, msg)) = scanner.error {
517 return Err(Error::new(ErrorKind::Unexpected, msg).with_offset(base + offset));
518 }
519 if config.bytes != BytesFormat::BASE64 {
520 config.bytes.set(driver.state_mut());
521 }
522 LexicalRules::LENIENT.set(driver.state_mut());
524 let fields = &scanner.fields[..];
525 let names = match config.headers {
527 Headers::Skip => None,
528 _ => names.as_ref(),
529 };
530 let expected = match (names, self_names_len) {
531 (Some(names), _) => names.len(),
532 (None, Some(len)) => len,
533 (None, None) => expected_len.unwrap_or(fields.len()),
534 };
535 if fields.len() != expected && !config.flexible {
536 return Err(Error::new(
537 ErrorKind::Unexpected,
538 format!(
539 "record has {} field{}, expected {}",
540 fields.len(),
541 if fields.len() == 1 { "" } else { "s" },
542 expected
543 ),
544 )
545 .with_offset(base));
546 }
547
548 let shape = ContainerShape::new().with_len(fields.len());
549 let emitter = FieldEmitter {
550 dialect,
551 nulls: config.nulls,
552 record,
553 record_is_utf8: record.is_ascii() || core::str::from_utf8(record).is_ok(),
556 base,
557 };
558 let end = base + record.len();
561 driver.state_mut().set_input_range(base, base);
562 match names {
563 Some(names) => {
564 driver.emit(Event::MapStart(shape.with_multimap(true)))?;
566 for (index, field) in fields.iter().enumerate() {
567 emitter.set_range(driver, field);
568 match names.get(index) {
569 Some(name) => driver.emit(Atom::Lexical(Text::borrowed(name.as_str())))?,
572 None => driver.emit(Atom::Lexical(Text::owned(index.to_string())))?,
573 }
574 emitter.emit(driver, field, scratch)?;
575 }
576 driver.state_mut().set_input_range(end, end);
577 driver.emit(Event::MapEnd)
578 }
579 None => {
580 driver.emit(Event::SeqStart(shape))?;
581 for field in fields {
582 emitter.emit(driver, field, scratch)?;
583 }
584 driver.state_mut().set_input_range(end, end);
585 driver.emit(Event::SeqEnd)
586 }
587 }
588 }
589}
590
591struct FieldEmitter<'a, 'de> {
593 dialect: &'a Dialect,
594 nulls: Nulls,
595 record: &'de [u8],
596 record_is_utf8: bool,
597 base: usize,
598}
599
600impl<'de> FieldEmitter<'_, 'de> {
601 #[inline]
602 fn set_range(&self, driver: &mut DeserializeDriver<'_, 'de>, field: &Field) {
603 driver
604 .state_mut()
605 .set_input_range(self.base + field.span_start, self.base + field.span_end);
606 }
607
608 #[inline]
609 fn emit(
610 &self,
611 driver: &mut DeserializeDriver<'_, 'de>,
612 field: &Field,
613 scratch: &mut Vec<u8>,
614 ) -> Result<(), Error> {
615 self.set_range(driver, field);
616 let text = &self.record[field.start..field.end];
617 if field.flags & QUOTED == 0 {
618 match self.nulls {
619 Nulls::Empty if text.is_empty() => return driver.emit(Atom::Null),
620 Nulls::Text(null) if text == null.as_bytes() => return driver.emit(Atom::Null),
621 _ => {}
622 }
623 }
624 if field.flags & UNESCAPE != 0 {
625 unescape(self.dialect, text, field.flags & QUOTED != 0, scratch);
626 match core::str::from_utf8(scratch) {
628 Ok(text) => driver.emit(Atom::Lexical(Text::borrowed(text))),
629 Err(_) => driver.emit(Atom::Bytes(Bytes::borrowed(scratch))),
630 }
631 } else if self.record_is_utf8 {
632 let text = unsafe { core::str::from_utf8_unchecked(text) };
635 driver.emit_borrowed(Atom::Lexical(Text::borrowed(text)))
636 } else {
637 match core::str::from_utf8(text) {
638 Ok(text) => driver.emit_borrowed(Atom::Lexical(Text::borrowed(text))),
639 Err(_) => driver.emit_borrowed(Atom::Bytes(Bytes::borrowed(text))),
640 }
641 }
642 }
643}
644
645pub struct Deserializer<'a> {
674 input: &'a [u8],
675 pos: usize,
676 config: DeserializerConfig,
677 state: StreamState,
678 failed: bool,
679 source: Option<Arc<str>>,
681}
682
683impl<'a> Deserializer<'a> {
684 #[allow(clippy::should_implement_trait)]
686 pub fn from_str(input: &'a str) -> Deserializer<'a> {
687 Deserializer::from_slice_with_config(input.as_bytes(), &DeserializerConfig::new())
688 }
689
690 pub fn from_str_with_config(input: &'a str, config: &DeserializerConfig) -> Deserializer<'a> {
692 Deserializer::from_slice_with_config(input.as_bytes(), config)
693 }
694
695 pub fn from_slice(input: &'a [u8]) -> Deserializer<'a> {
699 Deserializer::from_slice_with_config(input, &DeserializerConfig::new())
700 }
701
702 pub fn from_slice_with_config(
705 input: &'a [u8],
706 config: &DeserializerConfig,
707 ) -> Deserializer<'a> {
708 Deserializer {
709 input,
710 pos: 0,
711 config: config.clone(),
712 state: StreamState::default(),
713 failed: false,
714 source: None,
715 }
716 }
717
718 pub fn config(&self) -> &DeserializerConfig {
720 &self.config
721 }
722
723 pub fn headers(&self) -> Option<&[String]> {
727 self.state.headers()
728 }
729
730 pub fn is_end(&self) -> bool {
736 self.failed || self.pos == self.input.len()
737 }
738
739 pub fn deserialize<T: Deserialize<'a>>(&mut self) -> Result<T, Error> {
744 de::Deserializer::deserialize(self)
745 }
746
747 pub fn deserialize_with<T, F>(&mut self, setup: F) -> Result<T, Error>
752 where
753 T: Deserialize<'a>,
754 F: FnOnce(&mut DeserializeDriver<'_, 'a>),
755 {
756 de::Deserializer::deserialize_with(self, setup)
757 }
758
759 pub fn deserialize_record<T: Deserialize<'a>>(&mut self) -> Result<Option<T>, Error> {
781 self.deserialize_record_with(|_| {})
782 }
783
784 pub fn deserialize_record_with<T, F>(&mut self, setup: F) -> Result<Option<T>, Error>
788 where
789 T: Deserialize<'a>,
790 F: FnOnce(&mut DeserializeDriver<'_, 'a>),
791 {
792 let mut out = None;
793 {
794 let mut driver = DeserializeDriver::new(&mut out);
795 setup(&mut driver);
796 if !self.drive_record(&mut driver)? {
797 return Ok(None);
798 }
799 }
800 out.ok_or_else(|| Error::new(ErrorKind::EndOfFile, "empty record"))
801 .map(Some)
802 }
803
804 pub fn records<T: Deserialize<'a>>(&mut self) -> Records<'_, 'a, T> {
809 Records {
810 de: self,
811 _marker: PhantomData,
812 }
813 }
814
815 pub fn drive_record(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<bool, Error> {
819 let rv = self.drive_record_impl(driver);
820 rv.map_err(|err| err.resolve_position(self.input))
821 }
822
823 fn drive_record_impl(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<bool, Error> {
824 let Some((start, end)) = self.next_record()? else {
825 return Ok(false);
826 };
827 let input = self.input;
828 self.set_source(driver);
829 self.state
830 .emit_record(&self.config, &input[start..end], start, driver)?;
831 Ok(true)
832 }
833
834 fn set_source(&mut self, driver: &mut DeserializeDriver<'_, 'a>) {
836 if self.config.track_locations {
837 let input = self.input;
838 let source = self
839 .source
840 .get_or_insert_with(|| String::from_utf8_lossy(input).into());
841 Source::set(driver.state_mut(), source.clone());
842 }
843 }
844
845 fn next_record(&mut self) -> Result<Option<(usize, usize)>, Error> {
847 if self.failed {
848 return Ok(None);
849 }
850 loop {
851 let input = &self.input[self.pos..];
852 let frame = match self.state.frame(&self.config, input, true) {
853 Ok(frame) => frame,
854 Err(err) => {
855 self.failed = true;
857 return Err(err.shift_offset(self.pos));
858 }
859 };
860 match frame {
861 Frame::Value {
862 start,
863 end,
864 consumed,
865 } => {
866 let range = (self.pos + start, self.pos + end);
867 self.pos += consumed;
868 return Ok(Some(range));
869 }
870 Frame::Incomplete { consumed } => self.pos += consumed,
871 Frame::End => return Ok(None),
872 }
873 }
874 }
875
876 pub fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
883 let rv = self.drive_impl(driver);
884 rv.map_err(|err| err.resolve_position(self.input))
885 }
886
887 fn drive_impl(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
888 self.set_source(driver);
889 let input = self.input;
890 driver.emit(Event::seq_start())?;
891 while let Some((start, end)) = self.next_record()? {
892 self.state
893 .emit_record(&self.config, &input[start..end], start, driver)?;
894 }
895 driver.emit(Event::SeqEnd)
896 }
897}
898
899impl<'a> de::Deserializer<'a> for Deserializer<'a> {
900 fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
901 Deserializer::drive(self, driver)
902 }
903}
904
905pub struct Records<'d, 'a, T> {
909 de: &'d mut Deserializer<'a>,
910 _marker: PhantomData<fn() -> T>,
911}
912
913impl<'a, T: Deserialize<'a>> Iterator for Records<'_, 'a, T> {
914 type Item = Result<T, Error>;
915
916 fn next(&mut self) -> Option<Self::Item> {
917 self.de.deserialize_record().transpose()
918 }
919}
920
921trait ShiftOffset {
923 fn shift_offset(self, base: usize) -> Self;
924}
925
926impl ShiftOffset for Error {
927 fn shift_offset(self, base: usize) -> Error {
928 match self.offset() {
929 Some(offset) => self.with_offset(base + offset),
930 None => self,
931 }
932 }
933}