cameleon/payload.rs
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! This module contains types related to `Payload` sent from the device.
6//!
7//! `Payload` is an abstracted container that is mainly used to transfer an image, but also meta data of the image.
8//! See [`Payload`] and [`ImageInfo`] for more details.
9
10pub use cameleon_device::PixelFormat;
11
12use std::time;
13
14use async_channel::{Receiver, Sender};
15
16use super::{StreamError, StreamResult};
17
18/// Represents Payload type of the image.
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub enum PayloadType {
21 /// Payload contains just an image data only.
22 Image,
23 /// Payload contains multiple data chunks, and its first chunk is an image.
24 ImageExtendedChunk,
25 /// Payload contains multiple data chunks, no gurantee about its first chunk.
26 Chunk,
27}
28
29/// Image meta information.
30#[derive(Clone, Debug, PartialEq, Eq)]
31pub struct ImageInfo {
32 /// Width of the image.
33 pub width: usize,
34 /// Height of the image.
35 pub height: usize,
36 /// X offset in pixels from the whole image origin. Some devices have capability of
37 /// sending multiple extracted image regions, this fields used for the purpose.
38 pub x_offset: usize,
39 /// Y offset in pixels from the whole image origin. Some devices have capability of
40 /// sending multiple extracted image regions, this fields used for the purpose.
41 pub y_offset: usize,
42 /// [`PixelFormat`] of the image.
43 pub pixel_format: PixelFormat,
44 /// Size of image in bytes.
45 pub image_size: usize,
46}
47
48/// A payload sent from the device.
49#[derive(Clone, Debug, PartialEq, Eq)]
50pub struct Payload {
51 pub(crate) id: u64,
52 pub(crate) payload_type: PayloadType,
53 pub(crate) image_info: Option<ImageInfo>,
54 pub(crate) payload: Vec<u8>,
55 pub(crate) valid_payload_size: usize,
56 pub(crate) timestamp: time::Duration,
57}
58
59impl Payload {
60 /// Returns [`PayloadType`] of the payload.
61 pub fn payload_type(&self) -> PayloadType {
62 self.payload_type
63 }
64
65 /// Returns [`ImageInfo`] if `payload_type` is [`PayloadType::Image`] or
66 /// [`PayloadType::ImageExtendedChunk`].
67 pub fn image_info(&self) -> Option<&ImageInfo> {
68 self.image_info.as_ref()
69 }
70
71 /// Returns the image bytes in the payload if `payload_type` is [`PayloadType::Image`] or
72 /// [`PayloadType::ImageExtendedChunk`].
73 pub fn image(&self) -> Option<&[u8]> {
74 let image_info = self.image_info()?;
75 Some(&self.payload[..image_info.image_size])
76 }
77
78 /// Returns the whole payload. Use [`Self::image`] instead if you interested only
79 /// in image region of the payload.
80 pub fn payload(&self) -> &[u8] {
81 &self.payload[..self.valid_payload_size]
82 }
83
84 /// Returns unique id of `payload`, which sequentially incremented every time the device send a
85 /// `payload`.
86 pub fn id(&self) -> u64 {
87 self.id
88 }
89
90 /// Timestamp of the device when the payload is generated.
91 pub fn timestamp(&self) -> time::Duration {
92 self.timestamp
93 }
94
95 /// Returns the payload as `Vec<u8>`.
96 pub fn into_vec(mut self) -> Vec<u8> {
97 self.payload.resize(self.valid_payload_size, 0);
98 self.payload
99 }
100}
101
102/// An Receiver of the `Payload` which is sent from a device.
103#[derive(Debug, Clone)]
104pub struct PayloadReceiver {
105 /// Sends back `payload` to the device for reusing it.
106 tx: Sender<Payload>,
107
108 /// Receives `payload` from the device.
109 rx: Receiver<StreamResult<Payload>>,
110}
111
112impl PayloadReceiver {
113 /// Receives [`Payload`] sent from the device.
114 pub async fn recv(&self) -> StreamResult<Payload> {
115 self.rx.recv().await?
116 }
117
118 /// Tries to receive [`Payload`].
119 /// This method doesn't wait arrival of `payload` and immediately returns `StreamError` if
120 /// the channel is empty.
121 pub fn try_recv(&self) -> StreamResult<Payload> {
122 self.rx.try_recv()?
123 }
124
125 /// Receives [`Payload`] sent from the device.
126 /// If the channel is empty, this method blocks until the device produces the payload.
127 pub fn recv_blocking(&self) -> StreamResult<Payload> {
128 self.rx.recv_blocking()?
129 }
130
131 /// Sends back [`Payload`] to the device to reuse already allocated `payload`.
132 ///
133 /// Sending back `payload` may improve performance of streaming, but not required to call this
134 /// method.
135 pub fn send_back(&self, payload: Payload) {
136 self.tx.try_send(payload).ok();
137 }
138}
139
140/// A sender of the [`Payload`] which is sent to the host.
141#[derive(Debug, Clone)]
142pub struct PayloadSender {
143 /// Receives from the device.
144 tx: Sender<StreamResult<Payload>>,
145 /// Sends back payload to reuse it.
146 rx: Receiver<Payload>,
147}
148
149impl PayloadSender {
150 /// Sends [`Payload`] to the host.
151 pub async fn send(&self, payload: StreamResult<Payload>) -> StreamResult<()> {
152 Ok(self.tx.send(payload).await?)
153 }
154
155 /// Tries to send [`Payload`] to the host.
156 /// Returns `StreamError` if the channel is full or empty.
157 pub fn try_send(&self, payload: StreamResult<Payload>) -> StreamResult<()> {
158 Ok(self.tx.try_send(payload)?)
159 }
160
161 /// Tries to receive [`Payload`].
162 /// This method doesn't wait arrival of `payload` and immediately returns `StreamError` if
163 /// the channel is empty.
164 pub fn try_recv(&self) -> StreamResult<Payload> {
165 Ok(self.rx.try_recv()?)
166 }
167}
168
169/// Creates [`PayloadReceiver`] and [`PayloadSender`].
170pub fn channel(payload_cap: usize, buffer_cap: usize) -> (PayloadSender, PayloadReceiver) {
171 let (device_tx, host_rx) = async_channel::bounded(payload_cap);
172 let (host_tx, device_rx) = async_channel::bounded(buffer_cap);
173 (
174 PayloadSender {
175 tx: device_tx,
176 rx: device_rx,
177 },
178 PayloadReceiver {
179 tx: host_tx,
180 rx: host_rx,
181 },
182 )
183}
184
185impl From<async_channel::RecvError> for StreamError {
186 fn from(err: async_channel::RecvError) -> Self {
187 StreamError::ReceiveError(err.to_string().into())
188 }
189}
190
191impl From<async_channel::TryRecvError> for StreamError {
192 fn from(err: async_channel::TryRecvError) -> Self {
193 StreamError::ReceiveError(err.to_string().into())
194 }
195}
196
197impl<T> From<async_channel::SendError<T>> for StreamError {
198 fn from(err: async_channel::SendError<T>) -> Self {
199 StreamError::ReceiveError(err.to_string().into())
200 }
201}
202
203impl<T> From<async_channel::TrySendError<T>> for StreamError {
204 fn from(err: async_channel::TrySendError<T>) -> Self {
205 StreamError::ReceiveError(err.to_string().into())
206 }
207}