Serde multiple adjactent tags

I am receiving web socket content that has the tag of "type" but the content can either be data
or just d

eg:

{
  type: "ORDER_BOOK",
  data: {....}
}

and

{
  type: "ORDER_BOOK_COMP",
  d: {....}
}

is there a way to add an alias to the content tag?

#[derive(Deserialize, Debug,)]
#[serde(tag="type", content="d/data")]
pub enum WsMessage {
  #[serde(rename = "ORDER_BOOK_COMP")]
    OrderbookComp(Orderbook),
  #[serde(rename = "ORDER_BOOK")]
    Orderbook(Orderbook)
}

Obviously content="d/data" does not work,
or can a struct be used as the content value where an alias dcan be used for data?

Thanks
Phill

Yeah, I couldn't find another way to do it other than just deserializing it manually Field attributes · Serde

Since both cases are OrderBook you could just have a struct of:

struct Foo {
    d: Option<OrderBook>,
    data: Option<OrderBook>,
}

Without much complications

You could (ab)use deserialize_with to trick serde into deserializing from either d or data and then unwrap it into your Orderbook

#[derive(Deserialize, Debug)]
#[serde(tag = "type")]
pub enum WsMessage {
    #[serde(rename = "ORDER_BOOK_COMP", deserialize_with = "content_hack")]
    OrderbookComp(Orderbook),
    #[serde(rename = "ORDER_BOOK", deserialize_with = "content_hack")]
    Orderbook(Orderbook),
}

#[derive(Deserialize, Debug)]
pub struct Orderbook {
    foo: i32,
}

fn content_hack<'de, D, T: Deserialize<'de>>(deserializer: D) -> Result<T, D::Error>
where
    D: Deserializer<'de>,
{
    #[derive(Deserialize)]
    struct Hack<T> {
        #[serde(alias = "d")]
        data: T
    }

    Ok(Hack::deserialize(deserializer)?.data)
}

Edit: found a slightly simplier solution

3 Likes

You could use a nested enum to represent either the d or the data field:

#[derive(Deserialize, Debug,)]
pub struct WsMessage {
  #[serde(flatten)]
  book_or_comp: WsMessageBookOrComp,
}

#[derive(Deserialize, Debug,)]
#[serde(tag="type"]
pub enum WsMessageBookOrComp {
   Orderbook(WsMessageBook),
   OrderbookComp(WsMessageBookComp)
}

#[derive(Deserialize, Debug,)]
pub struct WsMessageBook {
  data: Orderbook
}

#[derive(Deserialize, Debug,)]
pub struct WsMessageBookComp {
  d: Orderbook
}
2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.