media-io / yaserde

Yet Another Serializer/Deserializer
MIT License
175 stars 57 forks source link

Add documentation for skip_serializing_if / skip_serializing_if is not triggered for enums #139

Open mracsko opened 2 years ago

mracsko commented 2 years ago

Currently I try to set up skip_serializing_if, but I could not make it work. In the examples I saw some ways to do it, but it still serialize the values. Can you provide some details about usage of this field?

mracsko commented 2 years ago

I have looked into more details and I was checking test cases. It looks like that skip does not work with enum:

use yaserde_derive::YaSerialize;

#[derive(YaSerialize, PartialEq, Debug)]
enum Enum {
    Enum1,
    Enum2,
}

#[derive(YaSerialize, PartialEq, Debug)]
struct Struct {
    #[yaserde(skip_serializing_if = "check_bool")]
    bool_value: bool,
    #[yaserde(skip_serializing_if = "check_string")]
    string_value: String,
    #[yaserde(skip_serializing_if = "check_i32")]
    i32_value: i32,
    #[yaserde(skip_serializing_if = "check_optional_string")]
    optional_string_value: Option<String>,
    #[yaserde(skip_serializing_if = "check_enum")]
    enum_value: Enum,
}

impl Struct {
    fn check_bool(&self, value: &bool) -> bool {
        value == &false
    }

    fn check_string(&self, value: &str) -> bool {
        value == "skip"
    }

    fn check_i32(&self, value: &i32) -> bool {
        value < &10
    }

    fn check_optional_string(&self, value: &Option<String>) -> bool {
        value == &Some("skip".to_string())
    }

    fn check_enum(&self, value: &Enum) -> bool {
        value == &Enum::Enum1
    }
}

fn main() {
    let obj_no_skip = Struct {
        bool_value: true,
        string_value: "testString".to_string(),
        i32_value: 10,
        optional_string_value: Some("optionalTestString".to_string()),
        enum_value: Enum::Enum2,
    };

    let obj_skip_all = Struct {
        bool_value: false,
        string_value: "skip".to_string(),
        i32_value: 9,
        optional_string_value: Some("skip".to_string()),
        enum_value: Enum::Enum1,
    };

    let yaserde_cfg = yaserde::ser::Config::default();

    assert_eq!("<?xml version=\"1.0\" encoding=\"utf-8\"?><Struct><bool_value>true</bool_value><string_value>testString</string_value><i32_value>10</i32_value><optional_string_value>optionalTestString</optional_string_value><enum_value>Enum2</enum_value></Struct>", yaserde::ser::to_string_with_config(&obj_no_skip, &yaserde_cfg).ok().unwrap());
    assert_eq!("<?xml version=\"1.0\" encoding=\"utf-8\"?><Struct></Struct>", yaserde::ser::to_string_with_config(&obj_skip_all, &yaserde_cfg).ok().unwrap());
}

Second assert fails with:

thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `"<?xml version=\"1.0\" encoding=\"utf-8\"?><Struct></Struct>"`,
 right: `"<?xml version=\"1.0\" encoding=\"utf-8\"?><Struct><enum_value>Enum1</enum_value></Struct>"`', src\main.rs:65:5

bug

After more investigation, it looks like that the skip is not called for enum fields at all. This is visible if we add println! for all checks:

impl Struct {
    fn check_bool(&self, value: &bool) -> bool {
        println!("Running 'check_bool'");
        value == &false
    }

    fn check_string(&self, value: &str) -> bool {
        println!("Running 'check_string'");
        value == "skip"
    }

    fn check_i32(&self, value: &i32) -> bool {
        println!("Running 'check_i32'");
        value < &10
    }

    fn check_optional_string(&self, value: &Option<String>) -> bool {
        println!("Running 'check_optional_string'");
        value == &Some("skip".to_string())
    }

    fn check_enum(&self, value: &Enum) -> bool {
        println!("Running 'check_enum'");
        value == &Enum::Enum1
    }
}

Output for the previous example:

Running 'check_bool'
Running 'check_string'
Running 'check_i32'
Running 'check_optional_string'
Running 'check_bool'
Running 'check_string'
Running 'check_i32'
Running 'check_optional_string'
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `"<?xml version=\"1.0\" encoding=\"utf-8\"?><Struct></Struct>"`,
 right: `"<?xml version=\"1.0\" encoding=\"utf-8\"?><Struct><enum_value>Enum1</enum_value></Struct>"`', src\main.rs:70:5

It is visible that all functions are called, except check_enum.

mracsko commented 2 years ago

Pull request is created for improved documentation, but feedback is required regarding the above mentioned bug.

lbenini commented 1 year ago

Please note that with the merge of #153 this issue is now solved and the code works as expected with just a small correction

assert_eq!("<?xml version=\"1.0\" encoding=\"utf-8\"?><Struct />", yaserde::ser::to_string_with_config(&obj_skip_all, &yaserde_cfg).ok().unwrap());

because an empty element is serialized by yaserde in self-closing mode