Skip to content

Commit 91fdaf1

Browse files
committed
Add Value::to_string{,pretty} methods that preserve structs
1 parent 3669ecf commit 91fdaf1

File tree

6 files changed

+137
-20
lines changed

6 files changed

+137
-20
lines changed

src/de/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
/// Deserialization module.
22
pub use crate::error::{Error, ErrorCode, Result};
33
pub use crate::parse::Position;
4-
use crate::{Map, Value};
54

65
use serde::de::{self, DeserializeSeed, Deserializer as SerdeError, Visitor};
76
use std::cell::RefCell;

src/error.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ impl fmt::Display for ErrorCode {
106106
ErrorCode::UnderscoreAtBeginning => f.write_str("Found underscore at the beginning"),
107107
ErrorCode::UnexpectedByte(_) => f.write_str("Unexpected byte"),
108108
ErrorCode::TrailingCharacters => f.write_str("Non-whitespace trailing characters"),
109-
_ => f.write_str("Unknown ErrorCode"),
110109
}
111110
}
112111
}

src/ser/mod.rs

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use serde::{ser, Deserialize, Serialize};
22
use std::io;
33

4+
use crate::Value;
45
use crate::{
56
error::{Error, Result},
67
extensions::Extensions,
@@ -56,6 +57,22 @@ where
5657
Ok(String::from_utf8(s.output).expect("Ron should be utf-8"))
5758
}
5859

60+
impl Value {
61+
pub fn to_string(&self) -> Result<String> {
62+
let buf = Vec::new();
63+
let mut s = Serializer::new(buf, None)?;
64+
self.enhanced_serialize(&mut s)?;
65+
Ok(String::from_utf8(s.output).expect("Ron should be utf-8"))
66+
}
67+
68+
pub fn to_string_pretty(&self, config: PrettyConfig) -> Result<String> {
69+
let buf = Vec::new();
70+
let mut s = Serializer::new(buf, Some(config))?;
71+
self.enhanced_serialize(&mut s)?;
72+
Ok(String::from_utf8(s.output).expect("Ron should be utf-8"))
73+
}
74+
}
75+
5976
/// Pretty serializer state
6077
struct Pretty {
6178
indent: usize,
@@ -86,7 +103,7 @@ pub struct PrettyConfig {
86103
/// Indentation string
87104
#[serde(default = "default_indentor")]
88105
pub indentor: String,
89-
// Whether to emit struct names
106+
/// Whether to emit struct names
90107
#[serde(default = "default_struct_names")]
91108
pub struct_names: bool,
92109
/// Separate tuple members with indentation
@@ -368,6 +385,21 @@ impl<W: io::Write> Serializer<W> {
368385
.map(|(pc, _)| pc.struct_names)
369386
.unwrap_or(false)
370387
}
388+
389+
fn serialize_struct_dyn<'b>(&mut self, name: &'b str, len: usize) -> Result<Compound<W>> {
390+
if self.struct_names() {
391+
self.write_identifier(name)?;
392+
}
393+
self.output.write_all(b"(")?;
394+
395+
self.is_empty = Some(len == 0);
396+
self.start_indent()?;
397+
398+
Ok(Compound {
399+
ser: self,
400+
state: State::First,
401+
})
402+
}
371403
}
372404

373405
impl<'a, W: io::Write> ser::Serializer for &'a mut Serializer<W> {
@@ -631,18 +663,7 @@ impl<'a, W: io::Write> ser::Serializer for &'a mut Serializer<W> {
631663
}
632664

633665
fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
634-
if self.struct_names() {
635-
self.write_identifier(name)?;
636-
}
637-
self.output.write_all(b"(")?;
638-
639-
self.is_empty = Some(len == 0);
640-
self.start_indent()?;
641-
642-
Ok(Compound {
643-
ser: self,
644-
state: State::First,
645-
})
666+
self.serialize_struct_dyn(name, len)
646667
}
647668

648669
fn serialize_struct_variant(
@@ -866,6 +887,33 @@ impl<'a, W: io::Write> ser::SerializeMap for Compound<'a, W> {
866887
}
867888
}
868889

