nimble_blob_stream/
out_logic.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::out_stream::{BlobStreamOut, OutStreamError};
6use crate::prelude::{SetChunkData, SetChunkFrontData, TransferId};
7use monotonic_time_rs::Millis;
8use std::time::Duration;
9
10#[allow(unused)]
11#[derive(Debug)]
12pub struct Logic {
13    out_stream: BlobStreamOut,
14    blob: Vec<u8>,
15    fixed_chunk_size: u16,
16    transfer_id: TransferId,
17}
18
19impl Logic {
20    /// # Errors
21    /// `OutStreamError` // TODO:
22    pub fn new(
23        transfer_id: TransferId,
24        fixed_chunk_size: u16,
25        resend_duration: Duration,
26        blob: &[u8],
27    ) -> Result<Self, OutStreamError> {
28        let chunk_count = blob.len().div_ceil(fixed_chunk_size as usize);
29        let chunk_count = u32::try_from(chunk_count).map_err(OutStreamError::BlobIsTooLarge)?;
30        Ok(Self {
31            out_stream: BlobStreamOut::new(chunk_count, resend_duration),
32            blob: blob.to_vec(),
33            transfer_id,
34            fixed_chunk_size,
35        })
36    }
37
38    #[must_use]
39    #[inline]
40    fn get_range(&self, index: u32) -> Option<(usize, usize)> {
41        if index >= self.out_stream.chunk_count() {
42            return None;
43        }
44        let is_last_chunk = index + 1 == self.out_stream.chunk_count();
45        let count = if is_last_chunk {
46            let remaining_size = self.blob.len() % (self.fixed_chunk_size as usize);
47            if remaining_size == 0 {
48                self.fixed_chunk_size
49            } else {
50                remaining_size as u16
51            }
52        } else {
53            self.fixed_chunk_size
54        };
55        let start = index * self.fixed_chunk_size as u32;
56        assert!(
57            start < self.blob.len() as u32,
58            "out logic index out of bounds"
59        );
60        assert!(
61            (start + count as u32) <= (self.blob.len() as u32),
62            "out logic index out of bounds"
63        );
64
65        Some((start as usize, start as usize + count as usize))
66    }
67
68    #[must_use]
69    #[allow(clippy::missing_panics_doc)]
70    pub fn send(&mut self, now: Millis, max_count: usize) -> Vec<SetChunkFrontData> {
71        let indices = self.out_stream.send(now, max_count);
72        let mut set_chunks = Vec::new();
73        for chunk_index in indices {
74            let (start, end) = self
75                .get_range(chunk_index)
76                .expect("indices returned should be valid");
77            let payload = &self.blob[start..end];
78            let set_chunk = SetChunkFrontData {
79                transfer_id: self.transfer_id,
80                data: SetChunkData {
81                    chunk_index,
82                    payload: payload.to_vec(),
83                },
84            };
85            set_chunks.push(set_chunk);
86        }
87        set_chunks
88    }
89
90    /// # Errors
91    /// `OutStreamError` // TODO:
92    pub fn set_waiting_for_chunk_index(
93        &mut self,
94        waiting_for_index: usize,
95        receive_mask: u64,
96    ) -> Result<(), OutStreamError> {
97        self.out_stream
98            .set_waiting_for_chunk_index(waiting_for_index, receive_mask)
99    }
100
101    #[must_use]
102    pub fn is_received_by_remote(&self) -> bool {
103        self.out_stream.is_received_by_remote()
104    }
105
106    #[must_use]
107    pub fn octet_size(&self) -> u32 {
108        self.blob.len() as u32
109    }
110
111    #[must_use]
112    pub const fn chunk_size(&self) -> u16 {
113        self.fixed_chunk_size
114    }
115
116    #[must_use]
117    pub const fn transfer_id(&self) -> TransferId {
118        self.transfer_id
119    }
120}