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}