Skip to content

Commit

Permalink
Add path-based field metadata serialisation support (#544)
Browse files Browse the repository at this point in the history
* Add provisional metadata ser in named field pos

* Use hierarchy to fix collision; fix multiline indent bug

* Add CHANGELOG.md entry

* Touch up on API, add some docs, fix inline call to indent

* Change let .. else to iterator

* Add build_fields as ergonomic shortcut

* Remove expect, use collect, add must_use

* Add test file with named field struct hierarchy test

* Touch up on API, add doctests

* Add meta with newline to test file

* Apply clippy lints

* Remove is_some_and, wrap meta, add tuple to test

* Make indent take mutable reference, make method a wrapper

---------

Co-authored-by: Juniper Tyree <[email protected]>
  • Loading branch information
voidentente and juntyr authored Sep 25, 2024
1 parent 761bfc6 commit ea6b406
Show file tree
Hide file tree
Showing 4 changed files with 539 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Breaking: Enforce that ron always writes valid UTF-8 ([#488](https://github.com/ron-rs/ron/pull/488))
- Add convenient `Value::from` impls ([#498](https://github.com/ron-rs/ron/pull/498))
- Add new extension `explicit_struct_names` which requires that struct names are included during deserialization ([#522](https://github.com/ron-rs/ron/pull/522))
- Add new path-based field metadata serialization support via `PrettyConfig` ([#544](https://github.com/ron-rs/ron/pull/544))
- Breaking: Change `PrettyConfig` so that `new_line`, `indentor` and `separator` are all `Cow<'static, str>` instead of `String` ([#546](https://github.com/ron-rs/ron/pull/546))

### Format Changes
Expand Down
55 changes: 49 additions & 6 deletions src/ser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use crate::{
parse::{is_ident_first_char, is_ident_raw_char, is_whitespace_char, LargeSInt, LargeUInt},
};

pub mod path_meta;

mod raw;
#[cfg(test)]
mod tests;
Expand Down Expand Up @@ -109,6 +111,8 @@ pub struct PrettyConfig {
pub compact_maps: bool,
/// Enable explicit number type suffixes like `1u16`
pub number_suffixes: bool,
/// Additional path-based field metadata to serialize
pub path_meta: Option<path_meta::Field>,
}

impl PrettyConfig {
Expand Down Expand Up @@ -359,6 +363,7 @@ impl Default for PrettyConfig {
compact_structs: false,
compact_maps: false,
number_suffixes: false,
path_meta: None,
}
}
}
Expand All @@ -378,6 +383,15 @@ pub struct Serializer<W: fmt::Write> {
implicit_some_depth: usize,
}

fn indent<W: fmt::Write>(output: &mut W, config: &PrettyConfig, pretty: &Pretty) -> fmt::Result {
if pretty.indent <= config.depth_limit {
for _ in 0..pretty.indent {
output.write_str(&config.indentor)?;
}
}
Ok(())
}

impl<W: fmt::Write> Serializer<W> {
/// Creates a new [`Serializer`].
///
Expand Down Expand Up @@ -491,11 +505,7 @@ impl<W: fmt::Write> Serializer<W> {

fn indent(&mut self) -> fmt::Result {
if let Some((ref config, ref pretty)) = self.pretty {
if pretty.indent <= config.depth_limit {
for _ in 0..pretty.indent {
self.output.write_str(&config.indentor)?;
}
}
indent(&mut self.output, config, pretty)?;
}
Ok(())
}
Expand Down Expand Up @@ -1313,6 +1323,15 @@ impl<'a, W: fmt::Write> ser::SerializeStruct for Compound<'a, W> {
where
T: ?Sized + Serialize,
{
let mut restore_field = self.ser.pretty.as_mut().and_then(|(config, _)| {
config.path_meta.take().map(|mut field| {
if let Some(fields) = field.fields_mut() {
config.path_meta = fields.remove(key);
}
field
})
});

if let State::First = self.state {
self.state = State::Rest;
} else {
Expand All @@ -1328,7 +1347,18 @@ impl<'a, W: fmt::Write> ser::SerializeStruct for Compound<'a, W> {
}

if !self.ser.compact_structs() {
self.ser.indent()?;
if let Some((ref config, ref pretty)) = self.ser.pretty {
indent(&mut self.ser.output, config, pretty)?;

if let Some(ref field) = config.path_meta {
for doc_line in field.doc().lines() {
self.ser.output.write_str("/// ")?;
self.ser.output.write_str(doc_line)?;
self.ser.output.write_char('\n')?;
indent(&mut self.ser.output, config, pretty)?;
}
}
}
}

self.ser.write_identifier(key)?;
Expand All @@ -1340,6 +1370,18 @@ impl<'a, W: fmt::Write> ser::SerializeStruct for Compound<'a, W> {

guard_recursion! { self.ser => value.serialize(&mut *self.ser)? };

if let Some((ref mut config, _)) = self.ser.pretty {
std::mem::swap(&mut config.path_meta, &mut restore_field);

if let Some(ref mut field) = config.path_meta {
if let Some(fields) = field.fields_mut() {
if let Some(restore_field) = restore_field {
fields.insert(key, restore_field);
}
}
}
};

Ok(())
}

Expand All @@ -1360,6 +1402,7 @@ impl<'a, W: fmt::Write> ser::SerializeStruct for Compound<'a, W> {
if !self.newtype_variant {
self.ser.output.write_char(')')?;
}

Ok(())
}
}
Expand Down
Loading

0 comments on commit ea6b406

Please sign in to comment.