1use core::cmp;
5
6use crate::{
7 channel::Channel,
8 command::Command,
9 error::{DefragmentationError, FragmentationError},
10 packet::{
11 ContinuationPacket, InitializationPacket, Packet, PacketType, CONTINUATION_HEADER_SIZE,
12 INITIALIZATION_HEADER_SIZE,
13 },
14};
15
16#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
22pub struct Message<T: AsRef<[u8]>> {
23 pub channel: Channel,
25 pub command: Command,
27 pub data: T,
29}
30
31impl<T: AsRef<[u8]>> Message<T> {
32 pub fn fragments(&self, packet_size: usize) -> Result<Fragments<'_>, FragmentationError> {
38 Fragments::new(self, packet_size)
39 }
40}
41
42impl<T: AsRef<[u8]> + Default + Extend<u8>> Message<T> {
43 pub fn from_fragments<S: AsRef<[u8]>>(
50 packet: InitializationPacket<S>,
51 ) -> DefragmentedMessage<T> {
52 packet.into()
53 }
54
55 pub fn try_from_fragments<S: AsRef<[u8]>>(
65 packet: Packet<S>,
66 ) -> Result<DefragmentedMessage<T>, DefragmentationError> {
67 if let Packet::Initialization(packet) = packet {
68 Ok(Self::from_fragments(packet))
69 } else {
70 Err(DefragmentationError::InvalidPacketType {
71 expected: PacketType::Initialization,
72 actual: packet.packet_type(),
73 })
74 }
75 }
76}
77
78#[derive(Clone, Debug)]
84pub struct Fragments<'a> {
85 channel: Channel,
86 init: Option<InitializationPacket<&'a [u8]>>,
87 chunks: core::iter::Enumerate<core::slice::Chunks<'a, u8>>,
88}
89
90impl<'a> Fragments<'a> {
91 fn new<T: AsRef<[u8]>>(
92 message: &'a Message<T>,
93 packet_size: usize,
94 ) -> Result<Self, FragmentationError> {
95 if INITIALIZATION_HEADER_SIZE >= packet_size || CONTINUATION_HEADER_SIZE >= packet_size {
96 return Err(FragmentationError::PacketSizeTooSmall);
97 }
98 let data_size_init = packet_size - INITIALIZATION_HEADER_SIZE;
99 let data_size_cont = packet_size - CONTINUATION_HEADER_SIZE;
100 if message.data.as_ref().len() > data_size_init + 128 * data_size_cont {
101 return Err(FragmentationError::DataTooLong);
102 }
103 let n = cmp::min(data_size_init, message.data.as_ref().len());
104 let (data_init, data_cont) = message.data.as_ref().split_at(n);
105 let init = InitializationPacket {
106 channel: message.channel,
107 command: message.command,
108 length: message.data.as_ref().len() as u16,
109 data: data_init,
110 };
111 Ok(Self {
112 channel: message.channel,
113 init: Some(init),
114 chunks: data_cont.chunks(data_size_cont).enumerate(),
115 })
116 }
117}
118
119impl<'a> Iterator for Fragments<'a> {
120 type Item = Packet<&'a [u8]>;
121
122 fn next(&mut self) -> Option<Self::Item> {
123 if let Some(init) = self.init.take() {
124 Some(Packet::Initialization(init))
125 } else if let Some((sequence, data)) = self.chunks.next() {
126 Some(Packet::Continuation(ContinuationPacket {
127 channel: self.channel,
128 sequence: sequence as u8,
129 data,
130 }))
131 } else {
132 None
133 }
134 }
135}
136
137#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
143pub enum DefragmentedMessage<T: AsRef<[u8]> + Default + Extend<u8>> {
144 Complete(Message<T>),
146 Partial(PartialMessage<T>),
148}
149
150impl<T: AsRef<[u8]> + Default + Extend<u8>, S: AsRef<[u8]>> From<InitializationPacket<S>>
151 for DefragmentedMessage<T>
152{
153 fn from(packet: InitializationPacket<S>) -> Self {
154 PartialMessage::from(packet).into()
155 }
156}
157
158impl<T: AsRef<[u8]> + Default + Extend<u8>> From<PartialMessage<T>> for DefragmentedMessage<T> {
159 fn from(message: PartialMessage<T>) -> Self {
160 if message.length == message.data.as_ref().len() {
161 Self::Complete(Message {
162 channel: message.channel,
163 command: message.command,
164 data: message.data,
165 })
166 } else {
167 Self::Partial(message)
168 }
169 }
170}
171
172#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
174pub struct PartialMessage<T: AsRef<[u8]> + Default + Extend<u8>> {
175 channel: Channel,
176 command: Command,
177 length: usize,
178 data: T,
179 next_sequence: u8,
180}
181
182impl<T: AsRef<[u8]> + Default + Extend<u8>> PartialMessage<T> {
183 pub fn extend<S: AsRef<[u8]>>(
185 mut self,
186 packet: &ContinuationPacket<S>,
187 ) -> Result<DefragmentedMessage<T>, DefragmentationError> {
188 if self.channel != packet.channel {
189 return Err(DefragmentationError::InvalidChannel {
190 expected: self.channel,
191 actual: packet.channel,
192 });
193 }
194 if self.next_sequence != packet.sequence {
195 return Err(DefragmentationError::InvalidSequence {
196 expected: self.next_sequence,
197 actual: packet.sequence,
198 });
199 }
200 self.extend_data(packet.data.as_ref());
201 self.next_sequence += 1;
202 Ok(self.into())
203 }
204
205 pub fn try_extend<S: AsRef<[u8]>>(
210 self,
211 packet: &Packet<S>,
212 ) -> Result<DefragmentedMessage<T>, DefragmentationError> {
213 if let Packet::Continuation(packet) = packet {
214 self.extend(packet)
215 } else {
216 Err(DefragmentationError::InvalidPacketType {
217 expected: PacketType::Continuation,
218 actual: packet.packet_type(),
219 })
220 }
221 }
222
223 fn extend_data(&mut self, data: &[u8]) {
224 let n = cmp::min(data.len(), self.length - self.data.as_ref().len());
226 self.data.extend(data[..n].iter().cloned());
227 }
228}
229
230impl<T: AsRef<[u8]> + Default + Extend<u8>, S: AsRef<[u8]>> From<InitializationPacket<S>>
231 for PartialMessage<T>
232{
233 fn from(packet: InitializationPacket<S>) -> Self {
234 let mut message = Self {
236 channel: packet.channel,
237 command: packet.command,
238 length: usize::from(packet.length),
239 data: T::default(),
240 next_sequence: 0,
241 };
242 message.extend_data(packet.data.as_ref());
243 message
244 }
245}
246
247#[cfg(test)]
248mod test {
249 use quickcheck::Arbitrary;
250
251 use super::{DefragmentedMessage, Message};
252
253 impl Arbitrary for Message<Vec<u8>> {
254 fn arbitrary(g: &mut quickcheck::Gen) -> Self {
255 Self {
256 channel: Arbitrary::arbitrary(g),
257 command: Arbitrary::arbitrary(g),
258 data: Arbitrary::arbitrary(g),
259 }
260 }
261
262 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
263 let channel = self.channel;
264 let command = self.command;
265 Box::new(self.data.shrink().map(move |data| Self {
266 channel,
267 command,
268 data,
269 }))
270 }
271 }
272
273 quickcheck::quickcheck! {
274 fn fragments(message: Message<Vec<u8>>) -> bool {
275 use std::convert::TryInto;
276
277 let mut d: Option<DefragmentedMessage<Vec<u8>>> = None;
278 for fragment in message.fragments(64).unwrap() {
279 if let Some(dm) = d.take() {
280 match dm {
281 DefragmentedMessage::Partial(p) => {
282 d = Some(p.extend(&fragment.try_into().unwrap()).unwrap());
283 },
284 DefragmentedMessage::Complete(_) => unreachable!(),
285 }
286 } else {
287 d = Some(Message::from_fragments(fragment.try_into().unwrap()));
288 }
289 }
290
291 match d.unwrap() {
292 DefragmentedMessage::Partial(_) => false,
293 DefragmentedMessage::Complete(m) => m == message,
294 }
295 }
296 }
297}