Skip to main content

nautilus_protocol/
version.rs

1//! Protocol versioning and compatibility checking.
2
3use crate::error::{ProtocolError, Result};
4
5/// Current Nautilus protocol version.
6///
7/// This version must be included in all client requests.
8pub const PROTOCOL_VERSION: u32 = 1;
9
10/// Minimum protocol version accepted by the engine.
11pub const MIN_PROTOCOL_VERSION: u32 = 1;
12
13/// Protocol version wrapper with validation.
14///
15/// Provides structured version checking as an alternative to comparing
16/// against [`PROTOCOL_VERSION`] directly. The engine currently validates
17/// versions inline, but consumers that prefer a typed wrapper can use this.
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub struct ProtocolVersion(u32);
20
21impl ProtocolVersion {
22    /// Create a new protocol version.
23    pub fn new(version: u32) -> Self {
24        Self(version)
25    }
26
27    /// Get the version number.
28    pub fn version(&self) -> u32 {
29        self.0
30    }
31
32    /// Check if this version is compatible with the current protocol.
33    /// Accepts any version in the range [MIN_PROTOCOL_VERSION, PROTOCOL_VERSION].
34    pub fn is_compatible(&self) -> bool {
35        self.0 >= MIN_PROTOCOL_VERSION && self.0 <= PROTOCOL_VERSION
36    }
37
38    /// Validate that this version is compatible, returning an error if not.
39    pub fn validate(&self) -> Result<()> {
40        if self.is_compatible() {
41            Ok(())
42        } else {
43            Err(ProtocolError::UnsupportedProtocolVersion {
44                actual: self.0,
45                expected: PROTOCOL_VERSION,
46            })
47        }
48    }
49}
50
51impl From<u32> for ProtocolVersion {
52    fn from(version: u32) -> Self {
53        Self(version)
54    }
55}
56
57impl From<ProtocolVersion> for u32 {
58    fn from(version: ProtocolVersion) -> Self {
59        version.0
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn test_current_version_is_compatible() {
69        let version = ProtocolVersion::new(PROTOCOL_VERSION);
70        assert!(version.is_compatible());
71        assert!(version.validate().is_ok());
72    }
73
74    #[test]
75    fn test_v1_is_still_compatible() {
76        let version = ProtocolVersion::new(1);
77        assert!(version.is_compatible());
78        assert!(version.validate().is_ok());
79    }
80
81    #[test]
82    fn test_incompatible_version() {
83        let version = ProtocolVersion::new(999);
84        assert!(!version.is_compatible());
85        assert!(version.validate().is_err());
86    }
87
88    #[test]
89    fn test_version_zero_incompatible() {
90        let version = ProtocolVersion::new(0);
91        assert!(!version.is_compatible());
92        assert!(version.validate().is_err());
93    }
94
95    #[test]
96    fn test_version_conversion() {
97        let v1 = ProtocolVersion::from(42);
98        assert_eq!(v1.version(), 42);
99
100        let v2: u32 = v1.into();
101        assert_eq!(v2, 42);
102    }
103
104    #[test]
105    fn test_version_error_message() {
106        let version = ProtocolVersion::new(5);
107        let result = version.validate();
108        assert!(result.is_err());
109
110        let err = result.unwrap_err();
111        let msg = err.to_string();
112        assert!(msg.contains("5"));
113        assert!(msg.contains(&PROTOCOL_VERSION.to_string()));
114    }
115}