use core::cmp;
use core::fmt;
use core::ops::{Deref, DerefMut};
use crate::buf::{buf, Buffer};
use crate::{AsTexel, Texel};
pub struct TexelBuffer<P = u8> {
inner: Buffer,
length: usize,
texel: Texel<P>,
}
pub struct BufferReuseError {
pub(crate) requested: Option<usize>,
pub(crate) capacity: usize,
}
impl<P> TexelBuffer<P> {
pub fn new(count: usize) -> Self
where
P: AsTexel,
{
Self::new_for_texel(P::texel(), count)
}
pub fn new_for_texel(texel: Texel<P>, count: usize) -> Self {
Self::bytes_for_texel(texel, mem_size(texel, count))
}
pub fn bytes_for_texel(texel: Texel<P>, mem_size: usize) -> Self {
TexelBuffer {
inner: Buffer::new(mem_size),
length: mem_size,
texel,
}
}
pub fn with_elements(elements: &[P]) -> Self
where
P: AsTexel,
{
Self::with_elements_for_texel(P::texel(), elements)
}
pub fn with_elements_for_texel(texel: Texel<P>, elements: &[P]) -> Self {
let src = texel.cast_bytes(elements);
let mut buffer = TexelBuffer::from_buffer(Buffer::from(src), texel);
buffer.length = src.len();
buffer
}
pub(crate) fn from_buffer(inner: Buffer, texel: Texel<P>) -> Self {
TexelBuffer {
inner,
texel,
length: 0,
}
}
pub fn resize(&mut self, count: usize) {
self.resize_bytes(mem_size(self.texel, count))
}
pub fn resize_bytes(&mut self, bytes: usize) {
self.inner.grow_to(bytes);
self.length = bytes;
}
pub fn resize_for_texel<O>(&mut self, count: usize, texel: Texel<O>) {
self.resize_bytes(mem_size(texel, count))
}
pub fn reuse(&mut self, count: usize) -> Result<(), BufferReuseError> {
let bytes = count
.checked_mul(self.texel.size())
.ok_or_else(|| BufferReuseError {
requested: None,
capacity: self.byte_capacity(),
})?;
self.reuse_bytes(bytes)
}
pub fn reuse_bytes(&mut self, bytes: usize) -> Result<(), BufferReuseError> {
if bytes > self.byte_capacity() {
return Err(BufferReuseError {
requested: Some(bytes),
capacity: self.capacity(),
});
}
Ok(self.resize_bytes(bytes))
}
pub fn shrink_to_fit(&mut self) {
let exact_size = mem_size(self.texel, self.len());
self.inner.resize_to(exact_size);
self.length = exact_size;
}
pub fn as_slice(&self) -> &[P] {
self.buf().as_texels(self.texel)
}
pub fn as_mut_slice(&mut self) -> &mut [P] {
let texel = self.texel;
self.buf_mut().as_mut_texels(texel)
}
pub fn len(&self) -> usize {
self.as_slice().len()
}
pub fn capacity(&self) -> usize {
self.inner.capacity() / self.texel.size_nz().get()
}
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()
}
pub fn as_texels<O>(&self, pixel: Texel<O>) -> &[O] {
self.inner.as_texels(pixel)
}
pub fn as_mut_texels<O>(&mut self, pixel: Texel<O>) -> &mut [O] {
self.inner.as_mut_texels(pixel)
}
pub fn byte_len(&self) -> usize {
self.as_bytes().len()
}
pub fn byte_capacity(&self) -> usize {
self.inner.capacity()
}
pub fn reinterpret<Q>(self) -> TexelBuffer<Q>
where
Q: AsTexel,
{
self.reinterpret_to(Q::texel())
}
pub fn reinterpret_to<Q>(self, texel: Texel<Q>) -> TexelBuffer<Q> {
TexelBuffer {
inner: self.inner,
length: self.length,
texel,
}
}
pub fn map<Q>(self, f: impl Fn(P) -> Q) -> TexelBuffer<Q>
where
Q: AsTexel,
{
self.map_to(f, Q::texel())
}
pub fn map_to<Q>(mut self, f: impl Fn(P) -> Q, texel: Texel<Q>) -> TexelBuffer<Q> {
let length = self.as_slice().len();
let new_bytes = mem_size(texel, length);
self.inner.grow_to(new_bytes);
self.inner.map_within(..length, 0, f, self.texel, texel);
TexelBuffer {
inner: self.inner,
length: new_bytes,
texel,
}
}
fn buf(&self) -> &buf {
&self.inner[..self.length]
}
fn buf_mut(&mut self) -> &mut buf {
&mut self.inner[..self.length]
}
pub(crate) fn into_inner(self) -> Buffer {
self.inner
}
}
fn mem_size<P>(texel: Texel<P>, count: usize) -> usize {
texel
.size()
.checked_mul(count)
.unwrap_or_else(|| panic!("Requested count overflows memory size"))
}
impl<P> Deref for TexelBuffer<P> {
type Target = [P];
fn deref(&self) -> &[P] {
self.as_slice()
}
}
impl<P> DerefMut for TexelBuffer<P> {
fn deref_mut(&mut self) -> &mut [P] {
self.as_mut_slice()
}
}
impl<P> Clone for TexelBuffer<P> {
fn clone(&self) -> Self {
TexelBuffer {
inner: self.inner.clone(),
..*self
}
}
}
impl<P: AsTexel> Default for TexelBuffer<P> {
fn default() -> Self {
TexelBuffer {
inner: Buffer::default(),
length: 0,
texel: P::texel(),
}
}
}
impl<P: AsTexel + Clone> From<&'_ [P]> for TexelBuffer<P> {
fn from(elements: &'_ [P]) -> Self {
TexelBuffer::with_elements(elements)
}
}
impl<P: cmp::PartialEq> cmp::PartialEq for TexelBuffer<P> {
fn eq(&self, other: &Self) -> bool {
self.as_slice().eq(other.as_slice())
}
}
impl<P: cmp::Eq> cmp::Eq for TexelBuffer<P> {}
impl<P: cmp::PartialOrd> cmp::PartialOrd for TexelBuffer<P> {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.as_slice().partial_cmp(other.as_slice())
}
}
impl<P: cmp::Ord> cmp::Ord for TexelBuffer<P> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.as_slice().cmp(other.as_slice())
}
}
impl<P: fmt::Debug> fmt::Debug for TexelBuffer<P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list().entries(self.as_slice().iter()).finish()
}
}
impl fmt::Debug for BufferReuseError {
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: TexelBuffer<u8> = TexelBuffer::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);
}
#[test]
fn map() {
let mut buffer: TexelBuffer<u8> = TexelBuffer::new(8);
assert_eq!(buffer.len(), 8);
buffer.copy_from_slice(&[0, 1, 2, 3, 4, 5, 6, 7]);
let buffer = buffer.map(u32::from);
assert_eq!(buffer.len(), 8);
assert_eq!(buffer.as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7]);
let buffer = buffer.map(|p| p as u8);
assert_eq!(buffer.len(), 8);
assert_eq!(buffer.as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7]);
}
#[test]
fn with_elements() {
const HELLO_WORLD: &[u8] = b"Hello, World!";
let buffer = TexelBuffer::with_elements(HELLO_WORLD);
assert_eq!(buffer.as_slice(), HELLO_WORLD);
assert_eq!(buffer.byte_len(), HELLO_WORLD.len());
let from_buffer = TexelBuffer::from(HELLO_WORLD);
assert_eq!(buffer, from_buffer);
}
}