1use std::fmt;
5use std::sync::Arc;
6
7macro_rules! opaque_id {
8 ($(#[$meta:meta])* $name:ident) => {
9 $(#[$meta])*
10 #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
13 pub struct $name(Arc<str>);
14
15 impl $name {
16 pub fn new(id: impl Into<Arc<str>>) -> Self {
18 Self(id.into())
19 }
20
21 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 OrderId
50}
51
52opaque_id! {
53 FillId
55}
56
57opaque_id! {
58 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}