nimble_blob_stream/
protocol_front.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/nimble-rust/nimble
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use crate::protocol::{AckChunkData, SetChunkData, StartTransferData, TransferId};
6use flood_rs::{ReadOctetStream, WriteOctetStream};
7use std::fmt::Display;
8use std::io;
9use std::io::ErrorKind;
10
11#[derive(Debug, Clone, Eq, PartialEq)]
12pub struct SetChunkFrontData {
13    pub transfer_id: TransferId,
14    pub data: SetChunkData,
15}
16
17impl SetChunkFrontData {
18    /// # Errors
19    ///
20    /// This function will return an `io::Error` if there is an issue with writing to the stream.
21    /// This could happen if the stream is closed or if there are underlying I/O errors during the write operation.
22    #[allow(clippy::cast_possible_truncation)]
23    pub fn to_stream(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
24        self.transfer_id.to_stream(stream)?;
25        self.data.to_stream(stream)?;
26        Ok(())
27    }
28
29    /// # Errors
30    ///
31    /// This function will return an `io::Error` if there is an issue with writing to the stream.
32    /// This could happen if the stream is closed or if there are underlying I/O errors during the write operation.
33    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
34        Ok(Self {
35            transfer_id: TransferId::from_stream(stream)?,
36            data: SetChunkData::from_stream(stream)?,
37        })
38    }
39}
40
41#[derive(Debug, Clone, Eq, PartialEq)]
42pub enum SenderToReceiverFrontCommands {
43    SetChunk(SetChunkFrontData),
44    StartTransfer(StartTransferData),
45}
46
47impl Display for SenderToReceiverFrontCommands {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        match self {
50            Self::SetChunk(set_chunk_data) => write!(
51                f,
52                "set_chunk transfer{} index:{} chunk_size:{}",
53                set_chunk_data.transfer_id.0,
54                set_chunk_data.data.chunk_index,
55                set_chunk_data.data.payload.len()
56            ),
57            Self::StartTransfer(transfer_data) => {
58                write!(f, "start transfer {transfer_data:?}")
59            }
60        }
61    }
62}
63
64#[repr(u8)]
65enum SenderToReceiverFrontCommand {
66    SetChunk = 0x01,
67    StartTransfer = 0x02,
68}
69
70impl TryFrom<u8> for SenderToReceiverFrontCommand {
71    type Error = io::Error;
72
73    fn try_from(value: u8) -> io::Result<Self> {
74        Ok(match value {
75            0x01 => Self::SetChunk,
76            0x02 => Self::StartTransfer,
77            _ => Err(io::Error::new(
78                ErrorKind::InvalidData,
79                format!("Unknown SenderToReceiverFrontCommand {value}"),
80            ))?,
81        })
82    }
83}
84
85impl SenderToReceiverFrontCommands {
86    #[must_use]
87    pub const fn to_octet(&self) -> u8 {
88        match self {
89            Self::SetChunk(_) => SenderToReceiverFrontCommand::SetChunk as u8,
90            Self::StartTransfer(_) => SenderToReceiverFrontCommand::StartTransfer as u8,
91        }
92    }
93
94    /// # Errors
95    ///
96    /// This function will return an `io::Error` if there is an issue with writing to the stream.
97    /// This could happen if the stream is closed or if there are underlying I/O errors during the write operation.
98
99    pub fn to_stream(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
100        stream.write_u8(self.to_octet())?;
101        match self {
102            Self::SetChunk(set_chunk_header) => set_chunk_header.to_stream(stream),
103            Self::StartTransfer(transfer_data) => transfer_data.to_stream(stream),
104        }
105    }
106
107    /// # Errors
108    ///
109    /// This function will return an `io::Error` if there is an issue with writing to the stream.
110    /// This could happen if the stream is closed or if there are underlying I/O errors during the write operation.
111    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
112        let command_value = stream.read_u8()?;
113        let command = SenderToReceiverFrontCommand::try_from(command_value)?;
114        let x = match command {
115            SenderToReceiverFrontCommand::SetChunk => {
116                Self::SetChunk(SetChunkFrontData::from_stream(stream)?)
117            }
118            SenderToReceiverFrontCommand::StartTransfer => {
119                Self::StartTransfer(StartTransferData::from_stream(stream)?)
120            }
121        };
122        Ok(x)
123    }
124}
125
126#[repr(u8)]
127enum ReceiverToSenderFrontCommand {
128    AckStart = 0x03,
129    AckChunk = 0x04,
130}
131
132impl TryFrom<u8> for ReceiverToSenderFrontCommand {
133    type Error = io::Error;
134
135    fn try_from(value: u8) -> io::Result<Self> {
136        Ok(match value {
137            0x03 => Self::AckStart,
138            0x04 => Self::AckChunk,
139            _ => Err(io::Error::new(
140                ErrorKind::InvalidData,
141                format!("Unknown ReceiverToSenderFrontCommand {value}"),
142            ))?,
143        })
144    }
145}
146
147#[derive(Debug, Clone, Eq, PartialEq)]
148pub struct AckChunkFrontData {
149    pub transfer_id: TransferId,
150    pub data: AckChunkData,
151}
152
153impl AckChunkFrontData {
154    /// # Errors
155    ///
156    /// This function will return an `io::Error` if there is an issue with writing to the stream.
157    /// This could happen if the stream is closed or if there are underlying I/O errors during the write operation.
158    pub fn to_stream(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
159        self.transfer_id.to_stream(stream)?;
160        self.data.to_stream(stream)
161    }
162
163    /// # Errors
164    ///
165    /// This function will return an `io::Error` if there is an issue with writing to the stream.
166    /// This could happen if the stream is closed or if there are underlying I/O errors during the write operation.
167    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
168        Ok(Self {
169            transfer_id: TransferId::from_stream(stream)?,
170            data: AckChunkData::from_stream(stream)?,
171        })
172    }
173}
174
175#[derive(Debug, Clone, Eq, PartialEq)]
176pub enum ReceiverToSenderFrontCommands {
177    AckChunk(AckChunkFrontData),
178    AckStart(u16),
179}
180
181impl ReceiverToSenderFrontCommands {
182    #[must_use]
183    pub const fn to_octet(&self) -> u8 {
184        match self {
185            Self::AckChunk(_) => ReceiverToSenderFrontCommand::AckChunk as u8,
186            Self::AckStart(_) => ReceiverToSenderFrontCommand::AckStart as u8,
187        }
188    }
189
190    /// # Errors
191    ///
192    /// This function will return an `io::Error` if there is an issue with writing to the stream.
193    /// This could happen if the stream is closed or if there are underlying I/O errors during the write operation.
194    pub fn to_stream(&self, stream: &mut impl WriteOctetStream) -> io::Result<()> {
195        stream.write_u8(self.to_octet())?;
196        match self {
197            Self::AckChunk(set_chunk_header) => set_chunk_header.to_stream(stream),
198            Self::AckStart(transfer_id) => stream.write_u16(*transfer_id),
199        }
200    }
201
202    /// # Errors
203    ///
204    /// This function will return an `io::Error` if there is an issue with writing to the stream.
205    /// This could happen if the stream is closed or if there are underlying I/O errors during the write operation.
206    pub fn from_stream(stream: &mut impl ReadOctetStream) -> io::Result<Self> {
207        let command_value = stream.read_u8()?;
208        let command = ReceiverToSenderFrontCommand::try_from(command_value)?;
209        let x = match command {
210            ReceiverToSenderFrontCommand::AckChunk => Self::AckChunk(AckChunkFrontData {
211                transfer_id: TransferId::from_stream(stream)?,
212                data: AckChunkData::from_stream(stream)?,
213            }),
214            ReceiverToSenderFrontCommand::AckStart => Self::AckStart(stream.read_u16()?),
215        };
216        Ok(x)
217    }
218}