Skip to main content

nimbi_protocol/messages/
check_update.rs

1use microdot::{
2    helpers::{Header, SerializeStructHelper, HEADER_SIZE},
3    Deserialize, MicrodotError, Serialize,
4};
5
6use crate::types::{Id, Version};
7
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9#[derive(Debug)]
10pub struct CheckUpdateRequest<'a> {
11    pub program_id: Id<'a>,
12    pub release_channel_id: Id<'a>,
13    pub current_version: Version,
14}
15
16impl Serialize for CheckUpdateRequest<'_> {
17    fn serialize(&self, buf: &mut [u8]) -> Result<usize, MicrodotError> {
18        let mut helper = SerializeStructHelper::new(buf);
19
20        helper.serialize_fields(&[
21            &self.program_id,
22            &self.release_channel_id,
23            &self.current_version,
24        ])
25    }
26}
27
28impl<'a> Deserialize<'a> for CheckUpdateRequest<'a> {
29    fn deserialize(buf: &'a [u8]) -> Result<Self, MicrodotError> {
30        let mut offset = 0;
31
32        let mut program_id = None;
33        let mut release_channel_id = None;
34        let mut current_version = None;
35
36        while offset < buf.len() {
37            let header = Header::deserialize(&buf[offset..offset + HEADER_SIZE])?;
38            let buf = &buf[offset + HEADER_SIZE..offset + HEADER_SIZE + header.size];
39
40            match header.id {
41                1 => {
42                    program_id = Some(Id::deserialize(buf)?);
43                }
44                2 => {
45                    release_channel_id = Some(Id::deserialize(buf)?);
46                }
47                3 => {
48                    current_version = Some(Version::deserialize(buf)?);
49                }
50                _ => return Err(MicrodotError::invalid_payload()),
51            }
52
53            offset += HEADER_SIZE + header.size;
54        }
55
56        let Some(program_id) = program_id else {
57            return Err(MicrodotError::missing_field("program_id"));
58        };
59
60        let Some(release_channel_id) = release_channel_id else {
61            return Err(MicrodotError::missing_field("release_channel_id"));
62        };
63
64        let Some(current_version) = current_version else {
65            return Err(MicrodotError::missing_field("current_version"));
66        };
67
68        Ok(Self {
69            program_id,
70            release_channel_id,
71            current_version,
72        })
73    }
74}
75
76#[cfg_attr(feature = "defmt", derive(defmt::Format))]
77#[derive(Debug)]
78pub struct CheckUpdateResponse {
79    pub next_version: Version,
80}
81
82impl Serialize for CheckUpdateResponse {
83    fn serialize(&self, buf: &mut [u8]) -> Result<usize, MicrodotError> {
84        let mut helper = SerializeStructHelper::new(buf);
85
86        helper.serialize_field(&self.next_version)
87    }
88}
89
90impl<'a> Deserialize<'a> for CheckUpdateResponse {
91    fn deserialize(buf: &'a [u8]) -> Result<Self, MicrodotError> {
92        let mut offset = 0;
93
94        let mut next_version = None;
95
96        while offset < buf.len() {
97            let header = Header::deserialize(&buf[offset..offset + HEADER_SIZE])?;
98            let buf = &buf[offset + HEADER_SIZE..offset + HEADER_SIZE + header.size];
99
100            match header.id {
101                1 => {
102                    next_version = Some(Version::deserialize(buf)?);
103                }
104                _ => return Err(MicrodotError::invalid_payload()),
105            }
106
107            offset += HEADER_SIZE + header.size;
108        }
109
110        let Some(next_version) = next_version else {
111            return Err(MicrodotError::missing_field("next_version"));
112        };
113
114        Ok(Self { next_version })
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121
122    #[test]
123    fn check_update_response_should_serialize() {
124        let payload = CheckUpdateResponse {
125            next_version: Version::new(1, 2, 3),
126        };
127
128        let mut buf = [0u8; 16];
129
130        match payload.serialize(&mut buf) {
131            Ok(bytes_written) => {
132                assert_eq!(bytes_written, 9);
133                assert_eq!(&buf[..bytes_written], &[1, 0, 6, 0, 1, 0, 2, 0, 3]);
134            }
135            Err(err) => {
136                dbg!(err);
137
138                unreachable!();
139            }
140        }
141    }
142
143    #[test]
144    fn check_update_response_should_deserialize() {
145        let buf = &[1, 0, 6, 0, 1, 0, 2, 0, 3];
146
147        match CheckUpdateResponse::deserialize(buf) {
148            Ok(response) => {
149                assert_eq!(response.next_version, Version::new(1, 2, 3,));
150            }
151            Err(err) => {
152                dbg!(err);
153
154                unreachable!();
155            }
156        }
157    }
158}