Skip to content

Commit

Permalink
Added implicit map support
Browse files Browse the repository at this point in the history
Closes #24
  • Loading branch information
ecton committed Oct 22, 2024
1 parent 04004a5 commit 57c2b54
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 67 deletions.
120 changes: 64 additions & 56 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,22 +325,25 @@ impl<'s> Parser<'s> {

fn parse_implicit_map(&mut self, state: MapState) -> Result<Event<'s>, Error> {
match state {
MapState::ExpectingKey => match self.next_token_parts()? {
(location, Some(TokenKind::Identifier(key))) => {
self.root_state = State::ImplicitMap(MapState::ExpectingColon);
Ok(Event::new(
MapState::ExpectingKey => match self.next_token().transpose()? {
Some(Token {
location,
kind: TokenKind::Comment(comment),
}) => Ok(Event::new(location, EventKind::Comment(comment))),
Some(token) => match self.parse_token(token, None)? {
Event {
kind: EventKind::Primitive(primitive),
location,
EventKind::Primitive(Primitive::Identifier(key)),
))
}
(location, Some(TokenKind::Comment(comment))) => {
Ok(Event::new(location, EventKind::Comment(comment)))
}
(location, None) => {
} => {
self.root_state = State::ImplicitMap(MapState::ExpectingColon);
Ok(Event::new(location, EventKind::Primitive(primitive)))
}
Event { location, .. } => Err(Error::new(location, ErrorKind::ExpectedKey)),
},
None => {
self.root_state = State::Finished;
Ok(Event::new(location, EventKind::EndNested))
Ok(Event::new(self.current_range(), EventKind::EndNested))
}
(location, _) => Err(Error::new(location, ErrorKind::ExpectedKey)),
},
MapState::ExpectingColon => match self.next_token_parts()? {
(_, Some(TokenKind::Colon)) => {
Expand All @@ -366,30 +369,39 @@ impl<'s> Parser<'s> {
ErrorKind::ExpectedValue,
)),
},
MapState::ExpectingComma => match self.next_token_parts()? {
(location, Some(TokenKind::Close(Balanced::Brace))) => {
MapState::ExpectingComma => match self.next_token().transpose()? {
Some(Token {
location,
kind: TokenKind::Comment(comment),
}) => Ok(Event::new(location, EventKind::Comment(comment))),
Some(Token {
location,
kind: TokenKind::Close(Balanced::Brace),
}) => {
self.root_state = State::Finished;
Ok(Event::new(location, EventKind::EndNested))
}
(_, Some(TokenKind::Comma)) => {
Some(Token {
kind: TokenKind::Comma,
..
}) => {
self.root_state = State::ImplicitMap(MapState::ExpectingKey);
self.parse_implicit_map(MapState::ExpectingKey)
}
(location, Some(TokenKind::Identifier(key))) => {
Some(token) => {
self.root_state = State::ImplicitMap(MapState::ExpectingColon);
Ok(Event::new(
location,
EventKind::Primitive(Primitive::Identifier(key)),
))
}
(location, Some(TokenKind::Comment(comment))) => {
Ok(Event::new(location, EventKind::Comment(comment)))
match self.parse_token(token, None)? {
Event {
location,
kind: EventKind::Primitive(primitive),
} => Ok(Event::new(location, EventKind::Primitive(primitive))),
Event { location, .. } => Err(Error::new(location, ErrorKind::ExpectedKey)),
}
}
(location, None) => {
None => {
self.root_state = State::Finished;
Ok(Event::new(location, EventKind::EndNested))
Ok(Event::new(self.current_range(), EventKind::EndNested))
}
(location, _) => Err(Error::new(location, ErrorKind::ExpectedKey)),
},
}
}
Expand All @@ -406,29 +418,28 @@ impl<'s> Parser<'s> {
TokenKind::Comment(comment) => {
Ok(Event::new(token.location, EventKind::Comment(comment)))
}
TokenKind::Identifier(_)
if self.config.allow_implicit_map
&& matches!(
self.peek(),
Some(Token {
kind: TokenKind::Colon,
..
})
) =>
_ if self.config.allow_implicit_map
&& matches!(
self.peek(),
Some(Token {
kind: TokenKind::Colon,
..
})
) =>
{
let TokenKind::Identifier(identifier) = token.kind else {
unreachable!("just matched")
};
// Switch to parsing an implicit map
self.root_state =
State::StartingImplicitMap((token.location, identifier));
Ok(Event::new(
0..0,
EventKind::BeginNested {
name: None,
kind: Nested::Map,
},
))
match self.parse_token(token, None) {
Ok(event) => {
self.root_state = State::StartingImplicitMap(event);
Ok(Event::new(
0..0,
EventKind::BeginNested {
name: None,
kind: Nested::Map,
},
))
}
Err(err) => Err(err),
}
}
_ => {
self.root_state = State::Finished;
Expand All @@ -437,16 +448,13 @@ impl<'s> Parser<'s> {
}
}
State::StartingImplicitMap(_) => {
let State::StartingImplicitMap((location, identifier)) = mem::replace(
let State::StartingImplicitMap(event) = mem::replace(
&mut self.root_state,
State::ImplicitMap(MapState::ExpectingColon),
) else {
unreachable!("just matched")
};
Ok(Event::new(
location,
EventKind::Primitive(Primitive::Identifier(identifier)),
))
Ok(event)
}
State::ImplicitMap(state) => self.parse_implicit_map(*state),
State::Finished => match self.next_token()? {
Expand Down Expand Up @@ -510,10 +518,10 @@ impl Config {
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
#[derive(Debug, Clone, PartialEq)]
enum State<'s> {
AtStart,
StartingImplicitMap((Range<usize>, &'s str)),
StartingImplicitMap(Event<'s>),
ImplicitMap(MapState),
Finished,
}
Expand Down
36 changes: 25 additions & 11 deletions src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ where
{
type Error = core::fmt::Error;
type Ok = ();
type SerializeMap = Self;
type SerializeMap = MapSerializer<'a, 'config, Output>;
type SerializeSeq = Self;
type SerializeStruct = StructSerializer<'a, 'config, Output>;
type SerializeStruct = MapSerializer<'a, 'config, Output>;
type SerializeStructVariant = Self;
type SerializeTuple = Self;
type SerializeTupleStruct = Self;
Expand Down Expand Up @@ -244,9 +244,15 @@ where

// TODO implicit_map_at_root
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
let is_implicit_map = self.implicit_map_at_root;
self.mark_value_seen();
self.writer.begin_map()?;
Ok(self)
if !is_implicit_map {
self.writer.begin_map()?;
}
Ok(MapSerializer {
serializer: self,
is_implicit_map,
})
}

fn serialize_struct(
Expand All @@ -265,7 +271,7 @@ where
}
}

Ok(StructSerializer {
Ok(MapSerializer {
serializer: self,
is_implicit_map,
})
Expand Down Expand Up @@ -359,12 +365,12 @@ where
}
}

pub struct StructSerializer<'a, 'config, Output> {
pub struct MapSerializer<'a, 'config, Output> {
serializer: &'a mut Serializer<'config, Output>,
is_implicit_map: bool,
}

impl<'a, 'config, Output> SerializeStruct for StructSerializer<'a, 'config, Output>
impl<'a, 'config, Output> SerializeStruct for MapSerializer<'a, 'config, Output>
where
Output: Write,
{
Expand Down Expand Up @@ -415,7 +421,7 @@ where
}
}

impl<'a, 'config, Output> SerializeMap for &'a mut Serializer<'config, Output>
impl<'a, 'config, Output> SerializeMap for MapSerializer<'a, 'config, Output>
where
Output: Write,
{
Expand All @@ -426,18 +432,26 @@ where
where
T: serde::Serialize + ?Sized,
{
key.serialize(&mut **self)
key.serialize(&mut *self.serializer)
}

fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: serde::Serialize + ?Sized,
{
value.serialize(&mut **self)
if self.is_implicit_map {
self.serializer.writer.write_raw_value(": ")?;
value.serialize(&mut *self.serializer)?;
self.serializer.writer.insert_newline()
} else {
value.serialize(&mut *self.serializer)
}
}

fn end(self) -> Result<Self::Ok, Self::Error> {
self.writer.finish_nested()?;
if !self.is_implicit_map {
self.serializer.writer.finish_nested()?;
}
Ok(())
}
}
Expand Down
10 changes: 10 additions & 0 deletions src/tests/serde.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use alloc::borrow::Cow;
use alloc::vec;
use core::fmt::Debug;
use std::collections::BTreeMap;
use std::string::String;

use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -236,3 +238,11 @@ fn value_from_serialize() {
let from_value: StructOfEverything = value.to_deserialize().unwrap();
assert_eq!(original, from_value);
}

#[test]
fn implicit_btree_map() {
roundtrip_implicit_map(
&BTreeMap::from([(String::from("Hello"), 1), (String::from("World"), 2)]),
"\"Hello\": 1\n\"World\": 2\n",
);
}

0 comments on commit 57c2b54

Please sign in to comment.