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}