Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
guotie opened this issue Mar 15, 2024 · 1 comment
Open

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

guotie opened this issue Mar 15, 2024 · 1 comment

Comments

@guotie
Copy link

guotie commented Mar 15, 2024

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
Copy link
Author

guotie commented Mar 15, 2024

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

1 participant