use serde::{Deserialize, Serialize};
use strum::{AsRefStr, Display, EnumIter, EnumString};
#[derive(
Clone,
Debug,
Display,
PartialEq,
Eq,
Hash,
AsRefStr,
EnumIter,
EnumString,
Serialize,
Deserialize,
)]
pub enum HyperliquidWsChannel {
#[serde(rename = "subscriptionResponse")]
SubscriptionResponse,
#[serde(rename = "trades")]
Trades,
#[serde(rename = "l2Book")]
L2Book,
#[serde(rename = "bbo")]
Bbo,
#[serde(rename = "candle")]
Candle,
#[serde(rename = "allMids")]
AllMids,
#[serde(rename = "notification")]
Notification,
#[serde(rename = "orderUpdates")]
OrderUpdates,
#[serde(rename = "userEvents")]
UserEvents,
#[serde(rename = "userFills")]
UserFills,
#[serde(rename = "userFundings")]
UserFundings,
#[serde(rename = "userNonFundingLedgerUpdates")]
UserNonFundingLedgerUpdates,
#[serde(rename = "activeAssetCtx")]
ActiveAssetCtx,
#[serde(rename = "activeSpotAssetCtx")]
ActiveSpotAssetCtx,
#[serde(rename = "activeAssetData")]
ActiveAssetData,
#[serde(rename = "userTwapSliceFills")]
UserTwapSliceFills,
#[serde(rename = "userTwapHistory")]
UserTwapHistory,
#[serde(rename = "webData2")]
WebData2,
#[serde(rename = "user")]
User,
#[serde(rename = "post")]
Post,
#[serde(rename = "pong")]
Pong,
#[serde(rename = "error")]
Error,
}
impl HyperliquidWsChannel {
pub fn as_str(&self) -> &'static str {
match self {
Self::SubscriptionResponse => "subscriptionResponse",
Self::Trades => "trades",
Self::L2Book => "l2Book",
Self::Bbo => "bbo",
Self::Candle => "candle",
Self::AllMids => "allMids",
Self::Notification => "notification",
Self::OrderUpdates => "orderUpdates",
Self::UserEvents => "userEvents",
Self::UserFills => "userFills",
Self::UserFundings => "userFundings",
Self::UserNonFundingLedgerUpdates => "userNonFundingLedgerUpdates",
Self::ActiveAssetCtx => "activeAssetCtx",
Self::ActiveSpotAssetCtx => "activeSpotAssetCtx",
Self::ActiveAssetData => "activeAssetData",
Self::UserTwapSliceFills => "userTwapSliceFills",
Self::UserTwapHistory => "userTwapHistory",
Self::WebData2 => "webData2",
Self::User => "user",
Self::Post => "post",
Self::Pong => "pong",
Self::Error => "error",
}
}
pub fn is_public(&self) -> bool {
matches!(
self,
Self::SubscriptionResponse
| Self::Trades
| Self::L2Book
| Self::Bbo
| Self::Candle
| Self::AllMids
| Self::ActiveAssetCtx
| Self::ActiveSpotAssetCtx
| Self::Notification
| Self::Pong
| Self::Error
)
}
pub fn is_private(&self) -> bool {
!self.is_public()
}
pub fn from_wire_str(s: &str) -> Option<Self> {
serde_json::from_value(serde_json::Value::String(s.to_string())).ok()
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use rstest::rstest;
use serde_json;
use strum::IntoEnumIterator;
use super::*;
#[rstest]
#[case(HyperliquidWsChannel::Trades, r#""trades""#)]
#[case(HyperliquidWsChannel::L2Book, r#""l2Book""#)]
#[case(HyperliquidWsChannel::UserFills, r#""userFills""#)]
#[case(HyperliquidWsChannel::Bbo, r#""bbo""#)]
#[case(
HyperliquidWsChannel::SubscriptionResponse,
r#""subscriptionResponse""#
)]
fn test_channel_serialization(#[case] channel: HyperliquidWsChannel, #[case] expected: &str) {
assert_eq!(serde_json::to_string(&channel).unwrap(), expected);
}
#[rstest]
#[case(r#""trades""#, HyperliquidWsChannel::Trades)]
#[case(r#""l2Book""#, HyperliquidWsChannel::L2Book)]
#[case(r#""userEvents""#, HyperliquidWsChannel::UserEvents)]
#[case(r#""bbo""#, HyperliquidWsChannel::Bbo)]
#[case(r#""pong""#, HyperliquidWsChannel::Pong)]
fn test_channel_deserialization(#[case] json: &str, #[case] expected: HyperliquidWsChannel) {
assert_eq!(
serde_json::from_str::<HyperliquidWsChannel>(json).unwrap(),
expected
);
}
#[rstest]
#[case(HyperliquidWsChannel::Trades, "trades")]
#[case(HyperliquidWsChannel::L2Book, "l2Book")]
#[case(HyperliquidWsChannel::UserFills, "userFills")]
#[case(
HyperliquidWsChannel::UserNonFundingLedgerUpdates,
"userNonFundingLedgerUpdates"
)]
#[case(HyperliquidWsChannel::Bbo, "bbo")]
fn test_as_str_method(#[case] channel: HyperliquidWsChannel, #[case] expected: &str) {
assert_eq!(channel.as_str(), expected);
}
#[rstest]
fn test_display_trait() {
assert_eq!(format!("{}", HyperliquidWsChannel::Trades), "Trades");
assert_eq!(format!("{}", HyperliquidWsChannel::L2Book), "L2Book");
assert_eq!(format!("{}", HyperliquidWsChannel::UserFills), "UserFills");
}
#[rstest]
fn test_is_public_channel() {
assert!(HyperliquidWsChannel::Trades.is_public());
assert!(HyperliquidWsChannel::L2Book.is_public());
assert!(HyperliquidWsChannel::Bbo.is_public());
assert!(HyperliquidWsChannel::SubscriptionResponse.is_public());
assert!(HyperliquidWsChannel::Pong.is_public());
assert!(!HyperliquidWsChannel::OrderUpdates.is_public());
assert!(!HyperliquidWsChannel::UserEvents.is_public());
assert!(!HyperliquidWsChannel::UserFills.is_public());
assert!(!HyperliquidWsChannel::UserFundings.is_public());
assert!(!HyperliquidWsChannel::UserNonFundingLedgerUpdates.is_public());
assert!(!HyperliquidWsChannel::Post.is_public());
}
#[rstest]
fn test_is_private_channel() {
assert!(!HyperliquidWsChannel::Trades.is_private());
assert!(!HyperliquidWsChannel::L2Book.is_private());
assert!(!HyperliquidWsChannel::Bbo.is_private());
assert!(HyperliquidWsChannel::OrderUpdates.is_private());
assert!(HyperliquidWsChannel::UserEvents.is_private());
assert!(HyperliquidWsChannel::UserFills.is_private());
assert!(HyperliquidWsChannel::UserFundings.is_private());
assert!(HyperliquidWsChannel::UserNonFundingLedgerUpdates.is_private());
assert!(HyperliquidWsChannel::Post.is_private());
}
#[rstest]
fn test_enum_iter() {
let channels: Vec<HyperliquidWsChannel> = HyperliquidWsChannel::iter().collect();
assert_eq!(channels.len(), 22);
assert!(channels.contains(&HyperliquidWsChannel::Trades));
assert!(channels.contains(&HyperliquidWsChannel::L2Book));
assert!(channels.contains(&HyperliquidWsChannel::UserFills));
assert!(channels.contains(&HyperliquidWsChannel::Candle));
assert!(channels.contains(&HyperliquidWsChannel::AllMids));
assert!(channels.contains(&HyperliquidWsChannel::Notification));
}
#[rstest]
fn test_from_str() {
assert_eq!(
HyperliquidWsChannel::from_str("Trades").unwrap(),
HyperliquidWsChannel::Trades
);
assert_eq!(
HyperliquidWsChannel::from_str("L2Book").unwrap(),
HyperliquidWsChannel::L2Book
);
assert_eq!(
HyperliquidWsChannel::from_str("UserFills").unwrap(),
HyperliquidWsChannel::UserFills
);
assert!(HyperliquidWsChannel::from_str("InvalidChannel").is_err());
}
}