use alloc::format;
use alloc::string::String;
use alloc::string::ToString;
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::marker::PhantomData;
use deser_core::Text;
use deser_core::de::{
self, Deserialize, DeserializeDriver, Frame, LexicalRules, deserialize_value,
};
use deser_core::{Atom, Bytes, ContainerShape, Error, ErrorKind, Event, Source, TrackLocations};
use crate::parser::{Dialect, Field, Options, QUOTED, Scan, Scanner, UNESCAPE, unescape};
use crate::{Escape, Headers, Nulls, Terminator, Trim};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DeserializerConfig {
pub(crate) delimiter: u8,
pub(crate) quote: Option<u8>,
pub(crate) double_quote: bool,
pub(crate) escape: Escape,
pub(crate) terminator: Terminator,
pub(crate) comment: Option<u8>,
pub(crate) headers: Headers,
pub(crate) trim: Trim,
pub(crate) nulls: Nulls,
pub(crate) skip_blank_lines: bool,
pub(crate) flexible: bool,
pub(crate) lenient_quotes: bool,
pub(crate) sep_line: bool,
pub(crate) max_record_len: usize,
context: deser_core::Context,
}
impl Default for DeserializerConfig {
fn default() -> DeserializerConfig {
DeserializerConfig::new()
}
}
impl DeserializerConfig {
pub const fn new() -> DeserializerConfig {
DeserializerConfig {
delimiter: b',',
quote: Some(b'"'),
double_quote: true,
escape: Escape::None,
terminator: Terminator::Newline,
comment: None,
headers: Headers::First,
trim: Trim::None,
nulls: Nulls::None,
skip_blank_lines: true,
flexible: false,
lenient_quotes: false,
sep_line: false,
max_record_len: 64 * 1024 * 1024,
context: deser_core::Context::new(),
}
}
pub const fn builder() -> DeserializerConfigBuilder {
DeserializerConfigBuilder::new()
}
pub const fn into_builder(self) -> DeserializerConfigBuilder {
DeserializerConfigBuilder { value: self }
}
pub fn set_context(&mut self, context: deser_core::Context) {
self.context = context;
}
pub fn context(&self) -> &deser_core::Context {
&self.context
}
pub const fn tsv() -> DeserializerConfig {
let mut config = DeserializerConfig::new();
config.set_delimiter(b'\t');
config.set_quote(None);
config.set_escape(Escape::Backslash);
config.set_nulls(Nulls::Text("\\N"));
config
}
pub const fn set_delimiter(&mut self, delimiter: u8) {
self.delimiter = delimiter;
}
pub const fn set_quote(&mut self, quote: Option<u8>) {
self.quote = quote;
}
pub const fn set_double_quote(&mut self, yes: bool) {
self.double_quote = yes;
}
pub const fn set_escape(&mut self, escape: Escape) {
self.escape = escape;
}
pub const fn set_terminator(&mut self, terminator: Terminator) {
self.terminator = terminator;
}
pub const fn set_comment(&mut self, comment: Option<u8>) {
self.comment = comment;
}
pub const fn set_headers(&mut self, headers: Headers) {
self.headers = headers;
}
pub const fn set_trim(&mut self, trim: Trim) {
self.trim = trim;
}
pub const fn set_nulls(&mut self, nulls: Nulls) {
self.nulls = nulls;
}
pub const fn set_skip_blank_lines(&mut self, yes: bool) {
self.skip_blank_lines = yes;
}
pub const fn set_flexible(&mut self, yes: bool) {
self.flexible = yes;
}
pub const fn set_lenient_quotes(&mut self, yes: bool) {
self.lenient_quotes = yes;
}
pub const fn set_sep_line(&mut self, yes: bool) {
self.sep_line = yes;
}
pub const fn set_max_record_len(&mut self, len: usize) {
self.max_record_len = len;
}
pub fn from_str<'de, T: Deserialize<'de>>(&self, s: &'de str) -> Result<T, Error> {
deserialize_value(|driver| self.drive_str(s, driver))
}
fn drive_str<'de>(
&self,
s: &'de str,
driver: &mut DeserializeDriver<'_, 'de>,
) -> Result<(), Error> {
de::Deserializer::drive(
&mut Deserializer::from_str_with_config(s, self.clone()),
driver,
)
}
pub fn from_slice<'de, T: Deserialize<'de>>(&self, bytes: &'de [u8]) -> Result<T, Error> {
deserialize_value(|driver| self.drive_slice(bytes, driver))
}
fn drive_slice<'de>(
&self,
bytes: &'de [u8],
driver: &mut DeserializeDriver<'_, 'de>,
) -> Result<(), Error> {
de::Deserializer::drive(
&mut Deserializer::from_slice_with_config(bytes, self.clone()),
driver,
)
}
fn options(&self, header: bool) -> Options {
Options {
trim: match self.trim {
Trim::None => false,
Trim::Headers => header,
Trim::Fields => !header,
Trim::All => true,
},
skip_blank_lines: self.skip_blank_lines,
lenient_quotes: self.lenient_quotes,
max_record_len: self.max_record_len,
}
}
fn dialect(&self, delimiter: u8) -> Result<Dialect, Error> {
Dialect::new(
delimiter,
self.quote,
self.double_quote,
self.escape,
self.terminator,
self.comment,
)
}
}
#[derive(Debug, Clone)]
#[must_use]
pub struct DeserializerConfigBuilder {
value: DeserializerConfig,
}
impl DeserializerConfigBuilder {
pub const fn new() -> DeserializerConfigBuilder {
DeserializerConfigBuilder {
value: DeserializerConfig::new(),
}
}
pub const fn delimiter(mut self, delimiter: u8) -> DeserializerConfigBuilder {
self.value.set_delimiter(delimiter);
self
}
pub const fn quote(mut self, quote: Option<u8>) -> DeserializerConfigBuilder {
self.value.set_quote(quote);
self
}
pub const fn double_quote(mut self, yes: bool) -> DeserializerConfigBuilder {
self.value.set_double_quote(yes);
self
}
pub const fn escape(mut self, escape: Escape) -> DeserializerConfigBuilder {
self.value.set_escape(escape);
self
}
pub const fn terminator(mut self, terminator: Terminator) -> DeserializerConfigBuilder {
self.value.set_terminator(terminator);
self
}
pub const fn comment(mut self, comment: Option<u8>) -> DeserializerConfigBuilder {
self.value.set_comment(comment);
self
}
pub const fn headers(mut self, headers: Headers) -> DeserializerConfigBuilder {
self.value.set_headers(headers);
self
}
pub const fn trim(mut self, trim: Trim) -> DeserializerConfigBuilder {
self.value.set_trim(trim);
self
}
pub const fn nulls(mut self, nulls: Nulls) -> DeserializerConfigBuilder {
self.value.set_nulls(nulls);
self
}
pub const fn skip_blank_lines(mut self, yes: bool) -> DeserializerConfigBuilder {
self.value.set_skip_blank_lines(yes);
self
}
pub const fn flexible(mut self, yes: bool) -> DeserializerConfigBuilder {
self.value.set_flexible(yes);
self
}
pub const fn lenient_quotes(mut self, yes: bool) -> DeserializerConfigBuilder {
self.value.set_lenient_quotes(yes);
self
}
pub const fn sep_line(mut self, yes: bool) -> DeserializerConfigBuilder {
self.value.set_sep_line(yes);
self
}
pub const fn max_record_len(mut self, len: usize) -> DeserializerConfigBuilder {
self.value.set_max_record_len(len);
self
}
pub fn context(mut self, context: deser_core::Context) -> DeserializerConfigBuilder {
self.value.set_context(context);
self
}
pub const fn build(self) -> DeserializerConfig {
let value = unsafe { core::ptr::read(&self.value) };
core::mem::forget(self);
value
}
}
impl Default for DeserializerConfigBuilder {
fn default() -> DeserializerConfigBuilder {
DeserializerConfigBuilder::new()
}
}
#[derive(Debug, Default)]
pub(crate) struct StreamState {
dialect: Option<Dialect>,
scanner: Scanner,
names: Option<Vec<String>>,
has_names: bool,
expected_len: Option<usize>,
scratch: Vec<u8>,
}
impl StreamState {
pub(crate) fn with_headers(names: Vec<String>) -> StreamState {
StreamState {
names: Some(names),
has_names: true,
..StreamState::default()
}
}
pub(crate) fn headers(&self) -> Option<&[String]> {
self.names.as_deref()
}
pub(crate) fn frame(
&mut self,
config: &DeserializerConfig,
input: &[u8],
eof: bool,
) -> Result<Frame, Error> {
if self.dialect.is_none() {
match self.start(config, input, eof)? {
Frame::Incomplete { consumed: 0 } if self.dialect.is_some() => {}
frame => return Ok(frame),
}
}
let dialect = self.dialect.as_ref().unwrap();
let header = !self.has_names;
let options = config.options(header);
match self.scanner.scan(dialect, input, eof, options)? {
Scan::Record { end, consumed } => {
if header {
self.read_names(input)?;
return Ok(Frame::Incomplete { consumed });
}
if self.names.is_none() && self.expected_len.is_none() {
self.expected_len = Some(self.scanner.fields.len());
}
Ok(Frame::Value {
start: 0,
end,
consumed,
})
}
Scan::Skip { consumed } => Ok(Frame::Incomplete { consumed }),
Scan::Incomplete => Ok(Frame::Incomplete { consumed: 0 }),
Scan::End => Ok(Frame::End),
}
}
fn start(
&mut self,
config: &DeserializerConfig,
input: &[u8],
eof: bool,
) -> Result<Frame, Error> {
const BOM: &[u8] = b"\xef\xbb\xbf";
const SEP: &[u8] = b"sep=";
if input.len() < BOM.len() && BOM.starts_with(input) && !eof {
return Ok(Frame::Incomplete { consumed: 0 });
}
if input.starts_with(b"\xff\xfe") || input.starts_with(b"\xfe\xff") {
return Err(Error::with_offset(
ErrorKind::Syntax,
"input is UTF-16, only UTF-8 is supported",
0,
));
}
let bom = if input.starts_with(BOM) { BOM.len() } else { 0 };
let rest = &input[bom..];
let prefix = rest.len().min(SEP.len());
if !config.sep_line || !rest[..prefix].eq_ignore_ascii_case(&SEP[..prefix]) {
return self.started(config, config.delimiter, bom);
}
let end = match rest.iter().position(|&b| b == b'\n' || b == b'\r') {
Some(end) if rest[end] == b'\r' && end + 1 == rest.len() && !eof => {
return Ok(Frame::Incomplete { consumed: 0 });
}
Some(end) => end,
None if eof => rest.len(),
None => return Ok(Frame::Incomplete { consumed: 0 }),
};
if end != SEP.len() + 1 {
return self.started(config, config.delimiter, bom);
}
let mut consumed = bom + end + 1;
if rest.get(end) == Some(&b'\r') && rest.get(end + 1) == Some(&b'\n') {
consumed += 1;
}
self.started(config, rest[SEP.len()], consumed.min(input.len()))
}
fn started(
&mut self,
config: &DeserializerConfig,
delimiter: u8,
consumed: usize,
) -> Result<Frame, Error> {
self.dialect = Some(config.dialect(delimiter)?);
if !self.has_names {
match config.headers {
Headers::First | Headers::Skip => {}
Headers::None => self.has_names = true,
Headers::Given(names) => {
self.names = Some(names.iter().map(|name| name.to_string()).collect());
self.has_names = true;
}
}
}
Ok(Frame::Incomplete { consumed })
}
fn read_names(&mut self, record: &[u8]) -> Result<(), Error> {
if let Some((offset, msg)) = self.scanner.error {
return Err(Error::with_offset(ErrorKind::Syntax, msg, offset));
}
let dialect = self.dialect.as_ref().unwrap();
let mut names = Vec::with_capacity(self.scanner.fields.len());
for field in &self.scanner.fields {
let text = &record[field.start..field.end];
let text = if field.flags & UNESCAPE != 0 {
unescape(dialect, text, field.flags & QUOTED != 0, &mut self.scratch);
&self.scratch[..]
} else {
text
};
match core::str::from_utf8(text) {
Ok(name) => names.push(name.to_string()),
Err(_) => {
return Err(Error::with_offset(
ErrorKind::Syntax,
"name is not valid UTF-8",
field.span_start,
));
}
}
}
self.names = Some(names);
self.has_names = true;
Ok(())
}
pub(crate) fn emit_record<'de>(
&mut self,
config: &DeserializerConfig,
record: &'de [u8],
base: usize,
utf8: bool,
driver: &mut DeserializeDriver<'_, 'de>,
) -> Result<(), Error> {
let StreamState {
ref dialect,
ref scanner,
ref names,
expected_len,
ref mut scratch,
..
} = *self;
let self_names_len = names.as_ref().map(Vec::len);
let dialect = dialect
.as_ref()
.expect("records are emitted after the start");
if let Some((offset, msg)) = scanner.error {
return Err(Error::with_offset(ErrorKind::Syntax, msg, base + offset));
}
LexicalRules::LENIENT.set_default(driver.state_mut());
let fields = &scanner.fields[..];
let names = match config.headers {
Headers::Skip => None,
_ => names.as_ref(),
};
let expected = match (names, self_names_len) {
(Some(names), _) => names.len(),
(None, Some(len)) => len,
(None, None) => expected_len.unwrap_or(fields.len()),
};
if fields.len() != expected && !config.flexible {
return Err(Error::with_offset(
ErrorKind::Syntax,
format!(
"record has {} field{}, expected {}",
fields.len(),
if fields.len() == 1 { "" } else { "s" },
expected
),
base,
));
}
let mut shape = ContainerShape::with_len(fields.len());
let emitter = FieldEmitter {
dialect,
nulls: config.nulls,
record,
record_is_utf8: utf8 || record.is_ascii() || core::str::from_utf8(record).is_ok(),
base,
};
let end = base + record.len();
driver.state_mut().set_input_range(base, base);
match names {
Some(names) => {
shape.set_multimap(true);
driver.emit(Event::MapStart(shape))?;
for (index, field) in fields.iter().enumerate() {
emitter.set_range(driver, field);
match names.get(index) {
Some(name) => driver.emit(Atom::Lexical(Text::borrowed(name.as_str())))?,
None => driver.emit(Atom::Lexical(Text::owned(index.to_string())))?,
}
emitter.emit(driver, field, scratch)?;
}
driver.state_mut().set_input_range(end, end);
driver.emit(Event::MapEnd)
}
None => {
driver.emit(Event::SeqStart(shape))?;
for field in fields {
emitter.emit(driver, field, scratch)?;
}
driver.state_mut().set_input_range(end, end);
driver.emit(Event::SeqEnd)
}
}
}
}
struct FieldEmitter<'a, 'de> {
dialect: &'a Dialect,
nulls: Nulls,
record: &'de [u8],
record_is_utf8: bool,
base: usize,
}
impl<'de> FieldEmitter<'_, 'de> {
#[inline]
fn set_range(&self, driver: &mut DeserializeDriver<'_, 'de>, field: &Field) {
driver
.state_mut()
.set_input_range(self.base + field.span_start, self.base + field.span_end);
}
#[inline]
fn emit(
&self,
driver: &mut DeserializeDriver<'_, 'de>,
field: &Field,
scratch: &mut Vec<u8>,
) -> Result<(), Error> {
self.set_range(driver, field);
let text = &self.record[field.start..field.end];
if field.flags & QUOTED == 0 {
match self.nulls {
Nulls::Empty if text.is_empty() => return driver.emit(Atom::Null),
Nulls::Text(null) if text == null.as_bytes() => return driver.emit(Atom::Null),
_ => {}
}
}
if field.flags & UNESCAPE != 0 {
unescape(self.dialect, text, field.flags & QUOTED != 0, scratch);
match core::str::from_utf8(scratch) {
Ok(text) => driver.emit(Atom::Lexical(Text::borrowed(text))),
Err(_) => driver.emit(Atom::Bytes(Bytes::borrowed(scratch))),
}
} else if self.record_is_utf8 {
let text = unsafe { core::str::from_utf8_unchecked(text) };
driver.emit_borrowed(Atom::Lexical(Text::borrowed(text)))
} else {
match core::str::from_utf8(text) {
Ok(text) => driver.emit_borrowed(Atom::Lexical(Text::borrowed(text))),
Err(_) => driver.emit_borrowed(Atom::Bytes(Bytes::borrowed(text))),
}
}
}
}
pub struct Deserializer<'a> {
input: &'a [u8],
utf8: bool,
pos: usize,
config: DeserializerConfig,
state: StreamState,
failed: bool,
source: Option<Arc<str>>,
}
impl<'a> Deserializer<'a> {
#[allow(clippy::should_implement_trait)]
pub fn from_str(input: &'a str) -> Deserializer<'a> {
Deserializer::from_str_with_config(input, DeserializerConfig::new())
}
pub fn from_str_with_config(input: &'a str, config: DeserializerConfig) -> Deserializer<'a> {
Deserializer::new(input.as_bytes(), true, config)
}
pub fn from_slice(input: &'a [u8]) -> Deserializer<'a> {
Deserializer::from_slice_with_config(input, DeserializerConfig::new())
}
pub fn from_slice_with_config(input: &'a [u8], config: DeserializerConfig) -> Deserializer<'a> {
Deserializer::new(input, false, config)
}
fn new(input: &'a [u8], utf8: bool, config: DeserializerConfig) -> Deserializer<'a> {
Deserializer {
input,
utf8,
pos: 0,
config,
state: StreamState::default(),
failed: false,
source: None,
}
}
pub fn config(&self) -> &DeserializerConfig {
&self.config
}
pub fn headers(&self) -> Option<&[String]> {
self.state.headers()
}
pub fn is_end(&self) -> bool {
self.failed || self.pos == self.input.len()
}
pub fn deserialize<T: Deserialize<'a>>(&mut self) -> Result<T, Error> {
de::Deserializer::deserialize(self)
}
pub fn deserialize_with<T, F>(&mut self, setup: F) -> Result<T, Error>
where
T: Deserialize<'a>,
F: FnOnce(&mut DeserializeDriver<'_, 'a>),
{
de::Deserializer::deserialize_with(self, setup)
}
pub fn deserialize_record<T: Deserialize<'a>>(&mut self) -> Result<Option<T>, Error> {
self.deserialize_record_with(|_| {})
}
pub fn deserialize_record_with<T, F>(&mut self, setup: F) -> Result<Option<T>, Error>
where
T: Deserialize<'a>,
F: FnOnce(&mut DeserializeDriver<'_, 'a>),
{
let mut out = None;
{
let mut driver = DeserializeDriver::new(&mut out);
setup(&mut driver);
if !self.drive_record(&mut driver)? {
return Ok(None);
}
}
out.ok_or_else(|| Error::new(ErrorKind::EndOfFile, "empty record"))
.map(Some)
}
pub fn records<T: Deserialize<'a>>(&mut self) -> Records<'_, 'a, T> {
Records {
de: self,
_marker: PhantomData,
}
}
pub fn drive_record(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<bool, Error> {
let rv = self.drive_record_impl(driver);
rv.map_err(|mut err| {
err.resolve_position(self.input);
err
})
}
fn drive_record_impl(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<bool, Error> {
let Some((start, end)) = self.next_record()? else {
return Ok(false);
};
let input = self.input;
self.set_source(driver);
self.state
.emit_record(&self.config, &input[start..end], start, self.utf8, driver)?;
Ok(true)
}
fn set_source(&mut self, driver: &mut DeserializeDriver<'_, 'a>) {
if TrackLocations::of(driver.state()) {
let input = self.input;
let source = self
.source
.get_or_insert_with(|| String::from_utf8_lossy(input).into());
Source(source.clone()).set(driver.state_mut());
}
}
fn next_record(&mut self) -> Result<Option<(usize, usize)>, Error> {
if self.failed {
return Ok(None);
}
loop {
let input = &self.input[self.pos..];
let frame = match self.state.frame(&self.config, input, true) {
Ok(frame) => frame,
Err(err) => {
self.failed = true;
return Err(err.shift_offset(self.pos));
}
};
match frame {
Frame::Value {
start,
end,
consumed,
} => {
let range = (self.pos + start, self.pos + end);
self.pos += consumed;
return Ok(Some(range));
}
Frame::Incomplete { consumed } => self.pos += consumed,
Frame::End => return Ok(None),
}
}
}
pub fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
let rv = self.drive_impl(driver);
rv.map_err(|mut err| {
err.resolve_position(self.input);
err
})
}
fn drive_impl(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
self.set_source(driver);
let input = self.input;
let mut next = self.next_record()?;
let shape = match next {
Some((start, _)) => {
let mut shape = ContainerShape::new();
shape.set_len_hint((input.len() - start) / (self.pos - start).max(1));
shape
}
None => ContainerShape::new(),
};
driver.emit(Event::SeqStart(shape))?;
while let Some((start, end)) = next {
self.state
.emit_record(&self.config, &input[start..end], start, self.utf8, driver)?;
next = self.next_record()?;
}
driver.emit(Event::SeqEnd)
}
}
impl<'a> de::Deserializer<'a> for Deserializer<'a> {
fn drive(&mut self, driver: &mut DeserializeDriver<'_, 'a>) -> Result<(), Error> {
if !self.config.context.is_empty() {
driver.set_default_context(self.config.context.clone());
}
Deserializer::drive(self, driver)
}
}
pub struct Records<'d, 'a, T> {
de: &'d mut Deserializer<'a>,
_marker: PhantomData<fn() -> T>,
}
impl<'a, T: Deserialize<'a>> Iterator for Records<'_, 'a, T> {
type Item = Result<T, Error>;
fn next(&mut self) -> Option<Self::Item> {
self.de.deserialize_record().transpose()
}
}
trait ShiftOffset {
fn shift_offset(self, base: usize) -> Self;
}
impl ShiftOffset for Error {
fn shift_offset(mut self, base: usize) -> Error {
if let Some(offset) = self.offset() {
self.set_offset(base + offset);
}
self
}
}