use microdot::{
helpers::{Header, SerializeStructHelper, HEADER_SIZE},
Deserialize, MicrodotError, Serialize,
};
use crate::types::{Id, Version};
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug)]
pub struct CheckUpdateRequest<'a> {
pub program_id: Id<'a>,
pub release_channel_id: Id<'a>,
pub current_version: Version,
}
impl Serialize for CheckUpdateRequest<'_> {
fn serialize(&self, buf: &mut [u8]) -> Result<usize, MicrodotError> {
let mut helper = SerializeStructHelper::new(buf);
helper.serialize_fields(&[
&self.program_id,
&self.release_channel_id,
&self.current_version,
])
}
}
impl<'a> Deserialize<'a> for CheckUpdateRequest<'a> {
fn deserialize(buf: &'a [u8]) -> Result<Self, MicrodotError> {
let mut offset = 0;
let mut program_id = None;
let mut release_channel_id = None;
let mut current_version = None;
while offset < buf.len() {
let header = Header::deserialize(&buf[offset..offset + HEADER_SIZE])?;
let buf = &buf[offset + HEADER_SIZE..offset + HEADER_SIZE + header.size];
match header.id {
1 => {
program_id = Some(Id::deserialize(buf)?);
}
2 => {
release_channel_id = Some(Id::deserialize(buf)?);
}
3 => {
current_version = Some(Version::deserialize(buf)?);
}
_ => return Err(MicrodotError::invalid_payload()),
}
offset += HEADER_SIZE + header.size;
}
let Some(program_id) = program_id else {
return Err(MicrodotError::missing_field("program_id"));
};
let Some(release_channel_id) = release_channel_id else {
return Err(MicrodotError::missing_field("release_channel_id"));
};
let Some(current_version) = current_version else {
return Err(MicrodotError::missing_field("current_version"));
};
Ok(Self {
program_id,
release_channel_id,
current_version,
})
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug)]
pub struct CheckUpdateResponse {
pub next_version: Version,
}
impl Serialize for CheckUpdateResponse {
fn serialize(&self, buf: &mut [u8]) -> Result<usize, MicrodotError> {
let mut helper = SerializeStructHelper::new(buf);
helper.serialize_field(&self.next_version)
}
}
impl<'a> Deserialize<'a> for CheckUpdateResponse {
fn deserialize(buf: &'a [u8]) -> Result<Self, MicrodotError> {
let mut offset = 0;
let mut next_version = None;
while offset < buf.len() {
let header = Header::deserialize(&buf[offset..offset + HEADER_SIZE])?;
let buf = &buf[offset + HEADER_SIZE..offset + HEADER_SIZE + header.size];
match header.id {
1 => {
next_version = Some(Version::deserialize(buf)?);
}
_ => return Err(MicrodotError::invalid_payload()),
}
offset += HEADER_SIZE + header.size;
}
let Some(next_version) = next_version else {
return Err(MicrodotError::missing_field("next_version"));
};
Ok(Self { next_version })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn check_update_response_should_serialize() {
let payload = CheckUpdateResponse {
next_version: Version::new(1, 2, 3),
};
let mut buf = [0u8; 16];
match payload.serialize(&mut buf) {
Ok(bytes_written) => {
assert_eq!(bytes_written, 9);
assert_eq!(&buf[..bytes_written], &[1, 0, 6, 0, 1, 0, 2, 0, 3]);
}
Err(err) => {
dbg!(err);
unreachable!();
}
}
}
#[test]
fn check_update_response_should_deserialize() {
let buf = &[1, 0, 6, 0, 1, 0, 2, 0, 3];
match CheckUpdateResponse::deserialize(buf) {
Ok(response) => {
assert_eq!(response.next_version, Version::new(1, 2, 3,));
}
Err(err) => {
dbg!(err);
unreachable!();
}
}
}
}