Skip to main content

polyoxide_venue/
ids.rs

1//! Opaque ids for orders, fills and the caller's own order names, as each
2//! venue spells them.
3
4use std::fmt;
5use std::sync::Arc;
6
7macro_rules! opaque_id {
8    ($(#[$meta:meta])* $name:ident) => {
9        $(#[$meta])*
10        ///
11        /// Opaque: compared and hashed as the venue's text, never parsed.
12        #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
13        pub struct $name(Arc<str>);
14
15        impl $name {
16            /// The id the venue sent, or the caller chose.
17            pub fn new(id: impl Into<Arc<str>>) -> Self {
18                Self(id.into())
19            }
20
21            /// The id, as the venue spells it.
22            pub fn as_str(&self) -> &str {
23                &self.0
24            }
25        }
26
27        impl fmt::Display for $name {
28            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29                f.write_str(&self.0)
30            }
31        }
32
33        impl From<&str> for $name {
34            fn from(id: &str) -> Self {
35                Self(id.into())
36            }
37        }
38
39        impl From<String> for $name {
40            fn from(id: String) -> Self {
41                Self(id.into())
42            }
43        }
44    };
45}
46
47opaque_id! {
48    /// The venue's id for an order.
49    OrderId
50}
51
52opaque_id! {
53    /// The venue's id for a fill: one order's part in a trade.
54    FillId
55}
56
57opaque_id! {
58    /// The id a caller gives an order, which the venue echoes back or the
59    /// implementation keeps for the orders it placed.
60    ClientOrderId
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn an_id_is_its_text() {
69        let id = OrderId::from("ee587a1c-0001");
70        assert_eq!(id.as_str(), "ee587a1c-0001");
71        assert_eq!(id.to_string(), "ee587a1c-0001");
72        assert_eq!(format!("{id:?}"), r#"OrderId("ee587a1c-0001")"#);
73        assert_eq!(id, OrderId::new(String::from("ee587a1c-0001")));
74        assert_eq!(FillId::new("f").as_str(), "f");
75        assert_eq!(ClientOrderId::from(String::from("c")).as_str(), "c");
76    }
77
78    #[test]
79    fn ids_compare_and_hash_by_their_text() {
80        let mut seen = std::collections::HashSet::new();
81        assert!(seen.insert(OrderId::from("a")));
82        assert!(!seen.insert(OrderId::new("a")), "one text is one id");
83        assert!(seen.insert(OrderId::from("b")));
84        assert!(OrderId::from("a") < OrderId::from("b"));
85        assert_ne!(OrderId::from("a"), OrderId::from("A"));
86    }
87}