Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose Extensions during ser+de through ron::Options #343

Merged
merged 4 commits into from
Dec 3, 2021
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix issue [#338](https://github.com/ron-rs/ron/issues/338) value map roundtrip ([#341](https://github.com/ron-rs/ron/pull/341))
- 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))

## [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 @@ -115,6 +113,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 {
torkleyy marked this conversation as resolved.
Show resolved Hide resolved
/// 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 @@ -922,18 +921,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