xref: /linux/drivers/gpu/nova-core/sbuffer.rs (revision c17ee635fd3a482b2ad2bf5e269755c2eae5f25e)
1d416035fSJoel Fernandes // SPDX-License-Identifier: GPL-2.0
2d416035fSJoel Fernandes 
3d416035fSJoel Fernandes use core::ops::Deref;
4d416035fSJoel Fernandes 
5*9b89cea1SGary Guo use kernel::prelude::*;
6d416035fSJoel Fernandes 
7d416035fSJoel Fernandes /// A buffer abstraction for discontiguous byte slices.
8d416035fSJoel Fernandes ///
9d416035fSJoel Fernandes /// This allows you to treat multiple non-contiguous `&mut [u8]` slices
10d416035fSJoel Fernandes /// of the same length as a single stream-like read/write buffer.
11d416035fSJoel Fernandes ///
12d416035fSJoel Fernandes /// # Examples
13d416035fSJoel Fernandes ///
14d416035fSJoel Fernandes /// ```
15d416035fSJoel Fernandes // let mut buf1 = [0u8; 5];
16d416035fSJoel Fernandes /// let mut buf2 = [0u8; 5];
17d416035fSJoel Fernandes /// let mut sbuffer = SBufferIter::new_writer([&mut buf1[..], &mut buf2[..]]);
18d416035fSJoel Fernandes ///
19d416035fSJoel Fernandes /// let data = b"hi world!";
20d416035fSJoel Fernandes /// sbuffer.write_all(data)?;
21d416035fSJoel Fernandes /// drop(sbuffer);
22d416035fSJoel Fernandes ///
23d416035fSJoel Fernandes /// assert_eq!(buf1, *b"hi wo");
24d416035fSJoel Fernandes /// assert_eq!(buf2, *b"rld!\0");
25d416035fSJoel Fernandes ///
26d416035fSJoel Fernandes /// # Ok::<(), Error>(())
27d416035fSJoel Fernandes /// ```
28d416035fSJoel Fernandes pub(crate) struct SBufferIter<I: Iterator> {
29d416035fSJoel Fernandes     // [`Some`] if we are not at the end of the data yet.
30d416035fSJoel Fernandes     cur_slice: Option<I::Item>,
31d416035fSJoel Fernandes     // All the slices remaining after `cur_slice`.
32d416035fSJoel Fernandes     slices: I,
33d416035fSJoel Fernandes }
34d416035fSJoel Fernandes 
35d416035fSJoel Fernandes impl<'a, I> SBufferIter<I>
36d416035fSJoel Fernandes where
37d416035fSJoel Fernandes     I: Iterator,
38d416035fSJoel Fernandes {
39d416035fSJoel Fernandes     /// Creates a reader buffer for a discontiguous set of byte slices.
40d416035fSJoel Fernandes     ///
41d416035fSJoel Fernandes     /// # Examples
42d416035fSJoel Fernandes     ///
43d416035fSJoel Fernandes     /// ```
44d416035fSJoel Fernandes     /// let buf1: [u8; 5] = [0, 1, 2, 3, 4];
45d416035fSJoel Fernandes     /// let buf2: [u8; 5] = [5, 6, 7, 8, 9];
46d416035fSJoel Fernandes     /// let sbuffer = SBufferIter::new_reader([&buf1[..], &buf2[..]]);
47d416035fSJoel Fernandes     /// let sum: u8 = sbuffer.sum();
48d416035fSJoel Fernandes     /// assert_eq!(sum, 45);
49d416035fSJoel Fernandes     /// ```
50d416035fSJoel Fernandes     pub(crate) fn new_reader(slices: impl IntoIterator<IntoIter = I>) -> Self
51d416035fSJoel Fernandes     where
52d416035fSJoel Fernandes         I: Iterator<Item = &'a [u8]>,
53d416035fSJoel Fernandes     {
54d416035fSJoel Fernandes         Self::new(slices)
55d416035fSJoel Fernandes     }
56d416035fSJoel Fernandes 
57d416035fSJoel Fernandes     /// Creates a writeable buffer for a discontiguous set of byte slices.
58d416035fSJoel Fernandes     ///
59d416035fSJoel Fernandes     /// # Examples
60d416035fSJoel Fernandes     ///
61d416035fSJoel Fernandes     /// ```
62d416035fSJoel Fernandes     /// let mut buf1 = [0u8; 5];
63d416035fSJoel Fernandes     /// let mut buf2 = [0u8; 5];
64d416035fSJoel Fernandes     /// let mut sbuffer = SBufferIter::new_writer([&mut buf1[..], &mut buf2[..]]);
65d416035fSJoel Fernandes     /// sbuffer.write_all(&[0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9][..])?;
66d416035fSJoel Fernandes     /// drop(sbuffer);
67d416035fSJoel Fernandes     /// assert_eq!(buf1, [0, 1, 2, 3, 4]);
68d416035fSJoel Fernandes     /// assert_eq!(buf2, [5, 6, 7, 8, 9]);
69d416035fSJoel Fernandes     ///
70d416035fSJoel Fernandes     /// ```
71d416035fSJoel Fernandes     pub(crate) fn new_writer(slices: impl IntoIterator<IntoIter = I>) -> Self
72d416035fSJoel Fernandes     where
73d416035fSJoel Fernandes         I: Iterator<Item = &'a mut [u8]>,
74d416035fSJoel Fernandes     {
75d416035fSJoel Fernandes         Self::new(slices)
76d416035fSJoel Fernandes     }
77d416035fSJoel Fernandes 
78d416035fSJoel Fernandes     fn new(slices: impl IntoIterator<IntoIter = I>) -> Self
79d416035fSJoel Fernandes     where
80d416035fSJoel Fernandes         I::Item: Deref<Target = [u8]>,
81d416035fSJoel Fernandes     {
82d416035fSJoel Fernandes         let mut slices = slices.into_iter();
83d416035fSJoel Fernandes 
84d416035fSJoel Fernandes         Self {
85d416035fSJoel Fernandes             // Skip empty slices.
86d416035fSJoel Fernandes             cur_slice: slices.find(|s| !s.deref().is_empty()),
87d416035fSJoel Fernandes             slices,
88d416035fSJoel Fernandes         }
89d416035fSJoel Fernandes     }
90d416035fSJoel Fernandes 
91d416035fSJoel Fernandes     /// Returns a slice of at most `len` bytes, or [`None`] if we are at the end of the data.
92d416035fSJoel Fernandes     ///
93d416035fSJoel Fernandes     /// If a slice shorter than `len` bytes has been returned, the caller can call this method
94d416035fSJoel Fernandes     /// again until it returns [`None`] to try and obtain the remainder of the data.
95d416035fSJoel Fernandes     ///
96d416035fSJoel Fernandes     /// The closure `f` should split the slice received in it's first parameter
97d416035fSJoel Fernandes     /// at the position given in the second parameter.
98d416035fSJoel Fernandes     fn get_slice_internal(
99d416035fSJoel Fernandes         &mut self,
100d416035fSJoel Fernandes         len: usize,
101d416035fSJoel Fernandes         mut f: impl FnMut(I::Item, usize) -> (I::Item, I::Item),
102d416035fSJoel Fernandes     ) -> Option<I::Item>
103d416035fSJoel Fernandes     where
104d416035fSJoel Fernandes         I::Item: Deref<Target = [u8]>,
105d416035fSJoel Fernandes     {
106d416035fSJoel Fernandes         match self.cur_slice.take() {
107d416035fSJoel Fernandes             None => None,
108d416035fSJoel Fernandes             Some(cur_slice) => {
109d416035fSJoel Fernandes                 if len >= cur_slice.len() {
110d416035fSJoel Fernandes                     // Caller requested more data than is in the current slice, return it entirely
111d416035fSJoel Fernandes                     // and prepare the following slice for being used. Skip empty slices to avoid
112d416035fSJoel Fernandes                     // trouble.
113d416035fSJoel Fernandes                     self.cur_slice = self.slices.find(|s| !s.is_empty());
114d416035fSJoel Fernandes 
115d416035fSJoel Fernandes                     Some(cur_slice)
116d416035fSJoel Fernandes                 } else {
117d416035fSJoel Fernandes                     // The current slice can satisfy the request, split it and return a slice of
118d416035fSJoel Fernandes                     // the requested size.
119d416035fSJoel Fernandes                     let (ret, next) = f(cur_slice, len);
120d416035fSJoel Fernandes                     self.cur_slice = Some(next);
121d416035fSJoel Fernandes 
122d416035fSJoel Fernandes                     Some(ret)
123d416035fSJoel Fernandes                 }
124d416035fSJoel Fernandes             }
125d416035fSJoel Fernandes         }
126d416035fSJoel Fernandes     }
127d416035fSJoel Fernandes 
128d416035fSJoel Fernandes     /// Returns whether this buffer still has data available.
129d416035fSJoel Fernandes     pub(crate) fn is_empty(&self) -> bool {
130d416035fSJoel Fernandes         self.cur_slice.is_none()
131d416035fSJoel Fernandes     }
132d416035fSJoel Fernandes }
133d416035fSJoel Fernandes 
134d416035fSJoel Fernandes /// Provides a way to get non-mutable slices of data to read from.
135d416035fSJoel Fernandes impl<'a, I> SBufferIter<I>
136d416035fSJoel Fernandes where
137d416035fSJoel Fernandes     I: Iterator<Item = &'a [u8]>,
138d416035fSJoel Fernandes {
139d416035fSJoel Fernandes     /// Returns a slice of at most `len` bytes, or [`None`] if we are at the end of the data.
140d416035fSJoel Fernandes     ///
141d416035fSJoel Fernandes     /// If a slice shorter than `len` bytes has been returned, the caller can call this method
142d416035fSJoel Fernandes     /// again until it returns [`None`] to try and obtain the remainder of the data.
143d416035fSJoel Fernandes     fn get_slice(&mut self, len: usize) -> Option<&'a [u8]> {
144d416035fSJoel Fernandes         self.get_slice_internal(len, |s, pos| s.split_at(pos))
145d416035fSJoel Fernandes     }
146d416035fSJoel Fernandes 
147d416035fSJoel Fernandes     /// Ideally we would implement `Read`, but it is not available in `core`.
148d416035fSJoel Fernandes     /// So mimic `std::io::Read::read_exact`.
149d416035fSJoel Fernandes     #[expect(unused)]
150d416035fSJoel Fernandes     pub(crate) fn read_exact(&mut self, mut dst: &mut [u8]) -> Result {
151d416035fSJoel Fernandes         while !dst.is_empty() {
152d416035fSJoel Fernandes             match self.get_slice(dst.len()) {
153d416035fSJoel Fernandes                 None => return Err(EINVAL),
154d416035fSJoel Fernandes                 Some(src) => {
155d416035fSJoel Fernandes                     let dst_slice;
156d416035fSJoel Fernandes                     (dst_slice, dst) = dst.split_at_mut(src.len());
157d416035fSJoel Fernandes                     dst_slice.copy_from_slice(src);
158d416035fSJoel Fernandes                 }
159d416035fSJoel Fernandes             }
160d416035fSJoel Fernandes         }
161d416035fSJoel Fernandes 
162d416035fSJoel Fernandes         Ok(())
163d416035fSJoel Fernandes     }
164d416035fSJoel Fernandes 
165d416035fSJoel Fernandes     /// Read all the remaining data into a [`KVec`].
166d416035fSJoel Fernandes     ///
167d416035fSJoel Fernandes     /// `self` will be empty after this operation.
168d416035fSJoel Fernandes     pub(crate) fn flush_into_kvec(&mut self, flags: kernel::alloc::Flags) -> Result<KVec<u8>> {
169d416035fSJoel Fernandes         let mut buf = KVec::<u8>::new();
170d416035fSJoel Fernandes 
171d416035fSJoel Fernandes         if let Some(slice) = core::mem::take(&mut self.cur_slice) {
172d416035fSJoel Fernandes             buf.extend_from_slice(slice, flags)?;
173d416035fSJoel Fernandes         }
174d416035fSJoel Fernandes         for slice in &mut self.slices {
175d416035fSJoel Fernandes             buf.extend_from_slice(slice, flags)?;
176d416035fSJoel Fernandes         }
177d416035fSJoel Fernandes 
178d416035fSJoel Fernandes         Ok(buf)
179d416035fSJoel Fernandes     }
180d416035fSJoel Fernandes }
181d416035fSJoel Fernandes 
182d416035fSJoel Fernandes /// Provides a way to get mutable slices of data to write into.
183d416035fSJoel Fernandes impl<'a, I> SBufferIter<I>
184d416035fSJoel Fernandes where
185d416035fSJoel Fernandes     I: Iterator<Item = &'a mut [u8]>,
186d416035fSJoel Fernandes {
187d416035fSJoel Fernandes     /// Returns a mutable slice of at most `len` bytes, or [`None`] if we are at the end of the
188d416035fSJoel Fernandes     /// data.
189d416035fSJoel Fernandes     ///
190d416035fSJoel Fernandes     /// If a slice shorter than `len` bytes has been returned, the caller can call this method
191d416035fSJoel Fernandes     /// again until it returns `None` to try and obtain the remainder of the data.
192d416035fSJoel Fernandes     fn get_slice_mut(&mut self, len: usize) -> Option<&'a mut [u8]> {
193d416035fSJoel Fernandes         self.get_slice_internal(len, |s, pos| s.split_at_mut(pos))
194d416035fSJoel Fernandes     }
195d416035fSJoel Fernandes 
196d416035fSJoel Fernandes     /// Ideally we would implement [`Write`], but it is not available in `core`.
197d416035fSJoel Fernandes     /// So mimic `std::io::Write::write_all`.
198d416035fSJoel Fernandes     pub(crate) fn write_all(&mut self, mut src: &[u8]) -> Result {
199d416035fSJoel Fernandes         while !src.is_empty() {
200d416035fSJoel Fernandes             match self.get_slice_mut(src.len()) {
201d416035fSJoel Fernandes                 None => return Err(ETOOSMALL),
202d416035fSJoel Fernandes                 Some(dst) => {
203d416035fSJoel Fernandes                     let src_slice;
204d416035fSJoel Fernandes                     (src_slice, src) = src.split_at(dst.len());
205d416035fSJoel Fernandes                     dst.copy_from_slice(src_slice);
206d416035fSJoel Fernandes                 }
207d416035fSJoel Fernandes             }
208d416035fSJoel Fernandes         }
209d416035fSJoel Fernandes 
210d416035fSJoel Fernandes         Ok(())
211d416035fSJoel Fernandes     }
212d416035fSJoel Fernandes }
213d416035fSJoel Fernandes 
214d416035fSJoel Fernandes impl<'a, I> Iterator for SBufferIter<I>
215d416035fSJoel Fernandes where
216d416035fSJoel Fernandes     I: Iterator<Item = &'a [u8]>,
217d416035fSJoel Fernandes {
218d416035fSJoel Fernandes     type Item = u8;
219d416035fSJoel Fernandes 
220d416035fSJoel Fernandes     fn next(&mut self) -> Option<Self::Item> {
221d416035fSJoel Fernandes         // Returned slices are guaranteed to not be empty so we can safely index the first entry.
222d416035fSJoel Fernandes         self.get_slice(1).map(|s| s[0])
223d416035fSJoel Fernandes     }
224d416035fSJoel Fernandes }
225