Skip to main content

futu_cache/qot_right/reconnect/
model.rs

1use super::super::QotRightData;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4pub struct QotRightReconnectToken(pub(in crate::qot_right) u64);
5
6impl QotRightReconnectToken {
7    #[must_use]
8    pub const fn value(self) -> u64 {
9        self.0
10    }
11}
12
13#[derive(Debug, Clone, Default, PartialEq, Eq)]
14pub struct QotRightReconnectAccumulator {
15    pub requested_highest: bool,
16    pub highest_changed_quote_types: Vec<i32>,
17    pub external_changed_quote_types: Vec<i32>,
18    pub latest_pushed_notify_version: Option<u64>,
19}
20
21impl QotRightReconnectAccumulator {
22    #[must_use]
23    pub fn highest(changed_quote_types: &[i32]) -> Self {
24        let mut value = Self {
25            requested_highest: true,
26            highest_changed_quote_types: changed_quote_types.to_vec(),
27            ..Self::default()
28        };
29        value.canonicalize();
30        value
31    }
32
33    #[must_use]
34    pub fn external(changed_quote_types: &[i32], pushed_notify_version: u64) -> Self {
35        let mut value = Self {
36            external_changed_quote_types: changed_quote_types.to_vec(),
37            latest_pushed_notify_version: Some(pushed_notify_version),
38            ..Self::default()
39        };
40        value.canonicalize();
41        value
42    }
43
44    pub(in crate::qot_right) fn merge(&mut self, other: &Self) {
45        self.requested_highest |= other.requested_highest;
46        self.highest_changed_quote_types
47            .extend_from_slice(&other.highest_changed_quote_types);
48        self.external_changed_quote_types
49            .extend_from_slice(&other.external_changed_quote_types);
50        self.latest_pushed_notify_version = match (
51            self.latest_pushed_notify_version,
52            other.latest_pushed_notify_version,
53        ) {
54            (Some(left), Some(right)) => Some(left.max(right)),
55            (left, right) => left.or(right),
56        };
57        self.canonicalize();
58    }
59
60    fn canonicalize(&mut self) {
61        canonicalize_reconnect_quote_types(&mut self.highest_changed_quote_types);
62        canonicalize_reconnect_quote_types(&mut self.external_changed_quote_types);
63    }
64
65    #[must_use]
66    pub fn effective_exclusion_quote_types(&self) -> Vec<i32> {
67        if !self.requested_highest {
68            return Vec::new();
69        }
70        let mut values = self.highest_changed_quote_types.clone();
71        values.extend_from_slice(&self.external_changed_quote_types);
72        canonicalize_reconnect_quote_types(&mut values);
73        values
74    }
75
76    #[must_use]
77    pub fn is_empty(&self) -> bool {
78        !self.requested_highest
79            && self.highest_changed_quote_types.is_empty()
80            && self.external_changed_quote_types.is_empty()
81            && self.latest_pushed_notify_version.is_none()
82    }
83}
84
85fn canonicalize_reconnect_quote_types(values: &mut Vec<i32>) {
86    // Ref: NNBiz_Qot_Right.cpp:1057-1158. C++ appends changed types in
87    // Parse* order and later feeds that order directly to AddQotRightMkt.
88    // Numeric sorting would incorrectly put HK future (4) before option (5).
89    const CPP_PARSE_ORDER: &[i32] = &[
90        1, 5, 4, 17, 8, 19, 11, 30, 31, 32, 33, 16, 40, 41, 38, 37, 36, 39, 20, 29,
91    ];
92    values.sort_by_key(|value| {
93        CPP_PARSE_ORDER
94            .iter()
95            .position(|candidate| candidate == value)
96            .map_or((usize::MAX, *value), |rank| (rank, 0))
97    });
98    values.dedup();
99}
100
101#[derive(Debug, Clone, Default, PartialEq, Eq)]
102pub enum QotRightReconnectLifecycle {
103    #[default]
104    Idle,
105    Deferred {
106        token: QotRightReconnectToken,
107        generation: u64,
108        accumulator: QotRightReconnectAccumulator,
109        dispatch_admitted: bool,
110    },
111    Pending {
112        token: QotRightReconnectToken,
113        generation: u64,
114        accumulator: QotRightReconnectAccumulator,
115    },
116    InFlight {
117        token: QotRightReconnectToken,
118        generation: u64,
119        serving: QotRightReconnectAccumulator,
120        follow_up: QotRightReconnectAccumulator,
121    },
122}
123
124#[derive(Debug, Clone, PartialEq, Eq)]
125pub enum QotRightReconnectClaimKind {
126    OrdinaryHighest,
127    Entitlement(QotRightReconnectAccumulator),
128}
129
130#[derive(Debug, Clone, PartialEq, Eq)]
131pub struct QotRightReconnectClaim {
132    pub token: QotRightReconnectToken,
133    pub source_generation: u64,
134    pub active_generation: u64,
135    pub kind: QotRightReconnectClaimKind,
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139pub struct QotRightReconnectRegistration {
140    pub token: QotRightReconnectToken,
141    pub owns_deferred: bool,
142    pub should_disconnect: bool,
143}
144
145#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146pub struct QotRightReconnectHandoff {
147    pub token: QotRightReconnectToken,
148    pub source_generation: u64,
149}
150
151#[derive(Debug, Clone, PartialEq, Eq)]
152pub(in crate::qot_right) struct QotRightPublicSnapshot {
153    hk_qot_right: i32,
154    api_us_qot_right: i32,
155    sh_qot_right: i32,
156    sz_qot_right: i32,
157    hk_option_qot_right: i32,
158    hk_future_qot_right: i32,
159    has_us_option_qot_right: bool,
160    us_option_qot_right: i32,
161    us_index_qot_right: i32,
162    us_otc_qot_right: i32,
163    us_cme_future_qot_right: i32,
164    us_cbot_future_qot_right: i32,
165    us_nymex_future_qot_right: i32,
166    us_comex_future_qot_right: i32,
167    us_cboe_future_qot_right: i32,
168    sg_future_qot_right: i32,
169    jp_future_qot_right: i32,
170    sg_stock_qot_right: i32,
171    my_stock_qot_right: i32,
172    jp_stock_qot_right: i32,
173    cc_qot_right: i32,
174    event_contract_qot_right: i32,
175}
176
177impl From<&QotRightData> for QotRightPublicSnapshot {
178    fn from(data: &QotRightData) -> Self {
179        Self {
180            hk_qot_right: data.hk_qot_right,
181            api_us_qot_right: data.api_us_qot_right,
182            sh_qot_right: data.sh_qot_right,
183            sz_qot_right: data.sz_qot_right,
184            hk_option_qot_right: data.hk_option_qot_right,
185            hk_future_qot_right: data.hk_future_qot_right,
186            has_us_option_qot_right: data.has_us_option_qot_right,
187            us_option_qot_right: data.us_option_qot_right,
188            us_index_qot_right: data.us_index_qot_right,
189            us_otc_qot_right: data.us_otc_qot_right,
190            us_cme_future_qot_right: data.us_cme_future_qot_right,
191            us_cbot_future_qot_right: data.us_cbot_future_qot_right,
192            us_nymex_future_qot_right: data.us_nymex_future_qot_right,
193            us_comex_future_qot_right: data.us_comex_future_qot_right,
194            us_cboe_future_qot_right: data.us_cboe_future_qot_right,
195            sg_future_qot_right: data.sg_future_qot_right,
196            jp_future_qot_right: data.jp_future_qot_right,
197            sg_stock_qot_right: data.sg_stock_qot_right,
198            my_stock_qot_right: data.my_stock_qot_right,
199            jp_stock_qot_right: data.jp_stock_qot_right,
200            cc_qot_right: data.cc_qot_right,
201            event_contract_qot_right: data.event_contract_qot_right,
202        }
203    }
204}
205
206#[derive(Debug, Clone, Copy, PartialEq, Eq)]
207pub(in crate::qot_right) struct QotRightReconnectSnapshot {
208    hk_qot_right: i32,
209    hk_option_qot_right: i32,
210    hk_future_qot_right: i32,
211    us_qot_right: i32,
212    us_own_qot_right: i32,
213    us_option_qot_right: i32,
214    us_cme_future_qot_right: i32,
215    us_cbot_future_qot_right: i32,
216    us_nymex_future_qot_right: i32,
217    us_comex_future_qot_right: i32,
218    us_cboe_future_qot_right: i32,
219    sh_qot_right: i32,
220    sz_qot_right: i32,
221    us_index_qot_right: i32,
222    us_otc_qot_right: i32,
223    sg_future_qot_right: i32,
224    jp_future_qot_right: i32,
225    sg_stock_qot_right: i32,
226    jp_stock_qot_right: i32,
227}
228
229impl From<&QotRightData> for QotRightReconnectSnapshot {
230    fn from(data: &QotRightData) -> Self {
231        Self {
232            hk_qot_right: data.hk_qot_right,
233            hk_option_qot_right: data.hk_option_qot_right,
234            hk_future_qot_right: data.hk_future_qot_right,
235            us_qot_right: data.us_qot_right,
236            us_own_qot_right: data.us_own_qot_right,
237            us_option_qot_right: data.us_option_qot_right,
238            us_cme_future_qot_right: data.us_cme_future_qot_right,
239            us_cbot_future_qot_right: data.us_cbot_future_qot_right,
240            us_nymex_future_qot_right: data.us_nymex_future_qot_right,
241            us_comex_future_qot_right: data.us_comex_future_qot_right,
242            us_cboe_future_qot_right: data.us_cboe_future_qot_right,
243            sh_qot_right: data.sh_qot_right,
244            sz_qot_right: data.sz_qot_right,
245            us_index_qot_right: data.us_index_qot_right,
246            us_otc_qot_right: data.us_otc_qot_right,
247            sg_future_qot_right: data.sg_future_qot_right,
248            jp_future_qot_right: data.jp_future_qot_right,
249            sg_stock_qot_right: data.sg_stock_qot_right,
250            jp_stock_qot_right: data.jp_stock_qot_right,
251        }
252    }
253}
254
255impl QotRightReconnectSnapshot {
256    pub(in crate::qot_right) fn changed_quote_types(self, after: &QotRightData) -> Vec<i32> {
257        let mut changed = Vec::new();
258        push_if_changed(&mut changed, 1, self.hk_qot_right, after.hk_qot_right);
259        push_if_changed(
260            &mut changed,
261            5,
262            self.hk_option_qot_right,
263            after.hk_option_qot_right,
264        );
265        push_if_changed(
266            &mut changed,
267            4,
268            self.hk_future_qot_right,
269            after.hk_future_qot_right,
270        );
271        if self.us_qot_right != after.us_qot_right
272            || self.us_own_qot_right != after.us_own_qot_right
273        {
274            changed.push(17);
275        }
276        push_if_changed(
277            &mut changed,
278            11,
279            self.us_option_qot_right,
280            after.us_option_qot_right,
281        );
282        push_if_changed(
283            &mut changed,
284            30,
285            self.us_cme_future_qot_right,
286            after.us_cme_future_qot_right,
287        );
288        push_if_changed(
289            &mut changed,
290            31,
291            self.us_cbot_future_qot_right,
292            after.us_cbot_future_qot_right,
293        );
294        push_if_changed(
295            &mut changed,
296            32,
297            self.us_nymex_future_qot_right,
298            after.us_nymex_future_qot_right,
299        );
300        push_if_changed(
301            &mut changed,
302            33,
303            self.us_comex_future_qot_right,
304            after.us_comex_future_qot_right,
305        );
306        push_if_changed(
307            &mut changed,
308            16,
309            self.us_cboe_future_qot_right,
310            after.us_cboe_future_qot_right,
311        );
312        if self.sh_qot_right != after.sh_qot_right || self.sz_qot_right != after.sz_qot_right {
313            changed.extend([40, 41]);
314        }
315        push_if_changed(
316            &mut changed,
317            38,
318            self.us_index_qot_right,
319            after.us_index_qot_right,
320        );
321        push_if_changed(
322            &mut changed,
323            37,
324            self.us_otc_qot_right,
325            after.us_otc_qot_right,
326        );
327        push_if_changed(
328            &mut changed,
329            36,
330            self.sg_future_qot_right,
331            after.sg_future_qot_right,
332        );
333        push_if_changed(
334            &mut changed,
335            39,
336            self.jp_future_qot_right,
337            after.jp_future_qot_right,
338        );
339        push_if_changed(
340            &mut changed,
341            20,
342            self.sg_stock_qot_right,
343            after.sg_stock_qot_right,
344        );
345        push_if_changed(
346            &mut changed,
347            29,
348            self.jp_stock_qot_right,
349            after.jp_stock_qot_right,
350        );
351        changed
352    }
353}
354
355fn push_if_changed(changed: &mut Vec<i32>, quote_type: i32, before: i32, after: i32) {
356    if before != after {
357        changed.push(quote_type);
358    }
359}