Serde - deserialization from various sources

Hello.
I have two inputs(sources) - files: JSON and XLSX. I want an object (structure) in the output.
I don't want to create two different structures for deserialization.
I would like to use different functions depending on the type of input (JSON object / XLSX row).
How to do it?

Can deserialize_with be used for this?

Please help me.

Used crates:

/// Xlsx Row
#[derive(Serialize, Deserialize, Clone, Debug, Default, Hash, PartialEq, Eq)]
pub struct VarDef
{
  #[serde(deserialize_with = "de_u8")]
  #[serde(rename = "SLAVE_ID")]
  pub slave_id: MbSlaveId,
  #[serde(deserialize_with = "de_reg_type")]
  #[serde(rename = "REG_TYPE")]
  pub reg_type: RegisterType,
  #[serde(deserialize_with = "de_u16")]
  #[serde(rename = "REG_OFFSET")]
  pub reg_offset: u16,
  #[serde(deserialize_with = "de_u16")]
  #[serde(rename = "REG_COUNT")]
  pub reg_count: u16,
  #[serde(deserialize_with = "de_reg_endianness")]
  #[serde(rename = "REG_ENDIAN")]
  pub reg_endian: Endianness,
 }

// JSON
 #[derive(Serialize, Deserialize, Clone, Debug, Default, Hash, PartialEq, Eq)]
 pub struct VarDef
 {
   pub slave_id: MbSlaveId,
   pub reg_type: RegisterType,
   pub reg_offset: u16,
   pub reg_count: u16,
   pub reg_endian: Endianness,
 }

You can certainly support deserializing from different structures. The derived Deserialize implementation for example supports both forms:

struct S {
    a: bool,
    b: usize,
}
// JSON List
[false, 123]
// JSON Map
{"a": false, "b": 123}

One way to achieve that is to try different formats and using the first, which deserializes without error. Another way is to implement a visitor, which supports multiple formats.

Maybe you want to only support one exact form and error on anything else. In that case there is nothing simple. You can branch on a thread local (set to either JSON or XLSX) or maybe is_human_readable.

You only mention deserialization, but your code also contains Serialize. If you want to support different forms there too, only the thread local seems useful.

What works best probably depends on how different the formats are and how much you want to derive or implement manually. But your post is missing quite some detail there, for example, what the de_* functions do.

If the only difference is the field names, the alias attribute should work well: Field attributes · Serde

Deserialize this field from the given name or from its Rust name. May be repeated to specify multiple possible names for the same field.