use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct ApiVersionInfo {
pub api_key: i16,
pub min_version: i16,
pub max_version: i16,
}
impl ApiVersionInfo {
pub fn new(api_key: i16, min_version: i16, max_version: i16) -> Self {
Self {
api_key,
min_version,
max_version,
}
}
pub fn supports_version(&self, version: i16) -> bool {
version >= self.min_version && version <= self.max_version
}
pub fn max_supported_version(&self, client_version: i16) -> i16 {
std::cmp::min(self.max_version, client_version)
}
}
pub struct ApiVersionRegistry {
versions: HashMap<i16, ApiVersionInfo>,
}
impl ApiVersionRegistry {
pub fn new() -> Self {
let mut registry = Self {
versions: HashMap::new(),
};
registry.register(0, 0, 7); registry.register(1, 0, 11); registry.register(3, 0, 9);
registry.register(10, 0, 3); registry.register(11, 0, 5); registry.register(12, 0, 3); registry.register(13, 0, 2); registry.register(14, 0, 3); registry.register(15, 0, 4); registry.register(16, 0, 3);
registry.register(2, 0, 5); registry.register(8, 0, 6); registry.register(9, 0, 5);
registry.register(18, 0, 3);
registry.register(19, 0, 4); registry.register(20, 0, 3); registry.register(32, 0, 3); registry.register(33, 0, 2);
registry.register(17, 0, 1); registry.register(36, 0, 2);
registry
}
fn register(&mut self, api_key: i16, min_version: i16, max_version: i16) {
self.versions.insert(
api_key,
ApiVersionInfo::new(api_key, min_version, max_version),
);
}
pub fn get_version_info(&self, api_key: i16) -> Option<&ApiVersionInfo> {
self.versions.get(&api_key)
}
pub fn is_supported(&self, api_key: i16, version: i16) -> bool {
self.versions
.get(&api_key)
.map_or(false, |info| info.supports_version(version))
}
pub fn get_all_versions(&self) -> Vec<&ApiVersionInfo> {
let mut versions: Vec<_> = self.versions.values().collect();
versions.sort_by_key(|v| v.api_key);
versions
}
pub fn negotiate_version(&self, api_key: i16, client_max_version: i16) -> Option<i16> {
self.versions
.get(&api_key)
.map(|info| info.max_supported_version(client_max_version))
}
pub fn supports_api(&self, api_key: i16) -> bool {
self.versions.contains_key(&api_key)
}
}
impl Default for ApiVersionRegistry {
fn default() -> Self {
Self::new()
}
}
pub mod compat {
use super::*;
pub fn produce_supports_idempotent(version: i16) -> bool {
version >= 3
}
pub fn produce_supports_transactions(version: i16) -> bool {
version >= 3
}
pub fn fetch_supports_isolation_level(version: i16) -> bool {
version >= 4
}
pub fn fetch_supports_sessions(version: i16) -> bool {
version >= 7
}
pub fn metadata_supports_auto_creation(version: i16) -> bool {
version >= 4
}
pub fn join_group_supports_static_membership(version: i16) -> bool {
version >= 5
}
pub fn get_recommended_versions() -> HashMap<i16, i16> {
let mut versions = HashMap::new();
versions.insert(0, 7); versions.insert(1, 7); versions.insert(2, 2); versions.insert(3, 5); versions.insert(8, 3); versions.insert(9, 3); versions.insert(10, 1); versions.insert(11, 3); versions.insert(12, 1); versions.insert(13, 1); versions.insert(14, 1); versions.insert(15, 1); versions.insert(16, 1); versions.insert(18, 2);
versions
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_api_version_info() {
let info = ApiVersionInfo::new(0, 1, 5);
assert_eq!(info.api_key, 0);
assert_eq!(info.min_version, 1);
assert_eq!(info.max_version, 5);
assert!(!info.supports_version(0));
assert!(info.supports_version(1));
assert!(info.supports_version(3));
assert!(info.supports_version(5));
assert!(!info.supports_version(6));
assert_eq!(info.max_supported_version(3), 3);
assert_eq!(info.max_supported_version(7), 5);
}
#[test]
fn test_api_version_registry() {
let registry = ApiVersionRegistry::new();
assert!(registry.is_supported(0, 0));
assert!(registry.is_supported(0, 7));
assert!(!registry.is_supported(0, 8));
assert!(!registry.supports_api(999));
assert!(!registry.is_supported(999, 0));
assert_eq!(registry.negotiate_version(0, 3), Some(3));
assert_eq!(registry.negotiate_version(0, 10), Some(7));
assert_eq!(registry.negotiate_version(999, 1), None);
let all_versions = registry.get_all_versions();
assert!(!all_versions.is_empty());
for i in 1..all_versions.len() {
assert!(all_versions[i - 1].api_key <= all_versions[i].api_key);
}
}
#[test]
fn test_compatibility_helpers() {
use compat::*;
assert!(!produce_supports_idempotent(2));
assert!(produce_supports_idempotent(3));
assert!(!fetch_supports_isolation_level(3));
assert!(fetch_supports_isolation_level(4));
assert!(!metadata_supports_auto_creation(3));
assert!(metadata_supports_auto_creation(4));
let recommended = get_recommended_versions();
assert!(recommended.contains_key(&0)); assert!(recommended.contains_key(&1)); assert!(recommended.contains_key(&3)); }
}