// Distributed under The MIT License (MIT)
//
// Copyright (c) 2019 The `image-rs` developers
use core::fmt;
use core::ops::{Deref, DerefMut};
use crate::{AsPixel, Pixel};
use crate::buf::{Buffer, buf};
use zerocopy::{AsBytes, FromBytes};
/// A **r**einterpretable v**ec**tor for an array of pixels.
///
/// It allows efficient conversion to other pixel representations, that is effective
/// reinterpretation casts.
pub struct Rec<P: AsBytes + FromBytes> {
inner: Buffer,
length: usize,
pixel: Pixel<P>,
}
/// Error representation for a failed buffer reuse.
///
/// Indicates that the capacity of the underlying buffer is not large enough to perform the
/// operation without a reallocation. This may be either since the allocation is simply not large
/// enough or due to the requested length not having any representation in memory for the chosen
/// pixel type.
///
/// ```
/// # use canvas::Rec;
/// let mut rec = Rec::<u16>::new(16);
///
/// let err = match rec.reuse(rec.capacity() + 1) {
/// Ok(_) => unreachable!("Increasing capacity would require reallocation"),
/// Err(err) => err,
/// };
///
/// let err = match rec.reuse(usize::max_value()) {
/// Ok(_) => unreachable!("A slice of u16 can never have usize::MAX elements"),
/// Err(err) => err,
/// };
/// ```
pub struct ReuseError {
requested: Option<usize>,
capacity: usize,
}
impl<P: AsBytes + FromBytes> Rec<P> {
/// Allocate a pixel buffer by the pixel count.
///
/// # Panics
///
/// This function will panic when the byte-length of the slice with the provided count would
/// exceed the possible `usize` values. To avoid this, use `bytes_for_pixel` with manual
/// calculation of the byte length instead.
///
/// This function will also panic if the allocation fails.
pub fn new(count: usize) -> Self where P: AsPixel {
Self::new_for_pixel(P::pixel(), count)
}
/// Allocate a pixel buffer by the pixel count.
///
/// Provides the opportunity to construct the pixel argument via other means than the trait,
/// for example a dynamically checked expression.
///
/// # Panics
///
/// This function will panic when the byte-length of the slice with the provided count would
/// exceed the possible `usize` values. To avoid this, use `bytes_for_pixel` with manual
/// calculation of the byte length instead.
///
/// This function will also panic if the allocation fails.
pub fn new_for_pixel(pixel: Pixel<P>, count: usize) -> Self {
Self::bytes_for_pixel(pixel, mem_size(pixel, count))
}
/// Allocate a pixel buffer by providing the byte count you wish to allocate.
///
/// # Panics
///
/// This function will panic if the allocation fails.
pub fn bytes_for_pixel(pixel: Pixel<P>, mem_size: usize) -> Self {
Rec {
inner: Buffer::new(mem_size),
length: mem_size,
pixel,
}
}
/// Change the number of pixels.
///
/// This will always reallocate the buffer if the size exceeds the current capacity.
///
/// # Panics
///
/// This function will panic when the byte-length of the slice with the provided count would
/// exceed the possible `usize` values. To avoid this, use `resize_bytes` with manual
/// calculation of the byte length instead.
///
/// This function will also panic if an allocation is necessary but fails.
pub fn resize(&mut self, count: usize) {
self.resize_bytes(mem_size(self.pixel, count))
}
/// Change the size in bytes.
///
/// The length is afterwards equal to `bytes / mem::size_of::<P>()`, i.e. the quotient rounded
/// down.
///
/// This will always reallocate the buffer if the size exceeds the current capacity.
///
/// # Panics
///
/// This function will panic if an allocation is necessary but fails.
pub fn resize_bytes(&mut self, bytes: usize) {
self.inner.grow_to(bytes);
self.length = bytes;
}
/// Change the number of pixels without reallocation.
///
/// Returns `Ok` when the resizing was successfully completed to the requested size and returns
/// `Err` if this could not have been performed without a reallocation. This function will also
/// never deallocate memory.
///
/// ```
/// # use canvas::Rec;
/// // Initial allocation may panic due to allocation error for now.
/// let mut buffer: Rec<u16> = Rec::new(100);
/// buffer.reuse(0)
/// .expect("Requested size smaller than allocation");
/// buffer.reuse(100)
/// .expect("The buffer didn't shrink from previous reuse");
///
/// // Capacity may be larger than requested size at initialization.
/// let capacity = buffer.capacity();
/// buffer.reuse(capacity)
/// .expect("Set to full underlying allocation size.");
/// ```
pub fn reuse(&mut self, count: usize) -> Result<(), ReuseError> {
let bytes = count
.checked_mul(self.pixel.size())
.ok_or_else(|| ReuseError {
requested: None,
capacity: self.byte_capacity(),
})?;
self.reuse_bytes(bytes)
}
/// Change the number of bytes without reallocation.
///
/// Returns `Ok` when the resizing was successfully completed to the requested size and returns
/// `Err` with the new byte size otherwise.
pub fn reuse_bytes(&mut self, bytes: usize) -> Result<(), ReuseError> {
if bytes > self.byte_capacity() {
return Err(ReuseError {
requested: Some(bytes),
capacity: self.capacity(),
})
}
// Resize within capacity will not reallocate, thus not panic.
Ok(self.resize_bytes(bytes))
}
/// Reallocate the slice to contain exactly as many bytes as necessary.
///
/// The number of contained elements is not changed. However, the number of elements
/// interpreted as a different type may change.
///
/// ```
/// # use canvas::Rec;
/// let rec_u8 = Rec::<u8>::new(7);
/// assert_eq!(rec_u8.len(), 7);
///
/// let mut rec_u32 = rec_u8.reinterpret::<u32>();
/// assert_eq!(rec_u32.len(), 1);
/// rec_u32.shrink_to_fit();
///
/// let rec_u8 = rec_u32.reinterpret::<u8>();
/// assert_eq!(rec_u8.len(), 4);
/// ```
///
/// # Panics
///
/// This function will panic if the allocation fails.
pub fn shrink_to_fit(&mut self) {
let exact_size = mem_size(self.pixel, self.len());
self.inner.resize_to(exact_size);
self.length = exact_size;
}
pub fn as_slice(&self) -> &[P] {
self.buf().as_pixels(self.pixel)
}
pub fn as_mut_slice(&mut self) -> &mut [P] {
let pixel = self.pixel;
self.buf_mut().as_mut_pixels(pixel)
}
/// The number of accessible elements for the current type.
pub fn len(&self) -> usize {
self.as_slice().len()
}
/// The number of elements that can fit without reallocation.
pub fn capacity(&self) -> usize {
self.inner.capacity() / self.pixel.size()
}
pub fn as_bytes(&self) -> &[u8] {
self.buf().as_bytes()
}
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
self.buf_mut().as_bytes_mut()
}
/// The total number of managed bytes.
///
/// This will not change even through a reinterpretation casts. This corresponds to the
/// capacity of the storage.
pub fn byte_len(&self) -> usize {
self.as_bytes().len()
}
/// The total number of managable bytes.
pub fn byte_capacity(&self) -> usize {
self.inner.capacity()
}
/// Reinterpret the buffer for a different type of pixel.
///
/// See `reinterpret_to` for details.
pub fn reinterpret<Q>(self) -> Rec<Q>
where Q: AsPixel + AsBytes + FromBytes
{
self.reinterpret_to(Q::pixel())
}
/// Reinterpret the buffer for a different type of pixel.
///
/// Note that this may leave some of the underlying pixels unaccessible if the new type is
/// larger than the old one and the allocation was not a multiple of the new size. Conversely,
/// some new bytes may become accessible if the memory length was not a multiple of the
/// previous pixel type's length.
pub fn reinterpret_to<Q>(self, pixel: Pixel<Q>) -> Rec<Q>
where Q: AsBytes + FromBytes
{
Rec {
inner: self.inner,
length: self.length,
pixel,
}
}
fn buf(&self) -> &buf {
&self.inner[..self.length]
}
fn buf_mut(&mut self) -> &mut buf {
&mut self.inner[..self.length]
}
}
fn mem_size<P>(pixel: Pixel<P>, count: usize) -> usize {
pixel.size().checked_mul(count).unwrap_or_else(
|| panic!("Requested count overflows memory size"))
}
impl<P: AsBytes + FromBytes> Deref for Rec<P> {
type Target = [P];
fn deref(&self) -> &[P] {
self.as_slice()
}
}
impl<P: AsBytes + FromBytes> DerefMut for Rec<P> {
fn deref_mut(&mut self) -> &mut [P] {
self.as_mut_slice()
}
}
impl fmt::Debug for ReuseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.requested {
None => {
write!(f, "Buffer reuse failed: Bytes count can not be expressed")
},
Some(requested) => {
write!(f, "Buffer reuse failed: {} bytes requested, only {} available",
requested, self.capacity)
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn resize() {
let mut buffer: Rec<u8> = Rec::new(0);
assert_eq!(buffer.capacity(), 0);
assert_eq!(buffer.len(), 0);
buffer.resize(4);
assert!(buffer.capacity() >= 4);
assert_eq!(buffer.len(), 4);
buffer.resize(2);
assert!(buffer.capacity() >= 2);
assert_eq!(buffer.len(), 2);
buffer.resize(0);
buffer.shrink_to_fit();
assert_eq!(buffer.capacity(), 0);
assert_eq!(buffer.len(), 0);
}
}