Skip to content

Commit

Permalink
Add Value::to_string{,pretty} methods that preserve structs
Browse files Browse the repository at this point in the history
  • Loading branch information
cswinter committed Oct 28, 2021
1 parent 3669ecf commit 91fdaf1
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 20 deletions.
1 change: 0 additions & 1 deletion src/de/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/// Deserialization module.
pub use crate::error::{Error, ErrorCode, Result};
pub use crate::parse::Position;
use crate::{Map, Value};

use serde::de::{self, DeserializeSeed, Deserializer as SerdeError, Visitor};
use std::cell::RefCell;
Expand Down
1 change: 0 additions & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,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
74 changes: 61 additions & 13 deletions src/ser/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use serde::{ser, Deserialize, Serialize};
use std::io;

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

impl Value {
pub fn to_string(&self) -> Result<String> {
let buf = Vec::new();
let mut s = Serializer::new(buf, None)?;
self.enhanced_serialize(&mut s)?;
Ok(String::from_utf8(s.output).expect("Ron should be utf-8"))
}

pub fn to_string_pretty(&self, config: PrettyConfig) -> Result<String> {
let buf = Vec::new();
let mut s = Serializer::new(buf, Some(config))?;
self.enhanced_serialize(&mut s)?;
Ok(String::from_utf8(s.output).expect("Ron should be utf-8"))
}
}

/// Pretty serializer state
struct Pretty {
indent: usize,
Expand Down Expand Up @@ -86,7 +103,7 @@ pub struct PrettyConfig {
/// Indentation string
#[serde(default = "default_indentor")]
pub indentor: String,
// Whether to emit struct names
/// Whether to emit struct names
#[serde(default = "default_struct_names")]
pub struct_names: bool,
/// Separate tuple members with indentation
Expand Down Expand Up @@ -368,6 +385,21 @@ impl<W: io::Write> Serializer<W> {
.map(|(pc, _)| pc.struct_names)
.unwrap_or(false)
}

fn serialize_struct_dyn<'b>(&mut self, name: &'b str, len: usize) -> Result<Compound<W>> {
if self.struct_names() {
self.write_identifier(name)?;
}
self.output.write_all(b"(")?;

self.is_empty = Some(len == 0);
self.start_indent()?;

Ok(Compound {
ser: self,
state: State::First,
})
}
}

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

fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
if self.struct_names() {
self.write_identifier(name)?;
}
self.output.write_all(b"(")?;

self.is_empty = Some(len == 0);
self.start_indent()?;

Ok(Compound {
ser: self,
state: State::First,
})
self.serialize_struct_dyn(name, len)
}

fn serialize_struct_variant(
Expand Down Expand Up @@ -866,6 +887,33 @@ impl<'a, W: io::Write> ser::SerializeMap for Compound<'a, W> {
}
}

impl<'a, W: io::Write> Compound<'a, W> {
fn serialize_field_dyn(&mut self, key: &str, value: &Value) -> Result<()> {
if let State::First = self.state {
self.state = State::Rest;
} else {
self.ser.output.write_all(b",")?;

if let Some((ref config, ref pretty)) = self.ser.pretty {
if pretty.indent <= config.depth_limit {
self.ser.output.write_all(config.new_line.as_bytes())?;
}
}
}
self.ser.indent()?;
self.ser.write_identifier(key)?;
self.ser.output.write_all(b":")?;

if self.ser.is_pretty() {
self.ser.output.write_all(b" ")?;
}

value.serialize(&mut *self.ser)?;

Ok(())
}
}

