dope_core/io/transfer/
progress.rs1use std::mem;
2
3use o3::buffer::{self, segments::scatter};
4
5use crate::io::transfer;
6
7pub struct Bytes<'data> {
9 bytes: &'data [u8],
10 progress: State,
11}
12
13#[must_use = "the selected bytes must either be committed or left untouched"]
15pub struct Slice<'a, 'data> {
16 bytes: &'data [u8],
17 step: Step<'a>,
18}
19
20impl<'data> Bytes<'data> {
21 #[must_use]
22 pub fn new(view: transfer::View<'data>) -> Self {
23 let (bytes, len) = view.into_parts();
24 Self {
25 bytes,
26 progress: State::new(len),
27 }
28 }
29
30 #[must_use]
31 pub const fn is_empty(&self) -> bool {
32 self.progress.is_empty()
33 }
34
35 pub fn take(&mut self, limit: transfer::Len) -> Slice<'_, 'data> {
36 let start = self.bytes.len() - self.progress.left().into_raw();
37 let step = self.progress.reserve(limit);
38 let end = start + step.amount().into_raw();
39 let bytes = unsafe { self.bytes.get_unchecked(start..end) };
43 Slice { bytes, step }
44 }
45
46 #[must_use]
47 pub const fn into_len(self) -> transfer::Len {
48 self.progress.len()
49 }
50}
51
52impl Slice<'_, '_> {
53 #[must_use]
54 pub const fn as_slice(&self) -> &[u8] {
55 self.bytes
56 }
57
58 #[must_use]
59 pub const fn amount(&self) -> transfer::Len {
60 self.step.amount()
61 }
62
63 pub fn commit(self) {
64 self.step.commit();
65 }
66}
67
68const _: () =
69 assert!(mem::size_of::<Bytes<'_>>() == mem::size_of::<&[u8]>() + mem::size_of::<State>());
70
71#[derive(Clone, Copy, Eq, PartialEq)]
73pub struct Exceeded {
74 requested: transfer::Len,
75 available: transfer::Len,
76}
77
78impl Exceeded {
79 const fn new(req: transfer::Len, avail: transfer::Len) -> Self {
80 Self {
81 requested: req,
82 available: avail,
83 }
84 }
85
86 pub const fn requested(self) -> transfer::Len {
87 self.requested
88 }
89
90 pub const fn available(self) -> transfer::Len {
91 self.available
92 }
93}
94
95pub struct State {
97 limit: transfer::Len,
98 remaining: transfer::Len,
99}
100
101impl State {
102 #[must_use]
103 pub const fn new(limit: transfer::Len) -> Self {
104 Self {
105 limit,
106 remaining: limit,
107 }
108 }
109
110 #[must_use]
111 pub const fn is_empty(&self) -> bool {
112 self.remaining.is_zero()
113 }
114
115 #[must_use]
117 pub const fn left(&self) -> transfer::Len {
118 self.remaining
119 }
120
121 #[must_use]
122 pub const fn len(&self) -> transfer::Len {
123 self.limit.abs_diff(self.remaining)
124 }
125
126 pub fn reserve(&mut self, limit: transfer::Len) -> Step<'_> {
127 let amount = limit.min(self.remaining);
128 Step {
129 progress: self,
130 amount,
131 }
132 }
133
134 pub fn scatter<'a>(
136 &mut self,
137 cursor: &mut impl buffer::raw::Scatter<'a>,
138 ) -> Option<buffer::raw::Chunk<'a, { transfer::MAX_BYTES }>> {
139 let chunk = scatter::Take::new(cursor, self.remaining.into_raw())
140 .next_chunk::<{ transfer::MAX_BYTES }>()?;
141 let count = transfer::Len::from_count(chunk.len().into_count());
142 self.remaining = self.remaining.abs_diff(count);
143 Some(chunk)
144 }
145
146 pub fn try_extend(&self, amount: transfer::Len) -> Result<Self, Exceeded> {
148 if amount.is_greater(self.remaining) {
149 return Err(Exceeded::new(amount, self.remaining));
150 }
151 Ok(Self {
152 limit: self.limit,
153 remaining: self.remaining.abs_diff(amount),
154 })
155 }
156}
157
158pub struct Step<'a> {
160 progress: &'a mut State,
161 amount: transfer::Len,
162}
163
164impl Step<'_> {
165 #[must_use]
167 pub const fn amount(&self) -> transfer::Len {
168 self.amount
169 }
170
171 pub fn commit(self) {
172 self.progress.remaining = self.progress.remaining.abs_diff(self.amount);
173 }
174}
175
176const _: () = {
177 assert!(mem::size_of::<State>() == 2 * mem::size_of::<u32>());
178 let state = mem::size_of::<&mut State>() + mem::size_of::<u32>();
179 let align = mem::align_of::<Step<'_>>();
180 assert!(mem::size_of::<Step<'_>>() == state.div_ceil(align) * align);
181};