swap_buffer_queue/write_vectored.rs
1//! [`Buffer`](`crate::buffer::Buffer`) implementations to be used with [`Write::write_vectored`](std::io::Write::write_vectored).
2//!
3//! [`WriteVectoredArrayBuffer`] and [`WriteVectoredVecBuffer`] allows buffering a slice of
4//! [`IoSlice`], saving the cost of dequeuing io-slices one by one to collect them after.
5//! (Internally, two buffers are used: one of the values, and one for the io-slices)
6//!
7//! # Examples
8//! ```rust
9//! # use std::io::{IoSlice, Write};
10//! # use swap_buffer_queue::{Queue, write_vectored::WriteVectoredVecBuffer};
11//! // Creates a WriteVectoredVecBuffer queue
12//! let queue: Queue<WriteVectoredVecBuffer<Vec<u8>>> = Queue::with_capacity(100);
13//! queue.try_enqueue([vec![0; 256]]).unwrap();
14//! queue.try_enqueue([vec![42; 42]]).unwrap();
15//! let mut total_size = 0u16.to_be_bytes();
16//! let mut slice = queue.try_dequeue().unwrap();
17//! // Adds a header with the total size of the slices
18//! total_size.copy_from_slice(&(slice.total_size() as u16).to_be_bytes());
19//! let mut frame = slice.frame(.., Some(&total_size), None);
20//! // Let's pretend we have a writer
21//! let mut writer: Vec<u8> = Default::default();
22//! assert_eq!(writer.write_vectored(&mut frame).unwrap(), 300);
23//! ```
24
25use std::{
26 fmt,
27 io::IoSlice,
28 mem,
29 ops::{Bound, Deref, DerefMut, RangeBounds},
30};
31
32mod array;
33mod vec;
34
35pub use array::WriteVectoredArrayBuffer;
36pub use vec::WriteVectoredVecBuffer;
37
38pub(crate) static EMPTY_SLICE: &[u8] = &[];
39
40/// A *vectored* slice, i.e. a slice of [`IoSlice`].
41///
42/// The total size of all the buffered io-slices can be retrieved with [`total_size`](VectoredSlice::total_size) method.
43/// An header and a trailer can also be added to the slice using [`frame`](VectoredSlice::frame)
44/// method.
45///
46/// # Examples
47///
48/// ```rust
49/// # use std::io::IoSlice;
50/// # use std::ops::Deref;
51/// # use swap_buffer_queue::buffer::BufferSlice;
52/// # use swap_buffer_queue::Queue;
53/// # use swap_buffer_queue::write_vectored::{VectoredSlice, WriteVectoredVecBuffer};
54/// # let queue: Queue<WriteVectoredVecBuffer<_>> = Queue::with_capacity(42);
55/// # queue.try_enqueue([vec![2, 3, 4, 5]]).unwrap();
56/// let header = vec![0, 1];
57/// let trailer = vec![6, 7, 8, 9];
58/// let mut slice: BufferSlice<WriteVectoredVecBuffer<Vec<u8>>, _> /* = ... */;
59/// # slice = queue.try_dequeue().unwrap();
60/// fn to_vec<'a, 'b: 'a>(slices: &'a [IoSlice<'b>]) -> Vec<&'a [u8]> {
61/// slices.iter().map(Deref::deref).collect()
62/// }
63/// assert_eq!(to_vec(slice.deref().deref()), vec![&[2u8, 3, 4, 5]]);
64/// assert_eq!(slice.total_size(), 4);
65/// let frame = slice.frame(.., Some(&header), Some(&trailer));
66/// assert_eq!(
67/// to_vec(frame.deref()),
68/// vec![&[0u8, 1] as &[u8], &[2, 3, 4, 5], &[6, 7, 8, 9]]
69/// );
70/// ```
71pub struct VectoredSlice<'a> {
72 slices: &'a mut [IoSlice<'static>],
73 total_size: usize,
74}
75
76impl<'a> fmt::Debug for VectoredSlice<'a> {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 f.debug_struct("VectoredSlice")
79 .field("slices", &self.deref())
80 .field("total_size", &self.total_size)
81 .finish()
82 }
83}
84
85impl<'a> Deref for VectoredSlice<'a> {
86 type Target = [IoSlice<'a>];
87 fn deref(&self) -> &Self::Target {
88 &self.slices[1..self.slices.len() - 1]
89 }
90}
91
92impl<'a> DerefMut for VectoredSlice<'a> {
93 fn deref_mut(&mut self) -> &mut Self::Target {
94 let slices_len = self.slices.len();
95 // SAFETY: slices in `self.slices[1..self.slices.len() - 1]` are never read
96 // with their static lifetime (see `VectoredSlice::new`), only with `'a`,
97 // so it's fine to mutate them with `'a` lifetime
98 unsafe { mem::transmute(&mut self.slices[1..slices_len - 1]) }
99 }
100}
101
102impl<'a> VectoredSlice<'a> {
103 /// # Safety
104 /// `slices` must not be read by the caller and have a lifetime greater than `'a`
105 pub(crate) unsafe fn new(slices: &'a mut [IoSlice<'static>], total_size: usize) -> Self {
106 Self { slices, total_size }
107 }
108
109 /// Returns the total size of all the buffered io-slices
110 /// (see [examples](VectoredSlice#examples)).
111 pub fn total_size(&self) -> usize {
112 self.total_size
113 }
114
115 /// Returns the *framed* part of the vectored slice within the given range, with an optional
116 /// header io-slice and an optional trailer io-slice
117 /// (see [examples](VectoredSlice#examples)).
118 pub fn frame(
119 &mut self,
120 range: impl RangeBounds<usize>,
121 header: Option<&'a [u8]>,
122 trailer: Option<&'a [u8]>,
123 ) -> VectoredFrame<'a> {
124 let mut start = match range.start_bound() {
125 Bound::Included(&n) => n,
126 Bound::Excluded(&n) => n + 1,
127 Bound::Unbounded => 0,
128 };
129 let mut end = match range.end_bound() {
130 Bound::Included(&n) => n + 2,
131 Bound::Excluded(&n) => n + 1,
132 Bound::Unbounded => self.slices.len(),
133 };
134 let header = if let Some(header) = header {
135 // SAFETY: `self.slices[start..end]` will be transmuted right after to `[IoSlice<'a>]
136 Some(mem::replace(&mut self.slices[start], unsafe {
137 mem::transmute::<IoSlice, IoSlice>(IoSlice::new(header))
138 }))
139 } else {
140 start += 1;
141 None
142 };
143 let trailer = if let Some(trailer) = trailer {
144 // SAFETY: `self.slices[start..end]` will be transmuted right after to `[IoSlice<'a>]
145 Some(mem::replace(&mut self.slices[end - 1], unsafe {
146 mem::transmute::<IoSlice, IoSlice>(IoSlice::new(trailer))
147 }))
148 } else {
149 end -= 1;
150 None
151 };
152 VectoredFrame {
153 // SAFETY: `[self.slices[1..self.slices.len() - 1]` is safe to transmute to
154 // `[IoSlice<'a>]` (see `VectoredSlice::new`), and `start == 0`
155 // (respectively `end == self.slices.len()`) means that `self.slices[start]`
156 // (respectively `self.slices[end]`) has `'a` lifetime because it's set from `header`
157 // (respectively `trailer`) parameter above
158 slices: unsafe {
159 mem::transmute::<&mut [IoSlice], &mut [IoSlice]>(&mut self.slices[start..end])
160 },
161 header,
162 trailer,
163 }
164 }
165}
166
167/// A *framed* part of a [`VectoredSlice`], with an [`IoSlice`] header and an [`IoSlice`] trailer
168/// (see [`VectoredSlice::frame`]).
169pub struct VectoredFrame<'a> {
170 slices: &'a mut [IoSlice<'a>],
171 header: Option<IoSlice<'static>>,
172 trailer: Option<IoSlice<'static>>,
173}
174
175impl fmt::Debug for VectoredFrame<'_> {
176 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177 f.debug_tuple("VectoredFrame").field(&self.slices).finish()
178 }
179}
180
181impl<'a> Deref for VectoredFrame<'a> {
182 type Target = [IoSlice<'a>];
183 fn deref(&self) -> &Self::Target {
184 self.slices
185 }
186}
187
188impl<'a> DerefMut for VectoredFrame<'a> {
189 fn deref_mut(&mut self) -> &mut Self::Target {
190 self.slices
191 }
192}
193
194impl<'a> Drop for VectoredFrame<'a> {
195 fn drop(&mut self) {
196 if let Some(header) = self.header {
197 self.slices[0] = header;
198 }
199 if let Some(trailer) = self.trailer {
200 self.slices[self.slices.len() - 1] = trailer;
201 }
202 }
203}