pub mod error;
pub use self::error::{UnsupportedFieldVersion, UnsupportedVersion};
pub use crate::generated::{ApiInfo, ApiKey, client_api_info};
pub type Result<T> = core::result::Result<T, UnsupportedVersion>;
pub const API_VERSIONS_KEY: i16 = 18;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ApiVersionRange {
pub min_version: i16,
pub max_version: i16,
}
#[must_use]
pub fn resolve_api_version(api_key: i16, broker_range: ApiVersionRange) -> Option<i16> {
if broker_range.min_version > broker_range.max_version {
return None;
}
let api_key = ApiKey::from_i16(api_key)?;
let info = client_api_info(api_key);
let min_version = broker_range.min_version.max(info.min_version);
let max_version = broker_range.max_version.min(info.max_version);
if min_version > max_version {
return None;
}
Some(max_version)
}
#[must_use]
pub fn request_header_version(api_key: i16, api_version: i16) -> i16 {
if api_key == ApiKey::ControlledShutdown as i16 && api_version == 0 {
return 0;
}
if is_flexible_version(api_key, api_version) {
2
} else {
1
}
}
#[must_use]
pub fn response_header_version(api_key: i16, api_version: i16) -> i16 {
if api_key == API_VERSIONS_KEY {
return 0;
}
i16::from(is_flexible_version(api_key, api_version))
}
fn is_flexible_version(api_key: i16, api_version: i16) -> bool {
let Some(api_key) = ApiKey::from_i16(api_key) else {
return false;
};
let info = client_api_info(api_key);
api_version >= info.flexible_versions_start
&& api_version >= info.min_version
&& api_version <= info.max_version
}
#[cfg(test)]
mod tests {
use super::{
API_VERSIONS_KEY, ApiVersionRange, request_header_version, resolve_api_version,
response_header_version,
};
use crate::generated::ApiKey;
#[test]
fn resolve_api_version_intersects_client_and_broker_ranges() {
let metadata = ApiKey::Metadata as i16;
assert_eq!(
resolve_api_version(
metadata,
ApiVersionRange {
min_version: 0,
max_version: 99,
},
),
Some(13),
);
assert_eq!(
resolve_api_version(
metadata,
ApiVersionRange {
min_version: 0,
max_version: 2,
},
),
Some(2),
);
assert_eq!(
resolve_api_version(
metadata,
ApiVersionRange {
min_version: 99,
max_version: 100,
},
),
None,
);
assert_eq!(
resolve_api_version(
-32,
ApiVersionRange {
min_version: 0,
max_version: 1,
},
),
None,
);
}
#[test]
fn header_versions_follow_flexible_metadata_and_special_cases() {
let metadata = ApiKey::Metadata as i16;
let controlled_shutdown = ApiKey::ControlledShutdown as i16;
assert_eq!(request_header_version(controlled_shutdown, 0), 0);
assert_eq!(request_header_version(metadata, 8), 1);
assert_eq!(request_header_version(metadata, 9), 2);
assert_eq!(response_header_version(API_VERSIONS_KEY, 3), 0);
assert_eq!(response_header_version(metadata, 8), 0);
assert_eq!(response_header_version(metadata, 9), 1);
}
}