use core::mem::replace;
use std::borrow::Cow;
use nt_syntax::{
IndentState, Lexer, LineKind, Seen, SeenPool, SyntaxError, ValidateSink,
inline::{parse, parse_with},
};
use serde::{
Deserialize, Deserializer,
de::{self, DeserializeSeed, IntoDeserializer, Visitor, value::BorrowedStrDeserializer},
};
use super::{scalar::ScalarDe, val::ValDe};
use crate::error::{Error, Result};
fn multiline_key_msg(at_eof: bool) -> &'static str {
if at_eof {
"indented value must follow multiline key."
} else {
"multiline key requires a value."
}
}
pub fn from_str<'de, T: Deserialize<'de>>(text: &'de str) -> Result<T> {
let mut state = StreamState {
lex: Lexer::new(text),
indent: IndentState::new(),
seen_pool: SeenPool::new(),
};
let val = match state.lex.peek()? {
None => T::deserialize(ScalarDe(Cow::Borrowed("")))?,
Some(tok) if tok.depth > 0 => {
return Err(
SyntaxError::line(tok.line_no, "top-level content must start in column 1.").into(),
);
}
Some(_) => T::deserialize(NodeDe {
st: &mut state,
depth: 0,
})?,
};
if let Some(tok) = state.lex.peek()? {
state.indent.check_trailing(tok.line_no, tok.depth)?;
}
Ok(val)
}
struct StreamState<'de> {
lex: Lexer<'de>,
indent: IndentState,
seen_pool: SeenPool<'de>,
}
impl<'de> StreamState<'de> {
#[inline]
fn check_depth(&self, depth: u32) -> Result<()> {
if let Some(tok) = self.lex.peek_cached()
&& tok.depth > depth
{
return Err(self.indent.err(tok.line_no, tok.depth).into());
}
Ok(())
}
fn skip_value(&mut self, depth: u32) -> Result<()> {
let Some(tok) = self.lex.peek()? else {
return Ok(());
};
if tok.depth < depth {
return Ok(());
}
if tok.depth > depth {
self.check_depth(depth)?;
}
match tok.kind {
LineKind::Str(_) => Ok(self.lex.skip_str_block(depth)?),
LineKind::List(_) => {
while let Some(t) = self.lex.peek()? {
if t.depth != depth {
break;
}
let LineKind::List(val) = t.kind else {
return Err(SyntaxError::line(t.line_no, "expected list item.").into());
};
let _ = self.lex.next_tok()?;
if val.is_empty() {
if let Some(c) = self.lex.peek()?.filter(|c| c.depth > depth) {
self.indent.enter(c.depth);
let r = self.skip_value(c.depth);
self.indent.leave();
r?;
}
} else {
self.lex.no_indented(depth)?;
}
}
Ok(())
}
LineKind::Dict { .. } | LineKind::Key(_) => {
let mut seen = Seen::new();
let res = (|| -> Result<()> {
while let Some(t) = self.lex.peek()? {
if t.depth != depth {
break;
}
match t.kind {
LineKind::Dict { key, val } => {
let _ = self.lex.next_tok()?;
if !seen.insert_borrowed(key, &mut self.seen_pool) {
return Err(
SyntaxError::line(t.line_no, format!("duplicate key: {key}.")).into(),
);
}
if val.is_empty() {
if let Some(c) = self.lex.peek()?.filter(|c| c.depth > depth) {
self.indent.enter(c.depth);
let r = self.skip_value(c.depth);
self.indent.leave();
r?;
}
} else {
self.lex.no_indented(depth)?;
}
}
LineKind::Key(_) => {
let (key, line_no) = self.lex.read_key_block(depth)?;
if seen.contains(key.as_ref()) {
return Err(SyntaxError::line(line_no, format!("duplicate key: {key}.")).into());
}
let _ = seen.insert_cow(key, &mut self.seen_pool);
let peek = self.lex.peek()?;
let at_eof = peek.is_none();
let Some(c) = peek.filter(|c| c.depth > depth) else {
return Err(SyntaxError::line(line_no, multiline_key_msg(at_eof)).into());
};
self.indent.enter(c.depth);
let r = self.skip_value(c.depth);
self.indent.leave();
r?;
}
_ => return Err(SyntaxError::line(t.line_no, "expected dictionary item.").into()),
}
}
Ok(())
})();
self.seen_pool.recycle(seen);
res
}
LineKind::InlineList(raw) | LineKind::InlineDict(raw) => {
let _ = self.lex.next_tok()?;
let mut sink = ValidateSink;
parse_with(raw, tok.line_no, &mut sink)?;
Ok(())
}
LineKind::Bad => Err(SyntaxError::line(tok.line_no, "unrecognized line.").into()),
}
}
}
struct NodeDe<'s, 'de> {
st: &'s mut StreamState<'de>,
depth: u32,
}
impl<'s, 'de> NodeDe<'s, 'de> {
fn take_scalar(self) -> Result<Cow<'de, str>> {
let Some(tok) = self.st.lex.peek()? else {
return Ok(Cow::Borrowed(""));
};
if tok.depth < self.depth {
return Ok(Cow::Borrowed(""));
}
if tok.depth > self.depth {
self.st.check_depth(self.depth)?;
}
match tok.kind {
LineKind::Str(_) => Ok(self.st.lex.read_str_block(self.depth)?),
LineKind::Bad => Err(SyntaxError::line(tok.line_no, "unrecognized line.").into()),
_ => Err(Error::msg("expected a string value")),
}
}
}
macro_rules! node_numeric {
($($de:ident),* $(,)?) => {
$(
fn $de<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
ScalarDe(self.take_scalar()?).$de(visitor)
}
)*
};
}
impl<'s, 'de> de::Deserializer<'de> for NodeDe<'s, 'de> {
type Error = Error;
fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
let Some(tok) = self.st.lex.peek()? else {
return visitor.visit_borrowed_str("");
};
if tok.depth < self.depth {
return visitor.visit_borrowed_str("");
}
if tok.depth > self.depth {
self.st.check_depth(self.depth)?;
}
match tok.kind {
LineKind::Str(_) => {
ScalarDe(self.st.lex.read_str_block(self.depth)?).deserialize_any(visitor)
}
LineKind::List(_) => self.deserialize_seq(visitor),
LineKind::Dict { .. } | LineKind::Key(_) => self.deserialize_map(visitor),
LineKind::InlineList(raw) | LineKind::InlineDict(raw) => {
let _ = self.st.lex.next_tok()?;
let v = parse(raw, tok.line_no)?;
ValDe { value: &v }.deserialize_any(visitor)
}
LineKind::Bad => Err(SyntaxError::line(tok.line_no, "unrecognized line.").into()),
}
}
fn deserialize_bool<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
ScalarDe(self.take_scalar()?).deserialize_bool(visitor)
}
fn deserialize_char<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
ScalarDe(self.take_scalar()?).deserialize_char(visitor)
}
fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
ScalarDe(self.take_scalar()?).deserialize_str(visitor)
}
fn deserialize_string<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
ScalarDe(self.take_scalar()?).deserialize_string(visitor)
}
fn deserialize_bytes<V: Visitor<'de>>(self, _: V) -> Result<V::Value> {
Err(Error::msg("NestedText does not support byte arrays"))
}
fn deserialize_byte_buf<V: Visitor<'de>>(self, _: V) -> Result<V::Value> {
Err(Error::msg("NestedText does not support byte arrays"))
}
fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
let Some(tok) = self.st.lex.peek()? else {
return visitor.visit_none();
};
if tok.depth < self.depth {
return visitor.visit_none();
}
if tok.depth > self.depth {
self.st.check_depth(self.depth)?;
}
if let LineKind::Str(first) = tok.kind
&& first.is_empty()
{
let s = self.st.lex.read_str_block(self.depth)?;
if s.is_empty() {
return visitor.visit_none();
}
return visitor.visit_some(ScalarDe(s));
}
visitor.visit_some(self)
}
fn deserialize_unit<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
ScalarDe(self.take_scalar()?).deserialize_unit(visitor)
}
fn deserialize_unit_struct<V: Visitor<'de>>(
self,
_: &'static str,
visitor: V,
) -> Result<V::Value> {
self.deserialize_unit(visitor)
}
fn deserialize_newtype_struct<V: Visitor<'de>>(
self,
_: &'static str,
visitor: V,
) -> Result<V::Value> {
visitor.visit_newtype_struct(self)
}
fn deserialize_seq<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
let Some(tok) = self.st.lex.peek()? else {
return Err(Error::msg("expected a list value"));
};
if tok.depth != self.depth {
self.st.check_depth(self.depth)?;
return Err(Error::msg("expected a list value"));
}
match tok.kind {
LineKind::List(_) => {
let mut seq = StreamSeqDe {
st: self.st,
depth: self.depth,
};
let v = visitor.visit_seq(&mut seq)?;
if let Some(rem) = seq.st.lex.peek()?
&& rem.depth == self.depth
{
return Err(Error::msg("more list elements than expected"));
}
Ok(v)
}
LineKind::InlineList(raw) => {
let _ = self.st.lex.next_tok()?;
let v = parse(raw, tok.line_no)?;
ValDe { value: &v }.deserialize_seq(visitor)
}
LineKind::Bad => Err(SyntaxError::line(tok.line_no, "unrecognized line.").into()),
_ => Err(Error::msg("expected a list value")),
}
}
fn deserialize_tuple<V: Visitor<'de>>(self, _: usize, visitor: V) -> Result<V::Value> {
self.deserialize_seq(visitor)
}
fn deserialize_tuple_struct<V: Visitor<'de>>(
self,
_: &'static str,
_: usize,
visitor: V,
) -> Result<V::Value> {
self.deserialize_seq(visitor)
}
fn deserialize_map<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
let Some(tok) = self.st.lex.peek()? else {
return Err(Error::msg("expected a dictionary value"));
};
if tok.depth != self.depth {
self.st.check_depth(self.depth)?;
return Err(Error::msg("expected a dictionary value"));
}
match tok.kind {
LineKind::Dict { .. } | LineKind::Key(_) => {
let mut seen = Seen::new();
let res = visitor.visit_map(StreamMapDe {
st: self.st,
depth: self.depth,
seen: &mut seen,
pending: PendingVal::None,
});
self.st.seen_pool.recycle(seen);
res
}
LineKind::InlineDict(raw) => {
let _ = self.st.lex.next_tok()?;
let v = parse(raw, tok.line_no)?;
ValDe { value: &v }.deserialize_map(visitor)
}
LineKind::Bad => Err(SyntaxError::line(tok.line_no, "unrecognized line.").into()),
_ => Err(Error::msg("expected a dictionary value")),
}
}
fn deserialize_struct<V: Visitor<'de>>(
self,
_: &'static str,
_: &'static [&'static str],
visitor: V,
) -> Result<V::Value> {
self.deserialize_map(visitor)
}
fn deserialize_enum<V: Visitor<'de>>(
self,
_: &'static str,
_: &'static [&'static str],
visitor: V,
) -> Result<V::Value> {
let Some(tok) = self.st.lex.peek()? else {
return Err(Error::msg(
"an enum expects a string or a single-entry dictionary",
));
};
if tok.depth != self.depth {
self.st.check_depth(self.depth)?;
return Err(Error::msg(
"an enum expects a string or a single-entry dictionary",
));
}
match tok.kind {
LineKind::Str(_) => {
let s = self.st.lex.read_str_block(self.depth)?;
match &s {
Cow::Borrowed(b) => visitor.visit_enum(BorrowedStrDeserializer::new(b)),
Cow::Owned(o) => visitor.visit_enum(o.as_str().into_deserializer()),
}
}
LineKind::Dict { key, val } => {
let _ = self.st.lex.next_tok()?;
let v = visitor.visit_enum(StreamEnumDe {
st: self.st,
parent_depth: self.depth,
variant: Cow::Borrowed(key),
inline_val: if val.is_empty() { None } else { Some(val) },
require_indented: false,
line_no: tok.line_no,
})?;
if let Some(extra) = self.st.lex.peek()?
&& extra.depth == self.depth
{
return Err(Error::msg("an enum dictionary must have exactly one key"));
}
Ok(v)
}
LineKind::Key(_) => {
let (variant, line_no) = self.st.lex.read_key_block(self.depth)?;
let v = visitor.visit_enum(StreamEnumDe {
st: self.st,
parent_depth: self.depth,
variant,
inline_val: None,
require_indented: true,
line_no,
})?;
if let Some(extra) = self.st.lex.peek()?
&& extra.depth == self.depth
{
return Err(Error::msg("an enum dictionary must have exactly one key"));
}
Ok(v)
}
LineKind::InlineDict(raw) => {
let _ = self.st.lex.next_tok()?;
let v = parse(raw, tok.line_no)?;
ValDe { value: &v }.deserialize_enum("", &[], visitor)
}
LineKind::Bad => Err(SyntaxError::line(tok.line_no, "unrecognized line.").into()),
_ => Err(Error::msg(
"an enum expects a string or a single-entry dictionary",
)),
}
}
fn deserialize_identifier<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
ScalarDe(self.take_scalar()?).deserialize_identifier(visitor)
}
fn deserialize_ignored_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
self.st.skip_value(self.depth)?;
visitor.visit_unit()
}
node_numeric! {
deserialize_i8,
deserialize_i16,
deserialize_i32,
deserialize_i64,
deserialize_i128,
deserialize_u8,
deserialize_u16,
deserialize_u32,
deserialize_u64,
deserialize_u128,
deserialize_f32,
deserialize_f64,
}
}
struct StreamSeqDe<'s, 'de> {
st: &'s mut StreamState<'de>,
depth: u32,
}
impl<'s, 'de> de::SeqAccess<'de> for StreamSeqDe<'s, 'de> {
type Error = Error;
fn next_element_seed<T: DeserializeSeed<'de>>(&mut self, seed: T) -> Result<Option<T::Value>> {
let Some(tok) = self.st.lex.peek()? else {
return Ok(None);
};
if tok.depth < self.depth {
return Ok(None);
}
if tok.depth > self.depth {
self.st.check_depth(self.depth)?;
}
let LineKind::List(val) = tok.kind else {
return Err(SyntaxError::line(tok.line_no, "expected list item.").into());
};
let _ = self.st.lex.next_tok()?;
if !val.is_empty() {
self.st.lex.no_indented(self.depth)?;
return seed.deserialize(ScalarDe(Cow::Borrowed(val))).map(Some);
}
let Some(child) = self.st.lex.peek()?.filter(|c| c.depth > self.depth) else {
return seed.deserialize(ScalarDe(Cow::Borrowed(""))).map(Some);
};
self.st.indent.enter(child.depth);
let res = seed.deserialize(NodeDe {
st: self.st,
depth: child.depth,
});
self.st.indent.leave();
res.map(Some)
}
}
enum PendingVal<'de> {
None,
Inline(&'de str),
EmptyOrBlock { require_child: bool, line_no: u32 },
}
struct StreamMapDe<'s, 'm, 'de> {
st: &'s mut StreamState<'de>,
depth: u32,
seen: &'m mut Seen<'de>,
pending: PendingVal<'de>,
}
impl<'s, 'm, 'de> de::MapAccess<'de> for StreamMapDe<'s, 'm, 'de> {
type Error = Error;
#[inline]
fn next_key_seed<K: DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>> {
let Some(tok) = self.st.lex.peek()? else {
return Ok(None);
};
if tok.depth < self.depth {
return Ok(None);
}
if tok.depth > self.depth {
self.st.check_depth(self.depth)?;
}
match tok.kind {
LineKind::Dict { key, val } => {
let _ = self.st.lex.next_tok()?;
if !self.seen.insert_borrowed(key, &mut self.st.seen_pool) {
return Err(SyntaxError::line(tok.line_no, format!("duplicate key: {key}.")).into());
}
self.pending = if val.is_empty() {
PendingVal::EmptyOrBlock {
require_child: false,
line_no: tok.line_no,
}
} else {
PendingVal::Inline(val)
};
seed.deserialize(ScalarDe(Cow::Borrowed(key))).map(Some)
}
LineKind::Key(_) => {
let (key, line_no) = self.st.lex.read_key_block(self.depth)?;
if self.seen.contains(key.as_ref()) {
return Err(SyntaxError::line(line_no, format!("duplicate key: {key}.")).into());
}
let _ = self.seen.insert_cow(key.clone(), &mut self.st.seen_pool);
self.pending = PendingVal::EmptyOrBlock {
require_child: true,
line_no,
};
seed.deserialize(ScalarDe(key)).map(Some)
}
_ => Err(SyntaxError::line(tok.line_no, "expected dictionary item.").into()),
}
}
#[inline]
fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value> {
match replace(&mut self.pending, PendingVal::None) {
PendingVal::Inline(val) => {
self.st.lex.no_indented(self.depth)?;
seed.deserialize(ScalarDe(Cow::Borrowed(val)))
}
PendingVal::EmptyOrBlock {
require_child,
line_no,
} => {
let peek = self.st.lex.peek()?;
let at_eof = peek.is_none();
let Some(child) = peek.filter(|c| c.depth > self.depth) else {
if require_child {
return Err(SyntaxError::line(line_no, multiline_key_msg(at_eof)).into());
}
return seed.deserialize(ScalarDe(Cow::Borrowed("")));
};
self.st.indent.enter(child.depth);
let res = seed.deserialize(NodeDe {
st: self.st,
depth: child.depth,
});
self.st.indent.leave();
res
}
PendingVal::None => unreachable!("next_value called before next_key"),
}
}
}
struct StreamEnumDe<'s, 'de> {
st: &'s mut StreamState<'de>,
parent_depth: u32,
variant: Cow<'de, str>,
inline_val: Option<&'de str>,
require_indented: bool,
line_no: u32,
}
impl<'s, 'de> de::EnumAccess<'de> for StreamEnumDe<'s, 'de> {
type Error = Error;
type Variant = StreamVariantDe<'s, 'de>;
fn variant_seed<V: DeserializeSeed<'de>>(self, seed: V) -> Result<(V::Value, Self::Variant)> {
let v = seed.deserialize(ScalarDe(self.variant))?;
Ok((
v,
StreamVariantDe {
st: self.st,
parent_depth: self.parent_depth,
inline_val: self.inline_val,
require_indented: self.require_indented,
line_no: self.line_no,
},
))
}
}
struct StreamVariantDe<'s, 'de> {
st: &'s mut StreamState<'de>,
parent_depth: u32,
inline_val: Option<&'de str>,
require_indented: bool,
line_no: u32,
}
impl<'s, 'de> de::VariantAccess<'de> for StreamVariantDe<'s, 'de> {
type Error = Error;
fn unit_variant(self) -> Result<()> {
if self.inline_val.is_some() {
self.st.lex.no_indented(self.parent_depth)?;
return Ok(());
}
let peek = self.st.lex.peek()?;
let at_eof = peek.is_none();
if let Some(c) = peek.filter(|c| c.depth > self.parent_depth) {
self.st.indent.enter(c.depth);
let r = self.st.skip_value(c.depth);
self.st.indent.leave();
r?;
} else if self.require_indented {
return Err(SyntaxError::line(self.line_no, multiline_key_msg(at_eof)).into());
}
Ok(())
}
fn newtype_variant_seed<T: DeserializeSeed<'de>>(self, seed: T) -> Result<T::Value> {
if let Some(val) = self.inline_val {
self.st.lex.no_indented(self.parent_depth)?;
return seed.deserialize(ScalarDe(Cow::Borrowed(val)));
}
let peek = self.st.lex.peek()?;
let at_eof = peek.is_none();
let Some(child) = peek.filter(|c| c.depth > self.parent_depth) else {
if self.require_indented {
return Err(SyntaxError::line(self.line_no, multiline_key_msg(at_eof)).into());
}
return seed.deserialize(ScalarDe(Cow::Borrowed("")));
};
self.st.indent.enter(child.depth);
let r = seed.deserialize(NodeDe {
st: self.st,
depth: child.depth,
});
self.st.indent.leave();
r
}
fn tuple_variant<V: Visitor<'de>>(self, _: usize, visitor: V) -> Result<V::Value> {
if self.inline_val.is_some() {
return Err(Error::msg("expected a list value"));
}
let Some(child) = self.st.lex.peek()?.filter(|c| c.depth > self.parent_depth) else {
return Err(Error::msg("expected a list value"));
};
self.st.indent.enter(child.depth);
let r = NodeDe {
st: self.st,
depth: child.depth,
}
.deserialize_seq(visitor);
self.st.indent.leave();
r
}
fn struct_variant<V: Visitor<'de>>(
self,
_: &'static [&'static str],
visitor: V,
) -> Result<V::Value> {
if self.inline_val.is_some() {
return Err(Error::msg("expected a dictionary value"));
}
let Some(child) = self.st.lex.peek()?.filter(|c| c.depth > self.parent_depth) else {
return Err(Error::msg("expected a dictionary value"));
};
self.st.indent.enter(child.depth);
let r = NodeDe {
st: self.st,
depth: child.depth,
}
.deserialize_map(visitor);
self.st.indent.leave();
r
}
}