serde-rs / serde

Serialization framework for Rust
https://serde.rs/
Apache License 2.0
8.82k stars 748 forks source link

deserialize from str is OK, but deserialize from Value failed #2713

Open guotie opened 3 months ago

guotie commented 3 months ago

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=6c3e85d001da3f5292b22d9a61b4710c

Code:


use serde::de::{Error, SeqAccess, Visitor};
use serde::{Deserialize, Deserializer};
use std::fmt::Formatter;

#[derive(Debug, Clone)]
pub struct Level {
    pub price: String,
    pub size: String,
    pub orders: String,
}

#[derive(Debug, Clone, Deserialize)]
#[serde(untagged)]
pub enum Levels {
    // #[serde(borrow)]
    Depth1([Level; 1]),
    // #[serde(borrow)]
    Depth5([Level; 5]),
    // #[serde(borrow)]
    DepthN(Vec<Level>),
}

#[allow(clippy::len_without_is_empty)]
impl Levels {
    pub fn iter(&self) -> impl Iterator<Item = &Level> {
        match self {
            Levels::Depth1(s) => s.iter(),
            Levels::Depth5(s) => s.iter(),
            Levels::DepthN(s) => s.iter(),
        }
    }

    pub fn len(&self) -> usize {
        match self {
            Levels::Depth1(_) => 1,
            Levels::Depth5(_) => 5,
            Levels::DepthN(s) => s.len(),
        }
    }
}

/// Custom deserializer for book level
/// expecting level format: [price, size, "0", orders]
struct LevelVisitor;
impl<'de> Visitor<'de> for LevelVisitor {
    type Value = Level;

    fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
        formatter.write_str("level format: [price, size, \"0\", orders]")
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
    where
        A: SeqAccess<'de>,
    {
        match (
            seq.next_element::<&str>()?,
            seq.next_element::<&str>()?,
            seq.next_element::<&str>()?,
            seq.next_element::<&str>()?,
        ) {
            (Some(price), Some(size), Some("0"), Some(orders)) => Ok(Level {
                price: price.to_string(),
                size: size.to_string(),
                orders: orders.to_string(),
            }),
            _ => Err(A::Error::custom("invalid level format")),
        }
    }
}

impl<'de> Deserialize<'de> for Level {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_seq(LevelVisitor)
    }
}

type BookUpdateList = Vec<BookUpdate>;

#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BookUpdate {
    // Checksum
    #[serde(default)]
    pub checksum: Option<i64>, // only update books has checksum
    /// Sequence ID of the current message
    pub seq_id: i64,
    /// Sequence ID of the last sent message. Only applicable to books, books-l2-tbt, books50-l2-tbt
    // FIXME: decide a default here. -1 ?
    #[serde(default)]
    pub prev_seq_id: i64,
    /// Order book on sell side
    // #[serde(borrow)]
    pub asks: Levels, // Vec<[String; 4]>
    /// Order book on bid side
    // #[serde(borrow)]
    pub bids: Levels, // Vec<[String; 4]>
    #[serde(default)]
    pub ts: String,
}

fn main() {
        let book = r#"[{"asks":[["67746","0.04574","0","1"]],"bids":[["67745.9","0.27384218","0","9"]],"ts":"1710496651802","seqId":21961839480}]"#;
        let data: BookUpdateList = serde_json::from_str(book).unwrap();
        let value: serde_json::Value = serde_json::from_str(book).unwrap();

        let data2 = BookUpdateList::deserialize(value.clone());

        println!("{:?}", data);
        println!("{:?}", value);
        println!("{:?}", data2); // this failed!
}

why?

Error is:

Err(Error("data did not match any variant of untagged enum Levels", line: 0, column: 0))
guotie commented 3 months ago

If I change

    pub asks: Levels, // Vec<[String; 4]>
    /// Order book on bid side
    // #[serde(borrow)]
    pub bids: Levels, // Vec<[String; 4]>

to

    pub asks: Vec<[String; 4]>,
    /// Order book on bid side
    // #[serde(borrow)]
    pub bids: Vec<[String; 4]>,

all can be success.