Skip to main content

df_hyperliquid_core/markets/
mids.rs

1//! `allMids`: every coin's mid on one perp dex, the same map from `/info` and from the socket.
2
3use std::fmt;
4
5use serde::{Deserialize, Deserializer, de};
6
7use crate::utils::dec::Dec;
8
9/// Every coin's mid on one dex, in the venue's order. The main dex's also carries spot pairs
10/// (`@107`, `PURR/USDC`) and outcome sides (`#14730`). Where a book is empty the venue prints its
11/// last trade instead, and a mid can sit between two ticks.
12#[derive(Debug, Clone, PartialEq, Eq, Default)]
13pub struct Mids(Vec<(String, Dec)>);
14
15impl Mids {
16    /// A coin's mid, the coin spelled as the venue spells it (`BTC`, `@107`, `#14730`).
17    #[must_use]
18    pub fn get(&self, coin: &str) -> Option<Dec> {
19        self.0.iter().find(|(name, _)| name == coin).map(|(_, mid)| *mid)
20    }
21
22    #[must_use]
23    pub fn len(&self) -> usize {
24        self.0.len()
25    }
26
27    #[must_use]
28    pub fn is_empty(&self) -> bool {
29        self.0.is_empty()
30    }
31
32    /// In the order written.
33    pub fn iter(&self) -> impl Iterator<Item = (&str, Dec)> {
34        self.0.iter().map(|(coin, mid)| (coin.as_str(), *mid))
35    }
36}
37
38impl FromIterator<(String, Dec)> for Mids {
39    fn from_iter<I: IntoIterator<Item = (String, Dec)>>(pairs: I) -> Self {
40        Mids(pairs.into_iter().collect())
41    }
42}
43
44/// Reads the JSON map into pairs to keep the order written, which a map type would lose.
45impl<'de> Deserialize<'de> for Mids {
46    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
47        struct Pairs;
48
49        impl<'de> de::Visitor<'de> for Pairs {
50            type Value = Mids;
51
52            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53                f.write_str("a map of coin to price")
54            }
55
56            fn visit_map<A: de::MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
57                let mut out = Vec::with_capacity(map.size_hint().unwrap_or(0));
58                while let Some(pair) = map.next_entry::<String, Dec>()? {
59                    out.push(pair);
60                }
61                Ok(Mids(out))
62            }
63        }
64
65        deserializer.deserialize_map(Pairs)
66    }
67}
68
69#[cfg(test)]
70#[path = "tests/mids.rs"]
71mod tests;