fluvio_dataplane_protocol/
versions.rs

1use std::io::{Error as IoError, ErrorKind};
2use fluvio_protocol::{Encoder, Version, Decoder};
3use fluvio_protocol::bytes::{BufMut, Buf};
4
5use crate::ErrorCode;
6use crate::api::Request;
7
8pub const VERSIONS_API_KEY: u16 = 18;
9
10// -----------------------------------
11// ApiVersionsRequest
12// -----------------------------------
13
14#[derive(Decoder, Encoder, Default, Debug)]
15pub struct ApiVersionsRequest {
16    #[fluvio(min_version = 1)]
17    pub client_version: String,
18    #[fluvio(min_version = 1)]
19    pub client_os: String,
20    #[fluvio(min_version = 1)]
21    pub client_arch: String,
22}
23
24impl Request for ApiVersionsRequest {
25    const API_KEY: u16 = VERSIONS_API_KEY;
26    const DEFAULT_API_VERSION: i16 = 1;
27    type Response = ApiVersionsResponse;
28}
29
30// -----------------------------------
31// ApiVersionsResponse
32// -----------------------------------
33
34pub type ApiVersions = Vec<ApiVersionKey>;
35
36#[derive(Decoder, Encoder, Default, Debug, PartialEq)]
37pub struct ApiVersionsResponse {
38    pub error_code: ErrorCode,
39    pub api_keys: ApiVersions,
40    pub platform_version: PlatformVersion,
41}
42
43#[derive(Decoder, Encoder, Default, Clone, Debug, PartialEq)]
44pub struct ApiVersionKey {
45    pub api_key: i16,
46    pub min_version: i16,
47    pub max_version: i16,
48}
49
50#[derive(Debug, PartialEq)]
51pub struct PlatformVersion(String);
52
53impl PlatformVersion {
54    /// Creates a `semver::Version` object of the inner version
55    pub fn to_semver(&self) -> semver::Version {
56        // This is safe because of this type's invariant:
57        // The only ways to construct it are From<semver::Version>,
58        // via the Decoder trait, or by Default. The Decoder impl explicitly
59        // checks that the inner string is Semver, and the Default impl
60        // directly constructs a Semver and stringifies it. Therefore this
61        // unwrapping is safe.
62        semver::Version::parse(&self.0)
63            .expect("Broken Invariant: PlatformVersion can only be constructed with Semver")
64    }
65}
66
67impl From<semver::Version> for PlatformVersion {
68    fn from(version: semver::Version) -> Self {
69        Self(version.to_string())
70    }
71}
72
73impl Default for PlatformVersion {
74    fn default() -> Self {
75        Self(semver::Version::new(0, 0, 0).to_string())
76    }
77}
78
79impl Decoder for PlatformVersion {
80    /// Wrap the decoder for the string inside
81    fn decode<T>(&mut self, src: &mut T, version: i16) -> Result<(), IoError>
82    where
83        T: Buf,
84    {
85        // Decoder the data as a String
86        let mut string = String::default();
87        string.decode(src, version)?;
88
89        // Before constructing, ensure that what was decoded is valid Semver
90        let _version = semver::Version::parse(&string).map_err(|_| {
91            IoError::new(
92                ErrorKind::InvalidData,
93                "PlatformVersion is not valid semver",
94            )
95        })?;
96
97        // Construct PlatformVersion with semver string
98        self.0 = string;
99        Ok(())
100    }
101}
102
103impl Encoder for PlatformVersion {
104    fn write_size(&self, version: Version) -> usize {
105        self.0.write_size(version)
106    }
107
108    fn encode<T>(&self, dest: &mut T, version: Version) -> Result<(), IoError>
109    where
110        T: BufMut,
111    {
112        self.0.encode(dest, version)
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn test_encode_platform_version() {
122        let version = semver::Version::parse("1.2.3-alpha.4+56789").unwrap();
123        let version_string = version.to_string();
124        let platform_version = PlatformVersion::from(version);
125
126        // Check encoding matches
127        let mut version_string_buffer: Vec<u8> = vec![];
128        version_string
129            .encode(&mut version_string_buffer, 0)
130            .unwrap();
131        let mut platform_version_buffer: Vec<u8> = vec![];
132        platform_version
133            .encode(&mut platform_version_buffer, 0)
134            .unwrap();
135        assert_eq!(version_string_buffer, platform_version_buffer);
136
137        // Check round-trip encode/decode for PlatformVersion
138        let mut decoded_platform_version = PlatformVersion::default();
139        decoded_platform_version
140            .decode(&mut (&*platform_version_buffer), 0)
141            .unwrap();
142        assert_eq!(platform_version, decoded_platform_version);
143    }
144
145    #[test]
146    fn test_encode_decode_api_versions_response() {
147        fn api_versions() -> ApiVersionsResponse {
148            let version = semver::Version::parse("0.1.2-alpha.3+4567").unwrap();
149            let platform_version = PlatformVersion::from(version);
150            ApiVersionsResponse {
151                error_code: ErrorCode::None,
152                api_keys: vec![],
153                platform_version,
154            }
155        }
156
157        let api_version = api_versions();
158        let mut api_versions_buffer: Vec<u8> = vec![];
159        api_version.encode(&mut api_versions_buffer, 0).unwrap();
160
161        let mut decoded_api_version = ApiVersionsResponse::default();
162        decoded_api_version
163            .decode(&mut (&*api_versions_buffer), 0)
164            .unwrap();
165
166        assert_eq!(api_version, decoded_api_version);
167    }
168}