#Diffing a struct and its default values to JSON

12 messages · Page 1 of 1 (latest)

plush surge
#

I'm writing a config file handler for an application where I have a config struct with default values through a default implementation. The configs are written to disk in JSON, but I only want to write values that are different from the defaults to disk. Is there a way to extract only the different values and write them out as JSON? I found serde_diff but it doesn't appear to have a way to do this directly.

jagged ridge
#

#[serde(skip_serializing_if = "ne_default")] on the field, with ```rs
fn ne_default<T: PartialEq + Default>(val: &T) -> bool {
val != T::default()
}

#

assuming the default value of the field is given by the trait Default

#

otherwise use a different function

plush surge
jagged ridge
# plush surge Is there a way to skip serialization only when performing a certain function? I ...

You could have a newtype wrapper that implements Serialize, something like: ```rs
struct MyType {
a: String,
b: u32,
c: f64,
}
impl MyType {
fn serialize(&self, skip_defaults: bool) -> Serialize<'_> {
Serialize {
inner: self,
skip_defaults,
}
}
}

struct Serialize<'inner> {
inner: &'inner MyType,
skip_defaults: bool,
}

impl serde::Serialize for Serialize<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let serializer = serializer.serialize_struct("MyType", 3)?;
if !(self.skip_defaults && self.inner.a == "default_string") {
serializer.serialize_field("a", self.inner.a)?;
}
if !(self.skip_defaults && self.inner.b == 0) {
serializer.serialize_field("b", self.inner.b)?;
}
serializer.serialize_field("c", self.inner.c)?;
serializer.end()
}
}

#

might get boilerplately though

plush surge
jagged ridge
#

Wait, it could be made nicer with some traits

#
pub trait SerializeConfig<Config> {
    fn serialize_config<S: Serializer>(&self, config: &Config) -> Result<S::Ok, S::Error>;

    fn serialize_with<'this, 'config>(&'this self, config: &'config Config) -> SerializeWith<'this, 'config, Self, Config>;
}

pub struct SerializeWith<'this, 'config, T, Config> {
    this: &'this T,
    config: &'config Config,
}
// impl Serialize for SerializeWith
#

^ the use of that trait will reduce boilerplate a lot