1use brokapi_core::{Charset, CidCaps, CidCodec, CidError, ClientOrderId, NativeCid};
4use uuid::Uuid;
5
6#[derive(Debug, Clone, Copy, Default)]
8pub struct BcsCidCodec;
9
10impl CidCodec for BcsCidCodec {
11 fn caps(&self) -> CidCaps {
12 CidCaps {
13 max_len: 36,
14 charset: Charset::Ascii,
15 native_bits: 128,
16 lossless: true,
17 }
18 }
19
20 fn encode(&self, cid: ClientOrderId) -> Result<NativeCid, CidError> {
21 let s = cid.hyphenated().to_string();
22 if s.len() > self.caps().max_len {
23 return Err(CidError::TooLong {
24 len: s.len(),
25 max: self.caps().max_len,
26 });
27 }
28 Ok(NativeCid::new(s))
29 }
30
31 fn decode(&self, native: &NativeCid) -> Option<ClientOrderId> {
32 Uuid::parse_str(native.as_str()).ok()
33 }
34}
35
36const FOREIGN_NS: Uuid = Uuid::from_u128(0x7bc5_2f01_53a4_4d0e_9b6a_0c8e_bc50_0001);
38
39pub fn foreign_cid(order_id: &str) -> ClientOrderId {
43 Uuid::new_v5(&FOREIGN_NS, order_id.as_bytes())
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49 use proptest::prelude::*;
50
51 prop_compose! {
52 fn arb_cid()(bytes in any::<[u8; 16]>()) -> ClientOrderId {
53 ClientOrderId::from_bytes(bytes)
54 }
55 }
56
57 #[test]
58 fn foreign_cids_are_stable_and_distinct() {
59 assert_eq!(
60 foreign_cid("20261019-TQBR-1"),
61 foreign_cid("20261019-TQBR-1")
62 );
63 assert_ne!(
64 foreign_cid("20261019-TQBR-1"),
65 foreign_cid("20261019-TQBR-2")
66 );
67 assert_eq!(foreign_cid("x").get_version_num(), 5);
68 }
69
70 proptest! {
71 #[test]
72 fn bcs_cid_roundtrip(cid in arb_cid()) {
73 let codec = BcsCidCodec;
74 let native = codec.encode(cid).expect("encode");
75 let decoded = codec.decode(&native).expect("decode");
76 prop_assert_eq!(decoded, cid);
77 }
78 }
79}