nimble_blob_stream/
out_logic.rs1use 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 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 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}