Skip to main content

rustrade_integration/
subscription.rs

1use serde::{Deserialize, Serialize};
2use smol_str::SmolStr;
3use std::borrow::Borrow;
4use std::fmt::{Display, Formatter};
5
6/// New type representing a unique `String` identifier for a stream that has been subscribed to.
7/// This is used to identify data structures received over the socket.
8///
9/// For example, `Barter-Data` uses this identifier to associate received data structures from the
10/// execution with the original `Barter-Data` `Subscription` that was actioned over the socket.
11///
12/// Note: Each execution will require the use of different `String` identifiers depending on the
13/// data structures they send.
14///
15/// eg/ [`SubscriptionId`] of an `FtxTrade` is "{BASE}/{QUOTE}" (ie/ market).
16/// eg/ [`SubscriptionId`] of a `BinanceTrade` is `"@trade|BTCUSDT"` (ie/ channel|MARKET).
17#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize)]
18pub struct SubscriptionId(pub SmolStr);
19
20impl Display for SubscriptionId {
21    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
22        write!(f, "{}", self.0)
23    }
24}
25
26/// Join [`SubscriptionId`]s with `", "` for an error message or a log line.
27pub fn display_subscription_ids(ids: &[SubscriptionId]) -> String {
28    ids.iter()
29        .map(SubscriptionId::as_ref)
30        .collect::<Vec<_>>()
31        .join(", ")
32}
33
34impl AsRef<str> for SubscriptionId {
35    fn as_ref(&self) -> &str {
36        &self.0
37    }
38}
39
40/// Borrow a [`SubscriptionId`] as a `&str` so an instrument map keyed on [`SubscriptionId`]
41/// can be queried with a borrowed key (e.g. `Map::find("@kline_1m|BTCUSDT")`) without
42/// allocating an owned [`SubscriptionId`] per lookup.
43///
44/// Soundness: the `Hash`, `Eq`, and `Ord` impls of [`SubscriptionId`] must agree with those of
45/// `str` for `Borrow` to be valid. [`SubscriptionId`] derives all three over its single inner
46/// [`SmolStr`] field, and `SmolStr`'s `Hash`/`Eq`/`Ord` delegate to its string contents — so a
47/// `SubscriptionId` hashes, compares, and orders identically to the `str` it borrows.
48impl Borrow<str> for SubscriptionId {
49    fn borrow(&self) -> &str {
50        &self.0
51    }
52}
53
54impl<S> From<S> for SubscriptionId
55where
56    S: Into<SmolStr>,
57{
58    fn from(input: S) -> Self {
59        Self(input.into())
60    }
61}