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