image_texel/
rec.rs

1// Distributed under The MIT License (MIT)
2//
3// Copyright (c) 2019 The `image-rs` developers
4use core::cmp;
5use core::fmt;
6use core::ops::{Deref, DerefMut};
7
8use crate::buf::{buf, Buffer};
9use crate::{AsTexel, Texel};
10
11/// A reinterpretable vector for an array of texels.
12///
13/// It allows efficient conversion to other texel representations, that is effective
14/// reinterpretation casts.
15pub struct TexelBuffer<P = u8> {
16    inner: Buffer,
17    length: usize,
18    texel: Texel<P>,
19}
20
21/// Error representation for a failed buffer reuse.
22///
23/// Indicates that the capacity of the underlying buffer is not large enough to perform the
24/// operation without a reallocation. This may be either since the allocation is simply not large
25/// enough or due to the requested length not having any representation in memory for the chosen
26/// texel type.
27///
28/// ```
29/// # use image_texel::TexelBuffer;
30/// let mut buffer = TexelBuffer::<u16>::new(16);
31///
32/// let err = match buffer.reuse(buffer.capacity() + 1) {
33///     Ok(_) => unreachable!("Increasing capacity would require reallocation"),
34///     Err(err) => err,
35/// };
36///
37/// let err = match buffer.reuse(usize::max_value()) {
38///     Ok(_) => unreachable!("A slice of u16 can never have usize::MAX elements"),
39///     Err(err) => err,
40/// };
41/// ```
42pub struct BufferReuseError {
43    pub(crate) requested: Option<usize>,
44    pub(crate) capacity: usize,
45}
46
47impl<P> TexelBuffer<P> {
48    /// Allocate a texel buffer by the texel count.
49    ///
50    /// # Panics
51    ///
52    /// This function will panic when the byte-length of the slice with the provided count would
53    /// exceed the possible `usize` values. To avoid this, use `bytes_for_texel` with manual
54    /// calculation of the byte length instead.
55    ///
56    /// This function will also panic if the allocation fails.
57    pub fn new(count: usize) -> Self
58    where
59        P: AsTexel,
60    {
61        Self::new_for_texel(P::texel(), count)
62    }
63
64    /// Allocate a texel buffer by the texel count.
65    ///
66    /// Provides the opportunity to construct the texel argument via other means than the trait,
67    /// for example a dynamically checked expression.
68    ///
69    /// # Panics
70    ///
71    /// This function will panic when the byte-length of the slice with the provided count would
72    /// exceed the possible `usize` values. To avoid this, use `bytes_for_texel` with manual
73    /// calculation of the byte length instead.
74    ///
75    /// This function will also panic if the allocation fails.
76    pub fn new_for_texel(texel: Texel<P>, count: usize) -> Self {
77        Self::bytes_for_texel(texel, mem_size(texel, count))
78    }
79
80    /// Allocate a texel buffer by providing the byte count you wish to allocate.
81    ///
82    /// # Panics
83    ///
84    /// This function will panic if the allocation fails.
85    pub fn bytes_for_texel(texel: Texel<P>, mem_size: usize) -> Self {
86        TexelBuffer {
87            inner: Buffer::new(mem_size),
88            length: mem_size,
89            texel,
90        }
91    }
92
93    /// Allocate a buffer with initial contents.
94    ///
95    /// The `TexelBuffer` will have a byte capacity that holds exactly as many elements as the slice
96    /// contains. Note that the elements are copied bytewise.
97    ///
98    /// # Panics
99    ///
100    /// This function will panic if the allocation fails.
101    pub fn with_elements(elements: &[P]) -> Self
102    where
103        P: AsTexel,
104    {
105        Self::with_elements_for_texel(P::texel(), elements)
106    }
107
108    /// Allocate a buffer with initial contents.
109    ///
110    /// The `TexelBuffer` will have a byte capacity that holds exactly as many elements as the slice
111    /// contains. Note that the elements are copied bytewise.
112    ///
113    /// # Panics
114    ///
115    /// This function will panic if the allocation fails.
116    pub fn with_elements_for_texel(texel: Texel<P>, elements: &[P]) -> Self {
117        let src = texel.to_bytes(elements);
118        let mut buffer = TexelBuffer::from_buffer(Buffer::from(src), texel);
119        // Will be treated as empty, so adjust to be filled up to count.
120        buffer.length = src.len();
121        buffer
122    }
123
124    pub(crate) fn from_buffer(inner: Buffer, texel: Texel<P>) -> Self {
125        TexelBuffer {
126            inner,
127            texel,
128            length: 0,
129        }
130    }
131
132    /// Change the number of texel.
133    ///
134    /// This will always reallocate the buffer if the size exceeds the current capacity.
135    ///
136    /// # Panics
137    ///
138    /// This function will panic when the byte-length of the slice with the provided count would
139    /// exceed the possible `usize` values. To avoid this, use `resize_bytes` with manual
140    /// calculation of the byte length instead.
141    ///
142    /// This function will also panic if an allocation is necessary but fails.
143    pub fn resize(&mut self, count: usize) {
144        self.resize_bytes(mem_size(self.texel, count))
145    }
146
147    /// Change the size in bytes.
148    ///
149    /// The length is afterwards equal to `bytes / mem::size_of::<P>()`, i.e. the quotient rounded
150    /// down.
151    ///
152    /// This will always reallocate the buffer if the size exceeds the current capacity.
153    ///
154    /// # Panics
155    ///
156    /// This function will panic if an allocation is necessary but fails.
157    pub fn resize_bytes(&mut self, bytes: usize) {
158        self.inner.grow_to(bytes);
159        self.length = bytes;
160    }
161
162    /// Change the allocated bytes, interpreted for another texel.
163    ///
164    /// This will always reallocate the buffer if the size exceeds the current capacity.
165    ///
166    /// # Panics
167    ///
168    /// This function will panic when the byte-length of the slice with the provided count would
169    /// exceed the possible `usize` values. To avoid this, use `resize_bytes` with manual
170    /// calculation of the byte length instead.
171    ///
172    /// This function will also panic if an allocation is necessary but fails.
173    pub fn resize_for_texel<O>(&mut self, count: usize, texel: Texel<O>) {
174        self.resize_bytes(mem_size(texel, count))
175    }
176
177    /// Change the number of texel without reallocation.
178    ///
179    /// Returns `Ok` when the resizing was successfully completed to the requested size and returns
180    /// `Err` if this could not have been performed without a reallocation. This function will also
181    /// never deallocate memory.
182    ///
183    /// ```
184    /// # use image_texel::TexelBuffer;
185    /// // Initial allocation may panic due to allocation error for now.
186    /// let mut buffer: TexelBuffer<u16> = TexelBuffer::new(100);
187    /// buffer.reuse(0)
188    ///     .expect("Requested size smaller than allocation");
189    /// buffer.reuse(100)
190    ///     .expect("The buffer didn't shrink from previous reuse");
191    ///
192    /// // Capacity may be larger than requested size at initialization.
193    /// let capacity = buffer.capacity();
194    /// buffer.reuse(capacity)
195    ///     .expect("Set to full underlying allocation size.");
196    /// ```
197    pub fn reuse(&mut self, count: usize) -> Result<(), BufferReuseError> {
198        let bytes = count
199            .checked_mul(self.texel.size())
200            .ok_or_else(|| BufferReuseError {
201                requested: None,
202                capacity: self.byte_capacity(),
203            })?;
204        self.reuse_bytes(bytes)
205    }
206
207    /// Change the number of bytes without reallocation.
208    ///
209    /// Returns `Ok` when the resizing was successfully completed to the requested size and returns
210    /// `Err` with the new byte size otherwise.
211    pub fn reuse_bytes(&mut self, bytes: usize) -> Result<(), BufferReuseError> {
212        if bytes > self.byte_capacity() {
213            return Err(BufferReuseError {
214                requested: Some(bytes),
215                capacity: self.capacity(),
216            });
217        }
218
219        // Resize within capacity will not reallocate, thus not panic.
220        Ok(self.resize_bytes(bytes))
221    }
222
223    /// Reallocate the slice to contain exactly as many bytes as necessary.
224    ///
225    /// The number of contained elements is not changed. However, the number of elements
226    /// interpreted as a different type may change.
227    ///
228    /// ```
229    /// # use image_texel::TexelBuffer;
230    /// let buf_u8 = TexelBuffer::<u8>::new(7);
231    /// assert_eq!(buf_u8.len(), 7);
232    ///
233    /// let mut buf_u32 = buf_u8.reinterpret::<u32>();
234    /// assert_eq!(buf_u32.len(), 1);
235    /// buf_u32.shrink_to_fit();
236    ///
237    /// let buf_u8 = buf_u32.reinterpret::<u8>();
238    /// assert_eq!(buf_u8.len(), 4);
239    /// ```
240    ///
241    /// # Panics
242    ///
243    /// This function will panic if the allocation fails.
244    pub fn shrink_to_fit(&mut self) {
245        let exact_size = mem_size(self.texel, self.len());
246        self.inner.resize_to(exact_size);
247        self.length = exact_size;
248    }
249
250    /// View the valid portion of the buffer as a slice of the texel type.
251    pub fn as_slice(&self) -> &[P] {
252        self.buf().as_texels(self.texel)
253    }
254
255    /// View the valid portion of the buffer as a mutable slice of the texel type.
256    pub fn as_mut_slice(&mut self) -> &mut [P] {
257        let texel = self.texel;
258        self.buf_mut().as_mut_texels(texel)
259    }
260
261    /// The number of accessible elements for the current type.
262    pub fn len(&self) -> usize {
263        self.as_slice().len()
264    }
265
266    /// The number of elements that can fit without reallocation.
267    pub fn capacity(&self) -> usize {
268        self.inner.capacity() / self.texel.size_nz().get()
269    }
270
271    /// View the raw bytes representing the buffer, in the native memory layout.
272    pub fn as_bytes(&self) -> &[u8] {
273        self.buf().as_bytes()
274    }
275
276    /// View the mutable raw bytes representing the buffer, in the native memory layout.
277    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
278        self.buf_mut().as_bytes_mut()
279    }
280
281    /// View the raw bytes wrapped in the aligned buffer type.
282    pub fn as_buf(&self) -> &buf {
283        self.buf()
284    }
285
286    /// View the mutable raw bytes wrapped in the aligned buffer type.
287    pub fn as_buf_mut(&mut self) -> &mut buf {
288        self.buf_mut()
289    }
290
291    /// View the buffer as a different texel type.
292    pub fn as_texels<O>(&self, pixel: Texel<O>) -> &[O] {
293        self.buf().as_texels(pixel)
294    }
295
296    /// Mutate the buffer as a different texel type.
297    pub fn as_mut_texels<O>(&mut self, pixel: Texel<O>) -> &mut [O] {
298        self.buf_mut().as_mut_texels(pixel)
299    }
300
301    /// The total number of managed bytes.
302    ///
303    /// This will not change even through a reinterpretation casts. This corresponds to the
304    /// capacity of the storage.
305    pub fn byte_len(&self) -> usize {
306        self.as_bytes().len()
307    }
308
309    /// The total number of managable bytes.
310    pub fn byte_capacity(&self) -> usize {
311        self.inner.capacity()
312    }
313
314    /// Reinterpret the buffer for a different type of texel.
315    ///
316    /// See `reinterpret_to` for details.
317    pub fn reinterpret<Q>(self) -> TexelBuffer<Q>
318    where
319        Q: AsTexel,
320    {
321        self.reinterpret_to(Q::texel())
322    }
323
324    /// Reinterpret the buffer for a different type of texel.
325    ///
326    /// Note that this may leave some of the underlying texels unaccessible if the new type is
327    /// larger than the old one and the allocation was not a multiple of the new size. Conversely,
328    /// some new bytes may become accessible if the memory length was not a multiple of the
329    /// previous texel type's length.
330    pub fn reinterpret_to<Q>(self, texel: Texel<Q>) -> TexelBuffer<Q> {
331        TexelBuffer {
332            inner: self.inner,
333            length: self.length,
334            texel,
335        }
336    }
337
338    /// Map all elements to another value.
339    ///
340    /// See [`TexelBuffer::map_to`] for details.
341    pub fn map<Q>(self, f: impl Fn(P) -> Q) -> TexelBuffer<Q>
342    where
343        Q: AsTexel,
344    {
345        self.map_to(f, Q::texel())
346    }
347
348    /// Map elements to another value.
349    ///
350    /// This will keep the logical length of the `TexelBuffer` so that the number of texels stays constant.
351    /// If necessary, it will grow the internal buffer to achieve this.
352    ///
353    /// # Panics
354    ///
355    /// This function will panic if the allocation fails or the necessary allocation exceeds the
356    /// value range of `usize`.
357    pub fn map_to<Q>(mut self, f: impl Fn(P) -> Q, texel: Texel<Q>) -> TexelBuffer<Q> {
358        // Ensure we have enough memory for both representations.
359        let length = self.as_slice().len();
360        let new_bytes = mem_size(texel, length);
361        self.inner.grow_to(new_bytes);
362        self.inner.map_within(..length, 0, f, self.texel, texel);
363        TexelBuffer {
364            inner: self.inner,
365            length: new_bytes,
366            texel,
367        }
368    }
369
370    fn buf(&self) -> &buf {
371        &self.inner[..self.length]
372    }
373
374    fn buf_mut(&mut self) -> &mut buf {
375        &mut self.inner[..self.length]
376    }
377
378    pub(crate) fn into_inner(self) -> Buffer {
379        self.inner
380    }
381}
382
383fn mem_size<P>(texel: Texel<P>, count: usize) -> usize {
384    texel
385        .size()
386        .checked_mul(count)
387        .unwrap_or_else(|| panic!("Requested count overflows memory size"))
388}
389
390impl<P> Deref for TexelBuffer<P> {
391    type Target = [P];
392
393    fn deref(&self) -> &[P] {
394        self.as_slice()
395    }
396}
397
398impl<P> DerefMut for TexelBuffer<P> {
399    fn deref_mut(&mut self) -> &mut [P] {
400        self.as_mut_slice()
401    }
402}
403
404impl<P> Clone for TexelBuffer<P> {
405    fn clone(&self) -> Self {
406        TexelBuffer {
407            inner: self.inner.clone(),
408            ..*self
409        }
410    }
411}
412
413impl<P: AsTexel> Default for TexelBuffer<P> {
414    fn default() -> Self {
415        TexelBuffer {
416            inner: Buffer::default(),
417            length: 0,
418            texel: P::texel(),
419        }
420    }
421}
422
423impl<P: AsTexel + Clone> From<&'_ [P]> for TexelBuffer<P> {
424    fn from(elements: &'_ [P]) -> Self {
425        TexelBuffer::with_elements(elements)
426    }
427}
428
429impl<P: cmp::PartialEq> cmp::PartialEq for TexelBuffer<P> {
430    fn eq(&self, other: &Self) -> bool {
431        self.as_slice().eq(other.as_slice())
432    }
433}
434
435impl<P: cmp::Eq> cmp::Eq for TexelBuffer<P> {}
436
437impl<P: cmp::PartialOrd> cmp::PartialOrd for TexelBuffer<P> {
438    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
439        self.as_slice().partial_cmp(other.as_slice())
440    }
441}
442
443impl<P: cmp::Ord> cmp::Ord for TexelBuffer<P> {
444    fn cmp(&self, other: &Self) -> cmp::Ordering {
445        self.as_slice().cmp(other.as_slice())
446    }
447}
448
449impl<P: fmt::Debug> fmt::Debug for TexelBuffer<P> {
450    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
451        f.debug_list().entries(self.as_slice().iter()).finish()
452    }
453}
454
455impl fmt::Debug for BufferReuseError {
456    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
457        match self.requested {
458            None => write!(f, "Buffer reuse failed: Bytes count can not be expressed"),
459            Some(requested) => write!(
460                f,
461                "Buffer reuse failed: {} bytes requested, only {} available",
462                requested, self.capacity
463            ),
464        }
465    }
466}
467
468#[cfg(test)]
469mod tests {
470    use super::*;
471
472    #[test]
473    fn resize() {
474        let mut buffer: TexelBuffer<u8> = TexelBuffer::new(0);
475        assert_eq!(buffer.capacity(), 0);
476        assert_eq!(buffer.len(), 0);
477        buffer.resize(4);
478        assert!(buffer.capacity() >= 4);
479        assert_eq!(buffer.len(), 4);
480        buffer.resize(2);
481        assert!(buffer.capacity() >= 2);
482        assert_eq!(buffer.len(), 2);
483        buffer.resize(0);
484        buffer.shrink_to_fit();
485        assert_eq!(buffer.capacity(), 0);
486        assert_eq!(buffer.len(), 0);
487    }
488
489    #[test]
490    fn map() {
491        let mut buffer: TexelBuffer<u8> = TexelBuffer::new(8);
492        assert_eq!(buffer.len(), 8);
493        buffer.copy_from_slice(&[0, 1, 2, 3, 4, 5, 6, 7]);
494
495        let buffer = buffer.map(u32::from);
496        assert_eq!(buffer.len(), 8);
497        assert_eq!(buffer.as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7]);
498
499        let buffer = buffer.map(|p| p as u8);
500        assert_eq!(buffer.len(), 8);
501        assert_eq!(buffer.as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7]);
502    }
503
504    #[test]
505    fn with_elements() {
506        const HELLO_WORLD: &[u8] = b"Hello, World!";
507        let buffer = TexelBuffer::with_elements(HELLO_WORLD);
508        assert_eq!(buffer.as_slice(), HELLO_WORLD);
509        assert_eq!(buffer.byte_len(), HELLO_WORLD.len());
510
511        let from_buffer = TexelBuffer::from(HELLO_WORLD);
512        assert_eq!(buffer, from_buffer);
513    }
514}