Skip to content

Commit 3669ecf

Browse files
committed
Add Value::Struct variant and preserve struct names and formatting
1 parent 0ce1426 commit 3669ecf

File tree

5 files changed

+252
-43
lines changed

5 files changed

+252
-43
lines changed

src/de/mod.rs

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
/// Deserialization module.
22
pub use crate::error::{Error, ErrorCode, Result};
33
pub use crate::parse::Position;
4+
use crate::{Map, Value};
45

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

810
use self::{id::IdDeserializer, tag::TagDeserializer};
@@ -24,6 +26,7 @@ mod value;
2426
pub struct Deserializer<'de> {
2527
bytes: Bytes<'de>,
2628
newtype_variant: bool,
29+
struct_name: Option<String>,
2730
}
2831

2932
impl<'de> Deserializer<'de> {
@@ -37,6 +40,7 @@ impl<'de> Deserializer<'de> {
3740
Ok(Deserializer {
3841
bytes: Bytes::new(input)?,
3942
newtype_variant: false,
43+
struct_name: None,
4044
})
4145
}
4246

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

153-
if ident.is_some() {
157+
if let Some(ident) = ident {
154158
self.bytes.skip_ws()?;
155-
159+
self.struct_name = Some(String::from_utf8(ident.to_vec()).unwrap());
156160
return self.handle_any_struct(visitor);
157161
}
158162

159163
match self.bytes.peek_or_eof()? {
160-
b'(' => self.handle_any_struct(visitor),
164+
b'(' => {
165+
self.struct_name = None;
166+
self.handle_any_struct(visitor)
167+
}
161168
b'[' => self.deserialize_seq(visitor),
162169
b'{' => self.deserialize_map(visitor),
163170
b'0'..=b'9' | b'+' | b'-' => {
@@ -415,7 +422,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
415422
V: Visitor<'de>,
416423
{
417424
if self.bytes.consume("[") {
418-
let value = visitor.visit_seq(CommaSeparated::new(b']', &mut self))?;
425+
let value = visitor.visit_seq(CommaSeparated::new(b']', None, &mut self))?;
419426
self.bytes.comma()?;
420427

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

439-
let value = visitor.visit_seq(CommaSeparated::new(b')', &mut self))?;
446+
let value = visitor.visit_seq(CommaSeparated::new(b')', None, &mut self))?;
440447
self.bytes.comma()?;
441448

442449
if old_newtype_variant || self.bytes.consume(")") {
@@ -470,7 +477,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
470477
V: Visitor<'de>,
471478
{
472479
if self.bytes.consume("{") {
473-
let value = visitor.visit_map(CommaSeparated::new(b'}', &mut self))?;
480+
let value = visitor.visit_map(CommaSeparated::new(b'}', None, &mut self))?;
474481
self.bytes.comma()?;
475482

476483
if self.bytes.consume("}") {
@@ -502,7 +509,17 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
502509
let old_newtype_variant = self.newtype_variant;
503510
self.newtype_variant = false;
504511

505-
let value = visitor.visit_map(CommaSeparated::new(b')', &mut self))?;
512+
let value = visitor.visit_map(CommaSeparated::new(
513+
b')',
514+
Some((
515+
self.struct_name
516+
.as_ref()
517+
.map(|s| s.as_bytes().into())
518+
.unwrap_or_default(),
519+
RefCell::new(0),
520+
)),
521+
&mut self,
522+
))?;
506523
self.bytes.comma()?;
507524

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

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

553577
impl<'a, 'de> CommaSeparated<'a, 'de> {
554-
fn new(terminator: u8, de: &'a mut Deserializer<'de>) -> Self {
578+
fn new(
579+
terminator: u8,
580+
struct_name: Option<(Vec<u8>, RefCell<usize>)>,
581+
de: &'a mut Deserializer<'de>,
582+
) -> Self {
555583
CommaSeparated {
556584
de,
585+
struct_name,
557586
terminator,
558587
had_comma: true,
559588
}
@@ -626,6 +655,22 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
626655
self.err(ErrorCode::ExpectedMapColon)
627656
}
628657
}
658+
659+
fn size_hint(&self) -> Option<usize> {
660+
// trolololololol
661+
match &self.struct_name {
662+
Some((bytes, offset)) if *offset.borrow() <= bytes.len() => {
663+
let i = *offset.borrow();
664+
*offset.borrow_mut() += 1;
665+
if bytes.len() == i {
666+
Some(0)
667+
} else {
668+
Some(bytes[i] as usize)
669+
}
670+
}
671+
_ => None,
672+
}
673+
}
629674
}
630675

631676
struct Enum<'a, 'de: 'a> {

src/de/value.rs

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use serde::{
55
Deserialize, Deserializer,
66
};
77

8+
use crate::value::Struct;
89
use crate::{
910
de,
1011
value::{Map, Number, Value},
@@ -169,13 +170,32 @@ impl<'de> Visitor<'de> for ValueVisitor {
169170
where
170171
A: MapAccess<'de>,
171172
{
172-
let mut res: Map = Map::new();
173-
174-
while let Some(entry) = map.next_entry()? {
175-
res.insert(entry.0, entry.1);
173+
let mut struct_name: Option<Vec<u8>> = None;
174+
while let Some(byte) = map.size_hint() {
175+
struct_name.get_or_insert_with(Vec::new).push(byte as u8);
176+
}
177+
match struct_name {
178+
Some(mut bytes) => {
179+
let name = if bytes.len() > 1 {
180+
bytes.pop();
181+
Some(String::from_utf8(bytes).unwrap())
182+
} else {
183+
None
184+
};
185+
let mut res: Struct = Struct::new(name);
186+
while let Some((Value::String(field), value)) = map.next_entry()? {
187+
res.insert(field, value);
188+
}
189+
Ok(Value::Struct(res))
190+
}
191+
None => {
192+
let mut res: Map = Map::new();
193+
while let Some(entry) = map.next_entry()? {
194+
res.insert(entry.0, entry.1);
195+
}
196+
Ok(Value::Map(res))
197+
}
176198
}
177-
178-
Ok(Value::Map(res))
179199
}
180200
}
181201

@@ -272,40 +292,23 @@ mod tests {
272292
])"
273293
),
274294
Value::Option(Some(Box::new(Value::Seq(vec![
275-
Value::Map(
276-
vec![
277-
(
278-
Value::String("width".to_owned()),
279-
Value::Number(Number::new(20)),
280-
),
281-
(
282-
Value::String("height".to_owned()),
283-
Value::Number(Number::new(5)),
284-
),
285-
(
286-
Value::String("name".to_owned()),
287-
Value::String("The Room".to_owned()),
288-
),
295+
Value::Struct(Struct {
296+
name: Some("Room".to_string()),
297+
fields: vec![
298+
("width".to_owned(), Value::Number(Number::new(20)),),
299+
("height".to_owned(), Value::Number(Number::new(5)),),
300+
("name".to_owned(), Value::String("The Room".to_owned()),),
289301
]
290302
.into_iter()
291303
.collect(),
292-
),
293-
Value::Map(
304+
}),
305+
Value::Struct(
294306
vec![
307+
("width".to_owned(), Value::Number(Number::new(10.0)),),
308+
("height".to_owned(), Value::Number(Number::new(10.0)),),
309+
("name".to_owned(), Value::String("Another room".to_owned()),),
295310
(
296-
Value::String("width".to_owned()),
297-
Value::Number(Number::new(10.0)),
298-
),
299-
(
300-
Value::String("height".to_owned()),
301-
Value::Number(Number::new(10.0)),
302-
),
303-
(
304-
Value::String("name".to_owned()),
305-
Value::String("Another room".to_owned()),
306-
),
307-
(
308-
Value::String("enemy_levels".to_owned()),
311+
"enemy_levels".to_owned(),
309312
Value::Map(
310313
vec![
311314
(

src/ser/value.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ impl Serialize for Value {
1111
Value::Bool(b) => serializer.serialize_bool(b),
1212
Value::Char(c) => serializer.serialize_char(c),
1313
Value::Map(ref m) => Serialize::serialize(m, serializer),
14+
Value::Struct(ref s) => Serialize::serialize(s, serializer),
1415
Value::Number(Number::Float(ref f)) => serializer.serialize_f64(f.get()),
1516
Value::Number(Number::Integer(i)) => serializer.serialize_i64(i),
1617
Value::Option(Some(ref o)) => serializer.serialize_some(o.as_ref()),

0 commit comments

Comments
 (0)