crabka_client_core/
version.rs1use std::collections::HashMap;
5
6use crate::error::ClientError;
7use crate::request::ProtocolRequest;
8
9#[derive(Debug, Clone, Default)]
10pub struct ApiVersionTable {
11 by_key: HashMap<i16, (i16, i16)>,
12}
13
14impl ApiVersionTable {
15 #[must_use]
18 pub fn from_entries(entries: impl IntoIterator<Item = (i16, i16, i16)>) -> Self {
19 let mut by_key = HashMap::new();
20 for (k, lo, hi) in entries {
21 by_key.insert(k, (lo, hi));
22 }
23 Self { by_key }
24 }
25
26 pub fn negotiate<R: ProtocolRequest>(&self) -> Result<i16, ClientError> {
29 let api_key = R::API_KEY;
30 let client_min = R::MIN_VERSION;
31 let client_max = R::MAX_VERSION;
32 let (broker_min, broker_max) = self.by_key.get(&api_key).copied().unwrap_or((0, 0));
33 let chosen = client_max.min(broker_max);
34 if chosen < client_min || chosen < broker_min {
35 return Err(ClientError::IncompatibleVersion {
36 api_key,
37 broker_min,
38 broker_max,
39 client_min,
40 client_max,
41 });
42 }
43 Ok(chosen)
44 }
45
46 #[must_use]
49 pub fn broker_range(&self, api_key: i16) -> Option<(i16, i16)> {
50 self.by_key.get(&api_key).copied()
51 }
52
53 #[must_use]
55 pub fn is_empty(&self) -> bool {
56 self.by_key.is_empty()
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use assert2::assert;
64 use crabka_protocol::owned::api_versions_request::ApiVersionsRequest;
65
66 #[test]
70 fn negotiate_takes_min_of_max() {
71 let t = ApiVersionTable::from_entries([(
72 ApiVersionsRequest::API_KEY,
73 0,
74 ApiVersionsRequest::MAX_VERSION,
75 )]);
76 let _ = t.negotiate::<ApiVersionsRequest>().unwrap();
78 }
79
80 #[test]
81 fn negotiate_errors_when_disjoint() {
82 let t = ApiVersionTable::from_entries([(ApiVersionsRequest::API_KEY, 99, 100)]);
83 assert!(matches!(
84 t.negotiate::<ApiVersionsRequest>(),
85 Err(ClientError::IncompatibleVersion { .. })
86 ));
87 }
88
89 #[test]
90 fn negotiate_picks_lowest_supported_when_broker_caps_low() {
91 let t = ApiVersionTable::from_entries([(ApiVersionsRequest::API_KEY, 0, 0)]);
92 assert!(t.negotiate::<ApiVersionsRequest>().unwrap() == 0);
94 }
95}