impl<'a, W: io::Write> ser::SerializeStruct for Compound<'a, W> {
type Error = Error;
type Ok = ();
Expand Down
21 changes: 21 additions & 0 deletions src/ser/tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use super::to_string;
use crate::ser::PrettyConfig;
use crate::value::Struct;
use crate::{Number, Value};
use serde::Serialize;

#[derive(Serialize)]
Expand Down Expand Up @@ -144,3 +147,21 @@ fn rename() {
assert_eq!(to_string(&Foo::D2).unwrap(), "r#2d");
assert_eq!(to_string(&Foo::TriangleList).unwrap(), "r#triangle-list");
}

#[test]
fn test_value_to_string() {
assert_eq!(
Value::Struct(Struct {
name: Some("Point".to_owned()),
fields: [
("x".to_owned(), Value::Number(Number::from(16.3))),
("y".to_owned(), Value::Number(Number::from(3.3))),
]
.iter()
.cloned()
.collect()
})
.to_string_pretty(PrettyConfig::default().struct_names(true)),
Ok("Point(\n x: 16.3,\n y: 3.3,\n)".to_string())
)
}
54 changes: 52 additions & 2 deletions src/ser/value.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use serde::ser::{Serialize, Serializer};
use std::io;

use serde::ser::{Serialize, SerializeMap, SerializeSeq, SerializeStruct, Serializer};

use crate::value::{Number, Value};
use crate::{Error, Map};

impl Serialize for Value {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
Expand All @@ -11,7 +14,14 @@ impl Serialize for Value {
Value::Bool(b) => serializer.serialize_bool(b),
Value::Char(c) => serializer.serialize_char(c),
Value::Map(ref m) => Serialize::serialize(m, serializer),
Value::Struct(ref s) => Serialize::serialize(s, serializer),
Value::Struct(ref s) => Serialize::serialize(
&Map(s
.fields
.iter()
.map(|(k, v)| (Value::String(k.clone()), v.clone()))
.collect()),
serializer,
),
Value::Number(Number::Float(ref f)) => serializer.serialize_f64(f.get()),
Value::Number(Number::Integer(i)) => serializer.serialize_i64(i),
Value::Option(Some(ref o)) => serializer.serialize_some(o.as_ref()),
Expand All @@ -22,3 +32,43 @@ impl Serialize for Value {
}
}
}

impl Value {
pub fn enhanced_serialize<W: io::Write>(
&self,
serializer: &mut crate::ser::Serializer<W>,
) -> Result<(), Error> {
match *self {
Value::Bool(b) => serializer.serialize_bool(b),
Value::Char(c) => serializer.serialize_char(c),
Value::Map(ref m) => {
let mut map = serializer.serialize_map(Some(m.len()))?;
for (k, v) in m.iter() {
map.serialize_entry(k, v)?;
}
SerializeMap::end(map)
}
Value::Struct(ref s) => {
let mut c = serializer
.serialize_struct_dyn(s.name.as_deref().unwrap_or(""), s.fields.len())?;
for (field, value) in s.iter() {
c.serialize_field_dyn(field.as_ref(), value)?;
}
SerializeStruct::end(c)
}
Value::Number(Number::Float(ref f)) => serializer.serialize_f64(f.get()),
Value::Number(Number::Integer(i)) => serializer.serialize_i64(i),
Value::Option(Some(ref o)) => serializer.serialize_some(o.as_ref()),
Value::Option(None) => serializer.serialize_none(),
Value::String(ref s) => serializer.serialize_str(s),
Value::Seq(ref s) => {
let mut seq = serializer.serialize_seq(Some(s.len()))?;
for v in s.iter() {
seq.serialize_element(v)?;
}
SerializeSeq::end(seq)
}
Value::Unit => serializer.serialize_unit(),
}
}
}
6 changes: 3 additions & 3 deletions src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::de::{Error as RonError, Result};
/// The latter can be used by enabling the `indexmap` feature. This can be used
/// to preserve the order of the parsed map.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Map(MapInner);
pub struct Map(pub MapInner);

impl Map {
/// Creates a new, empty `Map`.
Expand Down Expand Up @@ -160,8 +160,8 @@ impl Struct {
}

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

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

0 comments on commit 91fdaf1

Please sign in to comment.