2

I have the following struct

struct S {
    value: f32,
    square: f32,
}

I would like to derive square from value in the new(value):

impl S {
    fn new(value: f32) -> Self {
        Self { value, square: value.powi(2) }
    }
}

Can I use value field only to serialize the struct and use new(value) to deserialize the whole thing without manually implementing Serialize/Deserialize traits?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
hombit
  • 131
  • 1
  • 9
  • what is the point of that? if you do that then deserialization wouldn't be safe – Daniel A. White Jul 23 '21 at 14:54
  • It looks like your question might be answered by the answers of [How to transform fields during deserialization using Serde?](https://stackoverflow.com/a/46755370/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Jul 23 '21 at 14:56
  • 2
    [The duplicate applied to your situation](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=1185c61776f1413aac08b5d28885a7d8). – Shepmaster Jul 23 '21 at 14:59
  • @DanielA.White imagine you have a JSON input in the form of `{"value": 1.23}` which should be enough to reconstruct the whole struct. Probably it is my conceptual mis-understanding, but I see no sense ask user to provide fully-constructed struct. – hombit Jul 23 '21 at 15:01
  • Ok then just use `Option` – Daniel A. White Jul 23 '21 at 15:02
  • @Stepmaster is it not about isolated field transformation, it is about deriving some fields from other ones – hombit Jul 23 '21 at 15:02
  • 1
    @hombit yes, and the [fully working example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=1185c61776f1413aac08b5d28885a7d8) I provided shows that exactly. – Shepmaster Jul 23 '21 at 15:03
  • @DanielA.White `Option` is not an option, because `square` is closely connected to the `value` – hombit Jul 23 '21 at 15:04
  • 1
    Does this answer your question? [How to transform fields during deserialization using Serde?](https://stackoverflow.com/questions/46753955/how-to-transform-fields-during-deserialization-using-serde) – Stargateur Jul 23 '21 at 15:14

1 Answers1

1

You can implement deserialization with the #[serde(from = "FromType")] attribute. If the transformation can fail, there is also the try_from attribute.

Deserialize this type by deserializing into FromType, then converting. This type must implement From<FromType>, and FromType must implement Deserialize.

Serializing a subset of fields can be achieved by applying the #[serde(skip)] annotation on the fields you want to omit.

Applied to your use case a solution looks like this:

#[derive(Debug, Serialize, Deserialize)]
#[serde(from = "DeserS")]
struct S {
    value: f32,
    #[serde(skip)]
    square: f32,
}

#[derive(Deserialize)]
struct DeserS {
    value: f32,
}

impl From<DeserS> for S {
    fn from(tmp: DeserS) -> Self {
        Self {
            value: tmp.value,
            square: tmp.value.powi(2),
        }
    }
}

Playground

jonasbb
  • 2,131
  • 1
  • 6
  • 25