Skip to main content

memlink_protocol/
negotiation.rs

1//! Version negotiation logic.
2//!
3//! Provides functions for negotiating protocol versions between clients
4//! and servers, including feature intersection and validation.
5
6use crate::error::{ProtocolError, Result};
7use crate::features::intersect_features;
8use crate::version::{ProtocolVersion, SUPPORTED_VERSIONS};
9
10pub fn negotiate_version(client: &ProtocolVersion, server: &ProtocolVersion) -> Result<ProtocolVersion> {
11    if client.major() != server.major() {
12        return Err(ProtocolError::UnsupportedVersion(
13            client.major().max(server.major()) as u8,
14        ));
15    }
16
17    let negotiated_minor = client.minor().min(server.minor());
18    let common_features = intersect_features(client.features(), server.features());
19
20    Ok(ProtocolVersion::new(client.major(), negotiated_minor, common_features))
21}
22
23pub fn negotiate_with_server_versions(
24    client: &ProtocolVersion,
25    server_versions: &[ProtocolVersion],
26) -> Result<ProtocolVersion> {
27    let mut best_version: Option<ProtocolVersion> = None;
28
29    for server_version in server_versions {
30        if let Ok(negotiated) = negotiate_version(client, server_version) {
31            if best_version.is_none() || negotiated.compare(&best_version.unwrap()) > 0 {
32                best_version = Some(negotiated);
33            }
34        }
35    }
36
37    best_version.ok_or_else(|| ProtocolError::UnsupportedVersion(client.major() as u8))
38}
39
40pub fn validate_version(version: &ProtocolVersion) -> Result<()> {
41    for supported in SUPPORTED_VERSIONS {
42        if version.major() == supported.major() && version.minor() <= supported.minor() {
43            return Ok(());
44        }
45    }
46
47    Err(ProtocolError::UnsupportedVersion(version.major() as u8))
48}
49
50pub fn is_feature_supported(feature: u32) -> bool {
51    feature != 0 && feature <= 0x00000007
52}
53
54pub fn version_string(version: &ProtocolVersion) -> alloc::string::String {
55    use alloc::format;
56    format!("MemLink/{}.{}", version.major(), version.minor())
57}