890+
impl<'a, W: io::Write> Compound<'a, W> {
891+
fn serialize_field_dyn(&mut self, key: &str, value: &Value) -> Result<()> {
892+
if let State::First = self.state {
893+
self.state = State::Rest;
894+
} else {
895+
self.ser.output.write_all(b",")?;
896+
897+
if let Some((ref config, ref pretty)) = self.ser.pretty {
898+
if pretty.indent <= config.depth_limit {
899+
self.ser.output.write_all(config.new_line.as_bytes())?;
900+
}
901+
}
902+
}
903+
self.ser.indent()?;
904+
self.ser.write_identifier(key)?;
905+
self.ser.output.write_all(b":")?;
906+
907+
if self.ser.is_pretty() {
908+
self.ser.output.write_all(b" ")?;
909+
}
910+
911+
value.serialize(&mut *self.ser)?;
912+
913+
Ok(())
914+
}
915+
}
916+
869917
impl<'a, W: io::Write> ser::SerializeStruct for Compound<'a, W> {
870918
type Error = Error;
871919
type Ok = ();

src/ser/tests.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
use super::to_string;
2+
use crate::ser::PrettyConfig;
3+
use crate::value::Struct;
4+
use crate::{Number, Value};
25
use serde::Serialize;
36

47
#[derive(Serialize)]
@@ -144,3 +147,21 @@ fn rename() {
144147
assert_eq!(to_string(&Foo::D2).unwrap(), "r#2d");
145148
assert_eq!(to_string(&Foo::TriangleList).unwrap(), "r#triangle-list");
146149
}
150+
151+
#[test]
152+
fn test_value_to_string() {
153+
assert_eq!(
154+
Value::Struct(Struct {
155+
name: Some("Point".to_owned()),
156+
fields: [
157+
("x".to_owned(), Value::Number(Number::from(16.3))),
158+
("y".to_owned(), Value::Number(Number::from(3.3))),
159+
]
160+
.iter()
161+
.cloned()
162+
.collect()
163+
})
164+
.to_string_pretty(PrettyConfig::default().struct_names(true)),
165+
Ok("Point(\n x: 16.3,\n y: 3.3,\n)".to_string())
166+
)
167+
}

src/ser/value.rs

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
use serde::ser::{Serialize, Serializer};
1+
use std::io;
2+
3+
use serde::ser::{Serialize, SerializeMap, SerializeSeq, SerializeStruct, Serializer};
24

35
use crate::value::{Number, Value};
6+
use crate::{Error, Map};
47

58
impl Serialize for Value {
69
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@@ -11,7 +14,14 @@ impl Serialize for Value {
1114
Value::Bool(b) => serializer.serialize_bool(b),
1215
Value::Char(c) => serializer.serialize_char(c),
1316
Value::Map(ref m) => Serialize::serialize(m, serializer),
14-
Value::Struct(ref s) => Serialize::serialize(s, serializer),
17+
Value::Struct(ref s) => Serialize::serialize(
18+
&Map(s
19+
.fields
20+
.iter()
21+
.map(|(k, v)| (Value::String(k.clone()), v.clone()))
22+
.collect()),
23+
serializer,
24+
),
1525
Value::Number(Number::Float(ref f)) => serializer.serialize_f64(f.get()),
1626
Value::Number(Number::Integer(i)) => serializer.serialize_i64(i),
1727
Value::Option(Some(ref o)) => serializer.serialize_some(o.as_ref()),
@@ -22,3 +32,43 @@ impl Serialize for Value {
2232
}
2333
}
2434
}
35+
36+
impl Value {
37+
pub fn enhanced_serialize<W: io::Write>(
38+
&self,
39+
serializer: &mut crate::ser::Serializer<W>,
40+
) -> Result<(), Error> {
41+
match *self {
42+
Value::Bool(b) => serializer.serialize_bool(b),
43+
Value::Char(c) => serializer.serialize_char(c),
44+
Value::Map(ref m) => {
45+
let mut map = serializer.serialize_map(Some(m.len()))?;
46+
for (k, v) in m.iter() {
47+
map.serialize_entry(k, v)?;
48+
}
49+
SerializeMap::end(map)
50+
}
51+
Value::Struct(ref s) => {
52+
let mut c = serializer
53+
.serialize_struct_dyn(s.name.as_deref().unwrap_or(""), s.fields.len())?;
54+
for (field, value) in s.iter() {
55+
c.serialize_field_dyn(field.as_ref(), value)?;
56+
}
57+
SerializeStruct::end(c)
58+
}
59+
Value::Number(Number::Float(ref f)) => serializer.serialize_f64(f.get()),
60+
Value::Number(Number::Integer(i)) => serializer.serialize_i64(i),
61+
Value::Option(Some(ref o)) => serializer.serialize_some(o.as_ref()),
62+
Value::Option(None) => serializer.serialize_none(),
63+
Value::String(ref s) => serializer.serialize_str(s),
64+
Value::Seq(ref s) => {
65+
let mut seq = serializer.serialize_seq(Some(s.len()))?;
66+
for v in s.iter() {
67+
seq.serialize_element(v)?;
68+
}
69+
SerializeSeq::end(seq)
70+
}
71+
Value::Unit => serializer.serialize_unit(),
72+
}
73+
}
74+
}

src/value.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::de::{Error as RonError, Result};
2323
/// The latter can be used by enabling the `indexmap` feature. This can be used
2424
/// to preserve the order of the parsed map.
2525
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
26-
pub struct Map(MapInner);
26+
pub struct Map(pub MapInner);
2727

2828
impl Map {
2929
/// Creates a new, empty `Map`.
@@ -160,8 +160,8 @@ impl Struct {
160160
}
161161

162162
/// Returns `true` if `self.len() == 0`, `false` otherwise.
163-
pub fn is_empty(&self) -> usize {
164-
self.fields.len()
163+
pub fn is_empty(&self) -> bool {
164+
self.fields.is_empty()
165165
}
166166

167167
/// Inserts a new element, returning the previous element with this `key` if

0 commit comments

Comments
 (0)