Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust serde deserializing a mixed array

Tags:

rust

serde

In Rust i am receiving data from a websocket. For simplicity it looks like this:

 [1, {"a": ["1.2345", 5, "9.8765"]}]

The string i get from the websocket is indeed double-quoted 'floating point values' (thus in actuality strings), and unquoted integers.

I want to deserialize this object into a struct. But since the return array "a" is of mixed type, I can't use something like:

 struct MyStruct {
    id: i32, 
    a: [f64; 3],
 }

So I thought let's define another struct:

 struct Ask {
    price: f64,
    whole_lot_volume: i64,
    lot_volume: f64
 }

 struct MyStruct {
    id: i32,
    a: Ask
 }

But how should I write the deserializer for this? Looking at the serde docs I understand that I should write a Visitor for Ask:

 impl<'de> Visitor<'de> for Ask {
    type Value = ...
 }

But what would be the Value type then?

So I'm sure I am not correctly understanding how the deserialization process works. Or is the fact that the Websocket returns an array of mixed types just incompatible with the serde deserialization process?

like image 441
Robin van Leeuwen Avatar asked Oct 28 '25 15:10

Robin van Leeuwen


1 Answers

Serde can deserialize to a Rust struct from sequence-like structures as well as map-like ones.

Your structs are almost right, but there is an extra layer of hierarchy in your JSON. If your JSON was:

{
    "id": 1,
    "a": [1.2345, 5, 9.8765]
}

then this will just work, with the right serde annotations:

use serde::{Serialize, Deserialize};

#[derive(Deserialize)]
struct Ask {
    price: f64,
    whole_lot_volume: i64,
    lot_volume: f64,
}

#[derive(Deserialize)]
struct MyStruct {
    id: i32,
    a: Ask,
}

If you can't change the JSON, you can use an extra layer of structs to match:

use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize)]
struct Order {
    price: f64,
    whole_lot_volume: i64,
    lot_volume: f64,
}

#[derive(Debug, Deserialize)]
struct Ask {
    a: Order,
}

#[derive(Debug, Deserialize)]
struct MyStruct {
    id: i32,
    a: Ask,
}

It is rare that you need to implement your own Visitor; the Deserialize macro provided by serde is quite customisable. However, if you want to omit the extra struct, that's what you'd have to do.

You may need to do more work if some of the numbers are represented as JSON strings, but you can still do that without a custom Visitor implementation. See:

  • How to transform fields during deserialization using Serde?
  • How to transform fields during serialization using Serde?
  • Serde field attributes
like image 89
Peter Hall Avatar answered Oct 31 '25 10:10

Peter Hall



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!