Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
- Add `struct_names` option to `PrettyConfig`

## [0.7.0] - 2021-10-22

- Add `unwrap_variant_newtypes` extension ([#319](https://github.com/ron-rs/ron/pull/319))
Expand Down Expand Up @@ -178,4 +181,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add roundtrip tests ([#24](https://github.com/ron-rs/ron/pull/24))

## [0.0.1] - 2015-07-30
Initial release
Initial release
2 changes: 2 additions & 0 deletions clippy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
msrv = "1.36"
blacklisted-names = []
64 changes: 54 additions & 10 deletions src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub use crate::error::{Error, ErrorCode, Result};
pub use crate::parse::Position;

use serde::de::{self, DeserializeSeed, Deserializer as SerdeError, Visitor};
use std::cell::RefCell;
use std::{borrow::Cow, io, str};

use self::{id::IdDeserializer, tag::TagDeserializer};
Expand All @@ -24,6 +25,7 @@ mod value;
pub struct Deserializer<'de> {
bytes: Bytes<'de>,
newtype_variant: bool,
struct_name: Option<String>,
}

impl<'de> Deserializer<'de> {
Expand All @@ -37,11 +39,12 @@ impl<'de> Deserializer<'de> {
Ok(Deserializer {
bytes: Bytes::new(input)?,
newtype_variant: false,
struct_name: None,
})
}

pub fn remainder(&self) -> Cow<'_, str> {
String::from_utf8_lossy(&self.bytes.bytes())
String::from_utf8_lossy(self.bytes.bytes())
}
}

Expand Down Expand Up @@ -150,14 +153,17 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
// `identifier` does not change state if it fails
let ident = self.bytes.identifier().ok();

if ident.is_some() {
if let Some(ident) = ident {
self.bytes.skip_ws()?;

self.struct_name = Some(String::from_utf8(ident.to_vec()).unwrap());
return self.handle_any_struct(visitor);
}

match self.bytes.peek_or_eof()? {
b'(' => self.handle_any_struct(visitor),
b'(' => {
self.struct_name = None;
self.handle_any_struct(visitor)
}
b'[' => self.deserialize_seq(visitor),
b'{' => self.deserialize_map(visitor),
b'0'..=b'9' | b'+' | b'-' => {
Expand Down Expand Up @@ -315,7 +321,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
let string = self.bytes.string()?;
let base64_str = match string {
ParsedStr::Allocated(ref s) => s.as_str(),
ParsedStr::Slice(ref s) => s,
ParsedStr::Slice(s) => s,
};
base64::decode(base64_str)
};
Expand Down Expand Up @@ -415,7 +421,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
V: Visitor<'de>,
{
if self.bytes.consume("[") {
let value = visitor.visit_seq(CommaSeparated::new(b']', &mut self))?;
let value = visitor.visit_seq(CommaSeparated::new(b']', None, &mut self))?;
self.bytes.comma()?;

if self.bytes.consume("]") {
Expand All @@ -436,7 +442,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
let old_newtype_variant = self.newtype_variant;
self.newtype_variant = false;

let value = visitor.visit_seq(CommaSeparated::new(b')', &mut self))?;
let value = visitor.visit_seq(CommaSeparated::new(b')', None, &mut self))?;
self.bytes.comma()?;

if old_newtype_variant || self.bytes.consume(")") {
Expand Down Expand Up @@ -470,7 +476,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
V: Visitor<'de>,
{
if self.bytes.consume("{") {
let value = visitor.visit_map(CommaSeparated::new(b'}', &mut self))?;
let value = visitor.visit_map(CommaSeparated::new(b'}', None, &mut self))?;
self.bytes.comma()?;

if self.bytes.consume("}") {
Expand Down Expand Up @@ -502,7 +508,17 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
let old_newtype_variant = self.newtype_variant;
self.newtype_variant = false;

let value = visitor.visit_map(CommaSeparated::new(b')', &mut self))?;
let value = visitor.visit_map(CommaSeparated::new(
b')',
Some((
self.struct_name
.as_ref()
.map(|s| s.as_bytes().into())
.unwrap_or_default(),
RefCell::new(0),
)),
&mut self,
))?;
self.bytes.comma()?;

if old_newtype_variant || self.bytes.consume(")") {
Expand Down Expand Up @@ -546,14 +562,26 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {

struct CommaSeparated<'a, 'de: 'a> {
de: &'a mut Deserializer<'de>,
// If we are parsing a struct, this is set to the name of the struct and a counter
// that indicates how many bytes of the name have been read by the ValueVisitor
// constructing the Map/Struct.
// Serde does not provide a way to distinguish between structs and maps. However,
// we can abuse multiple calls to the `size_hint` method to access this information
// one byte at a time.
struct_name: Option<(Vec<u8>, RefCell<usize>)>,
terminator: u8,
had_comma: bool,
}

impl<'a, 'de> CommaSeparated<'a, 'de> {
fn new(terminator: u8, de: &'a mut Deserializer<'de>) -> Self {
fn new(
terminator: u8,
struct_name: Option<(Vec<u8>, RefCell<usize>)>,
de: &'a mut Deserializer<'de>,
) -> Self {
CommaSeparated {
de,
struct_name,
terminator,
had_comma: true,
}
Expand Down Expand Up @@ -626,6 +654,22 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
self.err(ErrorCode::ExpectedMapColon)
}
}

fn size_hint(&self) -> Option<usize> {
// trolololololol
match &self.struct_name {
Some((bytes, offset)) if *offset.borrow() <= bytes.len() => {
let i = *offset.borrow();
*offset.borrow_mut() += 1;
if bytes.len() == i {
Some(0)
} else {
Some(bytes[i] as usize)
}
}
_ => None,
}
}
}

struct Enum<'a, 'de: 'a> {
Expand Down
73 changes: 38 additions & 35 deletions src/de/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use serde::{
Deserialize, Deserializer,
};

use crate::value::Struct;
use crate::{
de,
value::{Map, Number, Value},
Expand Down Expand Up @@ -169,13 +170,32 @@ impl<'de> Visitor<'de> for ValueVisitor {
where
A: MapAccess<'de>,
{
let mut res: Map = Map::new();

while let Some(entry) = map.next_entry()? {
res.insert(entry.0, entry.1);
let mut struct_name: Option<Vec<u8>> = None;
while let Some(byte) = map.size_hint() {
struct_name.get_or_insert_with(Vec::new).push(byte as u8);
}
match struct_name {
Some(mut bytes) => {
let name = if bytes.len() > 1 {
bytes.pop();
Some(String::from_utf8(bytes).unwrap())
} else {
None
};
let mut res: Struct = Struct::new(name);
while let Some((Value::String(field), value)) = map.next_entry()? {
res.insert(field, value);
}
Ok(Value::Struct(res))
}
None => {
let mut res: Map = Map::new();
while let Some(entry) = map.next_entry()? {
res.insert(entry.0, entry.1);
}
Ok(Value::Map(res))
}
}

Ok(Value::Map(res))
}
}

Expand Down Expand Up @@ -272,40 +292,23 @@ mod tests {
])"
),
Value::Option(Some(Box::new(Value::Seq(vec![
Value::Map(
vec![
(
Value::String("width".to_owned()),
Value::Number(Number::new(20)),
),
(
Value::String("height".to_owned()),
Value::Number(Number::new(5)),
),
(
Value::String("name".to_owned()),
Value::String("The Room".to_owned()),
),
Value::Struct(Struct {
name: Some("Room".to_string()),
fields: vec![
("width".to_owned(), Value::Number(Number::new(20)),),
("height".to_owned(), Value::Number(Number::new(5)),),
("name".to_owned(), Value::String("The Room".to_owned()),),
]
.into_iter()
.collect(),
),
Value::Map(
}),
Value::Struct(
vec![
("width".to_owned(), Value::Number(Number::new(10.0)),),
("height".to_owned(), Value::Number(Number::new(10.0)),),
("name".to_owned(), Value::String("Another room".to_owned()),),
(
Value::String("width".to_owned()),
Value::Number(Number::new(10.0)),
),
(
Value::String("height".to_owned()),
Value::Number(Number::new(10.0)),
),
(
Value::String("name".to_owned()),
Value::String("Another room".to_owned()),
),
(
Value::String("enemy_levels".to_owned()),
"enemy_levels".to_owned(),
Value::Map(
vec![
(
Expand Down
5 changes: 1 addition & 4 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct Error {
pub type Result<T> = std::result::Result<T, Error>;

#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum ErrorCode {
Io(String),
Message(String),
Expand Down Expand Up @@ -54,9 +55,6 @@ pub enum ErrorCode {

Utf8Error(Utf8Error),
TrailingCharacters,

#[doc(hidden)]
__Nonexhaustive,
}

impl fmt::Display for Error {
Expand Down Expand Up @@ -108,7 +106,6 @@ impl fmt::Display for ErrorCode {
ErrorCode::UnderscoreAtBeginning => f.write_str("Found underscore at the beginning"),
ErrorCode::UnexpectedByte(_) => f.write_str("Unexpected byte"),
ErrorCode::TrailingCharacters => f.write_str("Non-whitespace trailing characters"),
_ => f.write_str("Unknown ErrorCode"),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ impl<'a> Bytes<'a> {
}

pub fn bytes(&self) -> &[u8] {
&self.bytes
self.bytes
}

pub fn char(&mut self) -> Result<char> {
Expand Down
Loading