mod error; pub use error::*;
mod helpers; pub use helpers::*;
mod key; pub(crate) use key::*;
mod location; pub(crate) use location::*;
mod map; pub(crate) use map::*;
mod num; pub(crate) use num::*;
mod r#enum; pub(crate) use r#enum::*;
mod seq; pub(crate) use seq::*;
#[derive(Debug,PartialEq)]
pub(crate) enum Position {
Start,
Inline,
Newline,
Indented,
}
#[derive(Debug,PartialEq)]
pub(crate) enum ReadResult {
Inline,
Multiline,
None,
}
pub struct Deserializer<R: std::io::BufRead + std::io::Seek> {
buf: Vec<u8>,
input: R,
indent: String,
prev_indent: Vec<usize>,
position: Position,
location: Location,
}
impl<R: std::io::BufRead + std::io::Seek> Deserializer<R> {
pub fn from(i: R) -> Self {
Self {
buf: Vec::new(),
input: i,
indent: Default::default(),
prev_indent: Default::default(),
position: Position::Start,
location: Location{line: 1, column: 1},
}
}
fn parse_string(&mut self) -> Result<(std::borrow::Cow<str>, crate::Location), DeserializeError> {
let mut r = std::borrow::Cow::Borrowed("");
let location = self.location;
loop {
match self.read_line(false)? {
ReadResult::Inline => {
return self.parse_inline_string()
}
ReadResult::Multiline => {
self.buf.clear();
self.input.read_until(b'\n', &mut self.buf)?;
let r = r.to_mut();
r.push_str(crate::from_utf8(&self.buf, self.location)?);
self.location.add_lines(1);
}
ReadResult::None => {
let s = r.to_mut();
while s.ends_with('\n') {
s.pop().unwrap();
}
self.dedent();
return Ok((r, location))
}
}
}
}
fn parse_inline_string(&mut self) -> Result<(std::borrow::Cow<str>, crate::Location), DeserializeError> {
let (s, location, size) = self.peek_inline_string()?;
let s = s.to_owned(); self.location.add_lines(1);
self.seek_forward(size)?;
Ok((s.into(), location))
}
fn peek_byte(&mut self) -> Result<Option<u8>, DeserializeError> {
Ok(self.input.fill_buf()?.get(0).cloned())
}
fn peek_inline_string(&mut self) -> Result<(&str, crate::Location, usize), DeserializeError> {
self.buf.clear();
let read = self.input.read_until(b'\n', &mut self.buf)?;
self.seek_backwards(read)?;
let mut b = &self.buf[..];
if let Some(comment_start) = b.iter().position(|c| c == &b'#') {
b = &b[..comment_start];
}
let mut location = self.location;
let mut s = crate::from_utf8(b, location)?;
for (i, c) in s.char_indices() {
if c.is_whitespace() {
location.add_columns(1);
} else {
s = &s[i..];
break
}
}
s = s.trim_end();
Ok((s.into(), location, read))
}
fn parse_key(&mut self) -> Result<(std::borrow::Cow<str>, Location), DeserializeError> {
self.buf.clear();
self.input.read_until(b':', &mut self.buf)?;
if self.buf.pop() != Some(b':') {
return Err(DeserializeErrorKind::Invalid("Expected \":\" after key".into())
.at(self.location));
}
let s = crate::from_utf8(&self.buf, self.location)?;
let chars = s.chars().count() + 1;
let location = self.location;
self.location.add_columns(chars);
if s.starts_with('\"') {
return Err(crate::DeserializeErrorKind::Invalid(
"Keys can't start with `\"`.\n\nQuoted strings are reserved for future features. There is currently no way to start a key with `\"`.".into())
.at(self.location))
}
self.position = Position::Inline;
Ok((s.into(), location))
}
fn read_line(&mut self, comments: bool) -> Result<ReadResult, DeserializeError> {
self.buf.clear();
let read = self.input.read_until(b'\n', &mut self.buf)?;
if self.buf.is_empty() {
return Ok(ReadResult::None)
}
if self.buf.ends_with(b"\n") {
self.buf.pop();
}
match self.position {
Position::Start => {
for (i, _i_end, c) in bstr::ByteSlice::char_indices(&self.buf[..]) {
if c == char::REPLACEMENT_CHARACTER {
return Err(DeserializeErrorKind::InvalidUtf8.at(self.location))
}
if !c.is_whitespace() {
let indent = &self.buf[..i];
self.indent.push_str(unsafe { crate::from_utf8_unchecked(indent) });
self.position = Position::Indented;
self.seek_backwards(read)?;
return self.read_line(comments)
}
}
self.location.add_lines(1);
self.read_line(comments)
}
Position::Inline => {
for (i, _i_end, c) in bstr::ByteSlice::char_indices(&self.buf[..]) {
if c == '#' {
break
} else if c == '"' {
return Err(crate::DeserializeErrorKind::Invalid(
"Inline strings can't start with `\"`.\n\nQuoted strings are reserved for future features. If you want a string that starts with a quote put the string indented on its own line.".into())
.at(self.location))
} else if c == char::REPLACEMENT_CHARACTER {
self.location.add_columns(i);
return Err(DeserializeErrorKind::InvalidUtf8.at(self.location))
} else if !c.is_whitespace() {
self.seek_backwards(read - i)?;
self.position = Position::Indented;
return Ok(ReadResult::Inline)
}
self.location.add_columns(1);
}
self.position = Position::Newline;
self.location.add_lines(1);
return self.read_line(comments)
}
Position::Newline => {
let s = crate::from_utf8(&self.buf, self.location)?;
let indent_len = s.find(|c: char| !c.is_whitespace()).unwrap_or(s.len());
let indent = &s[..indent_len];
if comments && (s.len() == indent_len || s.as_bytes()[indent_len] == b'#') {
self.location.add_lines(1);
return self.read_line(comments);
}
if indent.len() <= self.indent.len() || !indent.starts_with(&self.indent) {
return Ok(ReadResult::None)
}
self.position = Position::Indented;
self.prev_indent.push(self.indent.len());
self.indent.push_str(&indent[self.indent.len()..]);
self.location.add_columns(indent.chars().count());
self.seek_backwards(read - self.indent.len())?;
Ok(ReadResult::Multiline)
}
Position::Indented => {
if comments {
let mut empty = true;
for (i, _i_end, c) in bstr::ByteSlice::char_indices(&self.buf[..]) {
if c == '#' {
break
} else if c == char::REPLACEMENT_CHARACTER {
self.location.add_columns(i);
return Err(DeserializeErrorKind::InvalidUtf8.at(self.location))
} else if !c.is_whitespace() {
empty = false;
break
}
}
if empty {
self.location.add_lines(1);
return self.read_line(comments)
}
}
if self.buf.starts_with(self.indent.as_bytes()) {
self.location.add_columns(self.indent.chars().count());
self.seek_backwards(read - self.indent.len())?;
return Ok(ReadResult::Multiline)
}
self.seek_backwards(read)?;
Ok(ReadResult::None)
}
}
}
fn seek_backwards(&mut self, bytes: usize) -> Result<(), DeserializeError> {
let seek: i64 = bytes
.try_into()
.map_err(|_| crate::DeserializeErrorKind::Custom(format!("Seek too long.")).at(self.location))?;
self.input.seek(std::io::SeekFrom::Current(-seek))?;
Ok(())
}
fn seek_forward(&mut self, bytes: usize) -> Result<(), DeserializeError> {
let seek: i64 = bytes
.try_into()
.map_err(|_| crate::DeserializeErrorKind::Custom(format!("Seek too long.")).at(self.location))?;
self.input.seek(std::io::SeekFrom::Current(seek))?;
Ok(())
}
fn dedent(&mut self) {
match self.position {
Position::Start => {} Position::Inline => self.position = Position::Indented,
Position::Newline => self.position = Position::Indented,
Position::Indented => {
if let Some(prev) = self.prev_indent.pop() {
self.indent.truncate(prev);
}
}
}
}
fn parse_num(&mut self) -> Result<(Number, crate::Location, std::borrow::Cow<str>), DeserializeError> {
let (s, location) = self.parse_string()?;
let n = parse_num(&s, location)?;
Ok((n, location, s))
}
fn parse_sint<T: std::convert::TryFrom<i128> + std::ops::Neg>(&mut self) -> Result<T, DeserializeError>
where
<T as std::convert::TryFrom<i128>>::Error: std::fmt::Debug,
<T as std::ops::Neg>::Output: std::convert::Into<T>,
{
let (n, location, source) = self.parse_num()?;
n.to_sint(&source).map_err(|e| e.at(location))
}
fn parse_uint<T: std::convert::TryFrom<u128>>(&mut self) -> Result<T, DeserializeError>
where
<T as std::convert::TryFrom<u128>>::Error: std::fmt::Debug,
{
let (n, location, source) = self.parse_num()?;
n.to_uint(&source).map_err(|e| e.at(location))
}
fn parse_float(&mut self) -> Result<f64, DeserializeError> {
self.parse_num().map(|(n, ..)| n.to_f64())
}
}
impl<'d, R: std::io::BufRead + std::io::Seek> serde::de::Deserializer<'d> for &mut Deserializer<R> {
type Error = DeserializeError;
fn deserialize_any<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
self.deserialize_str(visitor)
}
fn deserialize_bool<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
let (s, location) = self.parse_string()?;
let b = match s.as_ref() {
"true" => true,
"false" => false,
other => return Err(
DeserializeErrorKind::Invalid(
format!("Expected bool, got {:?}", other))
.at(location)),
};
visitor.visit_bool(b)
}
fn deserialize_i8<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
visitor.visit_i8(self.parse_sint()?)
}
fn deserialize_i16<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
visitor.visit_i16(self.parse_sint()?)
}
fn deserialize_i32<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
visitor.visit_i32(self.parse_sint()?)
}
fn deserialize_i64<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
visitor.visit_i64(self.parse_sint()?)
}
fn deserialize_i128<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
visitor.visit_i128(self.parse_sint()?)
}
fn deserialize_u8<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
visitor.visit_u8(self.parse_uint()?)
}
fn deserialize_u16<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
visitor.visit_u16(self.parse_uint()?)
}
fn deserialize_u32<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
visitor.visit_u32(self.parse_uint()?)
}
fn deserialize_u64<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
visitor.visit_u64(self.parse_uint()?)
}
fn deserialize_u128<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
visitor.visit_u128(self.parse_uint()?)
}
fn deserialize_f32<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
visitor.visit_f32(self.parse_float()? as f32)
}
fn deserialize_f64<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
visitor.visit_f64(self.parse_float()?)
}
fn deserialize_char<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
let (s, location) = self.parse_string()?;
if s.len() == 1 {
visitor.visit_char(s.chars().next().unwrap())
} else {
Err(crate::DeserializeErrorKind::Invalid(format!("Expected single character, got {:?}", s)).at(location))
}
}
fn deserialize_str<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
let (s, _location) = self.parse_string()?;
match s {
std::borrow::Cow::Borrowed(s) => visitor.visit_str(s),
std::borrow::Cow::Owned(s) => visitor.visit_string(s),
}
}
fn deserialize_string<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
self.deserialize_str(visitor)
}
fn deserialize_bytes<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, crate::DeserializeError> {
self.deserialize_byte_buf(visitor)
}
fn deserialize_byte_buf<V: serde::de::Visitor<'d>>(self, _visitor: V) -> Result<V::Value, crate::DeserializeError> {
Err(crate::DeserializeErrorKind::Unimplemented("deserialize_byte_buf").at(self.location))
}
fn deserialize_option<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
if self.position == Position::Inline {
let (s, _, size) = self.peek_inline_string()?;
if !s.is_empty() {
return visitor.visit_some(self)
}
self.seek_forward(size)?;
self.location.add_lines(1);
self.position = Position::Newline;
}
self.buf.clear();
let read = self.input.read_until(b'\n', &mut self.buf)?;
if self.buf.is_empty() {
return visitor.visit_none()
}
if self.buf.ends_with(b"\n") {
self.buf.pop();
}
if self.buf.len() > self.indent.len()
&& self.buf.starts_with(self.indent.as_bytes())
&& bstr::decode_utf8(&self.buf[self.indent.len()..]).0.map(|c| c.is_whitespace()).unwrap_or(false)
{
self.seek_backwards(read)?;
visitor.visit_some(self)
} else if bstr::ByteSlice::chars(&self.buf[..]).all(|c| c.is_whitespace()) {
self.location.add_lines(1);
self.deserialize_option(visitor)
} else {
self.seek_backwards(read)?;
self.dedent();
visitor.visit_none()
}
}
fn deserialize_unit<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
self.parse_string()?;
visitor.visit_unit()
}
fn deserialize_unit_struct<V: serde::de::Visitor<'d>>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, DeserializeError> {
self.deserialize_unit(visitor)
}
fn deserialize_newtype_struct<V: serde::de::Visitor<'d>>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, DeserializeError> {
visitor.visit_newtype_struct(self)
}
fn deserialize_seq<V: serde::de::Visitor<'d>>(mut self, visitor: V) -> Result<V::Value, DeserializeError> {
let r = visitor.visit_seq(SeqDeserializer {
root: &mut self,
});
self.dedent();
r
}
fn deserialize_tuple<V: serde::de::Visitor<'d>>(self, _len: usize, visitor: V) -> Result<V::Value, DeserializeError> {
self.deserialize_seq(visitor)
}
fn deserialize_tuple_struct<V: serde::de::Visitor<'d>>(
self,
_name: &'static str,
_len: usize,
visitor: V,
) -> Result<V::Value, DeserializeError> {
self.deserialize_seq(visitor)
}
fn deserialize_map<V: serde::de::Visitor<'d>>(mut self, visitor: V) -> Result<V::Value, DeserializeError> {
let r = visitor.visit_map(MapDeserializer {
root: &mut self,
});
self.dedent();
r
}
fn deserialize_struct<V: serde::de::Visitor<'d>>(
self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, DeserializeError> {
self.deserialize_map(visitor)
}
fn deserialize_enum<V: serde::de::Visitor<'d>>(
mut self,
name: &'static str,
variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, DeserializeError> {
match self.read_line(true)? {
ReadResult::Inline => {
let (inline, location) = self.parse_inline_string()?;
serde::de::IntoDeserializer::into_deserializer(inline)
.deserialize_enum(name, variants, visitor)
.map_err(|e: crate::DeserializeError| e.with_location(location))
}
ReadResult::None => {
self.dedent();
serde::de::IntoDeserializer::into_deserializer("")
.deserialize_enum(name, variants, visitor)
.map_err(|e: crate::DeserializeError| e.with_location(self.location))
}
ReadResult::Multiline => {
self.buf.clear();
let read = self.input.read_until(b'\n', &mut self.buf)?;
self.seek_backwards(read)?;
let mut b = &self.buf[..];
if let Some(comment_start) = b.iter().position(|c| c == &b'#') {
b = &b[..comment_start];
}
if b.contains(&b':') {
let r = visitor.visit_enum(EnumDeserializer {
root: &mut self,
});
self.dedent();
r
} else {
let (inline, location) = self.parse_inline_string()?;
let r = serde::de::IntoDeserializer::into_deserializer(inline)
.deserialize_enum(name, variants, visitor)
.map_err(|e: crate::DeserializeError| e.with_location(location));
self.dedent();
r
}
}
}
}
fn deserialize_identifier<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
self.deserialize_str(visitor)
}
fn deserialize_ignored_any<V: serde::de::Visitor<'d>>(self, visitor: V) -> Result<V::Value, DeserializeError> {
self.deserialize_unit(visitor)
}
}