use core::marker::PhantomData;
#[cfg(feature = "alloc")]
use crate::alloc::Global;
#[cfg(feature = "alloc")]
use crate::mode::Text;
use crate::{Allocator, Context, Decode};
use super::de::{DocState, Headers, RecordDecoder};
use super::encoding::Config;
#[cfg(feature = "alloc")]
use super::error::Error;
use super::parser::{self, Parser, SliceParser};
#[cfg(feature = "alloc")]
pub struct Reader<'de, M = Text, A = Global>
where
A: Allocator,
{
cfg: Config,
parser: SliceParser<'de>,
doc: DocState<A>,
_marker: PhantomData<M>,
}
#[cfg(not(feature = "alloc"))]
pub struct Reader<'de, M, A>
where
A: Allocator,
{
cfg: Config,
parser: SliceParser<'de>,
doc: DocState<A>,
_marker: PhantomData<M>,
}
impl<'de, M, A> Reader<'de, M, A>
where
M: 'static,
A: Allocator,
{
#[inline]
pub(crate) fn new(cfg: Config, input: &'de [u8], alloc: A) -> Self {
Self {
cfg,
parser: SliceParser::new(input),
doc: DocState::new(alloc),
_marker: PhantomData,
}
}
#[inline]
pub fn headers_with<C>(&mut self, cx: C) -> Result<Option<&Headers<A>>, C::Error>
where
C: Context,
{
self.doc.ensure_header(cx, &mut self.parser, &self.cfg)?;
Ok(self.doc.headers())
}
#[inline]
pub fn next_record_with<C, T>(&mut self, cx: C) -> Result<Option<T>, C::Error>
where
C: Context<Allocator = A>,
T: Decode<'de, M, A>,
{
cx.clear();
self.doc.ensure_header(cx, &mut self.parser, &self.cfg)?;
if !parser::begin_record(cx, &mut self.parser, &self.cfg) {
return Ok(None);
}
let value = T::decode(RecordDecoder::<_, _, M, _>::new(
cx,
&mut self.parser,
self.cfg,
&mut self.doc,
true,
))?;
Ok(Some(value))
}
#[inline]
pub fn is_done(&self) -> bool {
self.parser
.remaining()
.iter()
.all(|&b| self.cfg.is_terminator(b))
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
impl<'de, M> Reader<'de, M, Global>
where
M: 'static,
{
#[inline]
pub fn headers(&mut self) -> Result<Option<&Headers<Global>>, Error> {
let cx = crate::context::new().with_error();
self.headers_with(&cx)
}
#[inline]
pub fn next_record<T>(&mut self) -> Result<Option<T>, Error>
where
T: Decode<'de, M, Global>,
{
let cx = crate::context::new().with_error();
self.next_record_with(&cx)
}
#[inline]
pub fn deserialize<T>(&mut self) -> DeserializeRecords<'_, 'de, M, T>
where
T: Decode<'de, M, Global>,
{
DeserializeRecords {
reader: self,
done: false,
_marker: PhantomData,
}
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
pub struct DeserializeRecords<'a, 'de, M, T> {
reader: &'a mut Reader<'de, M, Global>,
done: bool,
_marker: PhantomData<T>,
}
#[cfg(feature = "alloc")]
impl<'de, M, T> Iterator for DeserializeRecords<'_, 'de, M, T>
where
M: 'static,
T: Decode<'de, M, Global>,
{
type Item = Result<T, Error>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
match self.reader.next_record() {
Ok(Some(value)) => Some(Ok(value)),
Ok(None) => {
self.done = true;
None
}
Err(error) => {
self.done = true;
Some(Err(error))
}
}
}
}