Skip to content

Commit

Permalink
Merge pull request ron-rs#343 from MomoLangenstein/ron-options
Browse files Browse the repository at this point in the history
Expose `Extensions` during ser+de through `ron::Options`
  • Loading branch information
torkleyy committed Jun 6, 2022
1 parent 14e73b3 commit 3c21904
Show file tree
Hide file tree
Showing 8 changed files with 278 additions and 63 deletions.
4 changes: 0 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix issue [#289](https://github.com/ron-rs/ron/issues/289) enumerate_arrays comments ([#344](https://github.com/ron-rs/ron/pull/344))
- Report struct name in expected struct error ([#342](https://github.com/ron-rs/ron/pull/342))
- Add `Options` builder to configure the RON serde roundtrip ([#343](https://github.com/ron-rs/ron/pull/343))
- Add `compact_arrays` ([#299](https://github.com/ron-rs/ron/pull/299)) and `separator` options to `PrettyConfig` ([#349](https://github.com/ron-rs/ron/pull/349))
- Fix issue [#265](https://github.com/ron-rs/ron/issues/265) with better missing comma error ([#353](https://github.com/ron-rs/ron/pull/353))
- Fix issue [#301](https://github.com/ron-rs/ron/issues/301) with better error messages ([#354](https://github.com/ron-rs/ron/pull/354))
- Fix issue [#367](https://github.com/ron-rs/ron/issues/367) with eager implicit some ([#368](https://github.com/ron-rs/ron/pull/368))

## [0.7.0] - 2021-10-22

Expand Down
38 changes: 21 additions & 17 deletions src/de/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/// Deserialization module.
pub use crate::error::{Error, ErrorCode, Result};
pub use crate::parse::Position;
pub use crate::error::{Error, ErrorCode, Position, Result};

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

use self::{id::IdDeserializer, tag::TagDeserializer};
use crate::{
extensions::Extensions,
options::Options,
parse::{AnyNum, Bytes, ParsedStr},
};

Expand All @@ -30,14 +30,26 @@ impl<'de> Deserializer<'de> {
// Cannot implement trait here since output is tied to input lifetime 'de.
#[allow(clippy::should_implement_trait)]
pub fn from_str(input: &'de str) -> Result<Self> {
Deserializer::from_bytes(input.as_bytes())
Self::from_str_with_options(input, Options::default())
}

pub fn from_bytes(input: &'de [u8]) -> Result<Self> {
Ok(Deserializer {
Self::from_bytes_with_options(input, Options::default())
}

pub fn from_str_with_options(input: &'de str, options: Options) -> Result<Self> {
Self::from_bytes_with_options(input.as_bytes(), options)
}

pub fn from_bytes_with_options(input: &'de [u8], options: Options) -> Result<Self> {
let mut deserializer = Deserializer {
bytes: Bytes::new(input)?,
newtype_variant: false,
})
};

deserializer.bytes.exts |= options.default_extensions;

Ok(deserializer)
}

pub fn remainder(&self) -> Cow<'_, str> {
Expand All @@ -47,15 +59,12 @@ impl<'de> Deserializer<'de> {

/// A convenience function for reading data from a reader
/// and feeding into a deserializer.
pub fn from_reader<R, T>(mut rdr: R) -> Result<T>
pub fn from_reader<R, T>(rdr: R) -> Result<T>
where
R: io::Read,
T: de::DeserializeOwned,
{
let mut bytes = Vec::new();
rdr.read_to_end(&mut bytes)?;

from_bytes(&bytes)
Options::default().from_reader(rdr)
}

/// A convenience function for building a deserializer
Expand All @@ -64,7 +73,7 @@ pub fn from_str<'a, T>(s: &'a str) -> Result<T>
where
T: de::Deserialize<'a>,
{
from_bytes(s.as_bytes())
Options::default().from_str(s)
}

/// A convenience function for building a deserializer
Expand All @@ -73,12 +82,7 @@ pub fn from_bytes<'a, T>(s: &'a [u8]) -> Result<T>
where
T: de::Deserialize<'a>,
{
let mut deserializer = Deserializer::from_bytes(s)?;
let t = T::deserialize(&mut deserializer)?;

deserializer.end()?;

Ok(t)
Options::default().from_bytes(s)
}

impl<'de> Deserializer<'de> {
Expand Down
14 changes: 12 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use serde::{de, ser};
use std::{error::Error as StdError, fmt, io, str::Utf8Error, string::FromUtf8Error};

pub use crate::parse::Position;

/// This type represents all possible errors that can occur when
/// serializing or deserializing RON data.
#[derive(Clone, Debug, PartialEq)]
Expand Down Expand Up @@ -123,6 +121,18 @@ impl fmt::Display for ErrorCode {
}
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Position {
pub line: usize,
pub col: usize,
}

impl fmt::Display for Position {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.line, self.col)
}
}

impl de::Error for Error {
fn custom<T: fmt::Display>(msg: T) -> Self {
Error {
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,11 @@ pub mod value;

pub mod extensions;

pub mod options;

pub use de::{from_str, Deserializer};
pub use error::{Error, Result};
pub use options::Options;
pub use ser::{to_string, Serializer};
pub use value::{Map, Number, Value};

Expand Down
150 changes: 150 additions & 0 deletions src/options.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
//! Roundtrip serde Options module.
use std::io;

use serde::{de, ser, Deserialize, Serialize};

use crate::de::Deserializer;
use crate::error::Result;
use crate::extensions::Extensions;
use crate::ser::{PrettyConfig, Serializer};

/// Roundtrip serde options.
///
/// # Examples
///
/// ```
/// use ron::{Options, extensions::Extensions};
///
/// let ron = Options::default()
/// .with_default_extension(Extensions::IMPLICIT_SOME);
///
/// let de: Option<i32> = ron.from_str("42").unwrap();
/// let ser = ron.to_string(&de).unwrap();
///
/// assert_eq!(ser, "42");
/// ```
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct Options {
/// Extensions that are enabled by default during serialization and
/// deserialization.
/// During serialization, these extensions do NOT have to be explicitly
/// enabled in the parsed RON.
/// During deserialization, these extensions are used, but their explicit
/// activation is NOT included in the output RON.
/// No extensions are enabled by default.
pub default_extensions: Extensions,
/// Private field to ensure adding a field is non-breaking.
#[serde(skip)]
_future_proof: (),
}

impl Default for Options {
fn default() -> Self {
Self {
default_extensions: Extensions::empty(),
_future_proof: (),
}
}
}

impl Options {
#[must_use]
/// Enable `default_extension` by default during serialization and deserialization.
pub fn with_default_extension(mut self, default_extension: Extensions) -> Self {
self.default_extensions |= default_extension;
self
}

#[must_use]
/// Do NOT enable `default_extension` by default during serialization and deserialization.
pub fn without_default_extension(mut self, default_extension: Extensions) -> Self {
self.default_extensions &= !default_extension;
self
}
}

impl Options {
/// A convenience function for reading data from a reader
/// and feeding into a deserializer.
pub fn from_reader<R, T>(&self, mut rdr: R) -> Result<T>
where
R: io::Read,
T: de::DeserializeOwned,
{
let mut bytes = Vec::new();
rdr.read_to_end(&mut bytes)?;

self.from_bytes(&bytes)
}

/// A convenience function for building a deserializer
/// and deserializing a value of type `T` from a string.
pub fn from_str<'a, T>(&self, s: &'a str) -> Result<T>
where
T: de::Deserialize<'a>,
{
self.from_bytes(s.as_bytes())
}

/// A convenience function for building a deserializer
/// and deserializing a value of type `T` from bytes.
pub fn from_bytes<'a, T>(&self, s: &'a [u8]) -> Result<T>
where
T: de::Deserialize<'a>,
{
let mut deserializer = Deserializer::from_bytes_with_options(s, self.clone())?;

let value = T::deserialize(&mut deserializer)?;

deserializer.end()?;

Ok(value)
}

/// Serializes `value` into `writer`
pub fn to_writer<W, T>(&self, writer: W, value: &T) -> Result<()>
where
W: io::Write,
T: ?Sized + ser::Serialize,
{
let mut s = Serializer::with_options(writer, None, self.clone())?;
value.serialize(&mut s)
}

/// Serializes `value` into `writer` in a pretty way.
pub fn to_writer_pretty<W, T>(&self, writer: W, value: &T, config: PrettyConfig) -> Result<()>
where
W: io::Write,
T: ?Sized + ser::Serialize,
{
let mut s = Serializer::with_options(writer, Some(config), self.clone())?;
value.serialize(&mut s)
}

/// Serializes `value` and returns it as string.
///
/// This function does not generate any newlines or nice formatting;
/// if you want that, you can use `to_string_pretty` instead.
pub fn to_string<T>(&self, value: &T) -> Result<String>
where
T: ?Sized + ser::Serialize,
{
let mut output = Vec::new();
let mut s = Serializer::with_options(&mut output, None, self.clone())?;
value.serialize(&mut s)?;
Ok(String::from_utf8(output).expect("Ron should be utf-8"))
}

/// Serializes `value` in the recommended RON layout in a pretty way.
pub fn to_string_pretty<T>(&self, value: &T, config: PrettyConfig) -> Result<String>
where
T: ?Sized + ser::Serialize,
{
let mut output = Vec::new();
let mut s = Serializer::with_options(&mut output, Some(config), self.clone())?;
value.serialize(&mut s)?;
Ok(String::from_utf8(output).expect("Ron should be utf-8"))
}
}
15 changes: 1 addition & 14 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

use std::{
char::from_u32 as char_from_u32,
fmt::{Display, Formatter, Result as FmtResult},
str::{from_utf8, from_utf8_unchecked, FromStr},
};

use crate::{
error::{Error, ErrorCode, Result},
error::{Error, ErrorCode, Position, Result},
extensions::Extensions,
};

Expand Down Expand Up @@ -952,18 +951,6 @@ pub enum ParsedStr<'a> {
Slice(&'a str),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Position {
pub line: usize,
pub col: usize,
}

impl Display for Position {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "{}:{}", self.line, self.col)
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading

0 comments on commit 3c21904

Please sign in to comment.