fast image operations
Diffstat (limited to 'src/term/bloc.rs')
| -rw-r--r-- | src/term/bloc.rs | 76 |
1 files changed, 42 insertions, 34 deletions
diff --git a/src/term/bloc.rs b/src/term/bloc.rs index 8601388..5f6347b 100644 --- a/src/term/bloc.rs +++ b/src/term/bloc.rs @@ -1,4 +1,6 @@ +use super::Basic; use crate::{pixels::convert::PFrom, scale, term::size::fit, Image}; +use core::intrinsics::transmute_unchecked as transmute; use std::fmt::{Debug, Display, Formatter, Result, Write}; /// Colored `▀`s. The simple, stupid solution. @@ -14,8 +16,7 @@ impl<T: AsRef<[u8]>, const N: usize> std::ops::Deref for Bloc<T, N> { impl<T: AsRef<[u8]>, const N: usize> Display for Bloc<T, N> where - Image<T, N>: Scaled<N>, - [u8; 3]: PFrom<N>, + [(); N]: Basic, { fn fmt(&self, f: &mut Formatter<'_>) -> Result { self.write(f) @@ -24,44 +25,16 @@ where impl<T: AsRef<[u8]>, const N: usize> Debug for Bloc<T, N> where - Image<T, N>: Scaled<N>, - [u8; 3]: PFrom<N>, + [(); N]: Basic, { fn fmt(&self, f: &mut Formatter<'_>) -> Result { self.write(f) } } -#[doc(hidden)] -pub trait Scaled<const N: usize> { - fn scaled(&self, to: (u32, u32)) -> Image<Box<[u8]>, N>; -} - -macro_rules! n { - ($n:literal) => { - impl<T: AsRef<[u8]>> Scaled<$n> for Image<T, $n> { - fn scaled(&self, (w, h): (u32, u32)) -> Image<Box<[u8]>, $n> { - self.scale::<scale::Nearest>(w, h) - } - } - }; - (o $n:literal) => { - impl<T: AsRef<[u8]>> Scaled<$n> for Image<T, $n> { - fn scaled(&self, (w, h): (u32, u32)) -> Image<Box<[u8]>, $n> { - self.as_ref().to_owned().scale::<scale::Nearest>(w, h) - } - } - }; -} -n!(1); -n!(o 2); -n!(3); -n!(o 4); - impl<T: AsRef<[u8]>, const N: usize> Bloc<T, N> where - [u8; 3]: PFrom<N>, - Image<T, N>: Scaled<N>, + [(); N]: Basic, { /// Write out halfblocks. pub fn write(&self, to: &mut impl Write) -> Result { @@ -74,7 +47,31 @@ where } let buf; let i = if !cfg!(test) { - buf = self.scaled(fit((self.width(), self.height()))); + let (w, h) = fit((self.width(), self.height())); + macro_rules! n { + ($n:literal) => { + transmute::<Image<Box<[u8]>, $n>, Image<Box<[u8]>, N>>( + transmute::<Image<&[u8], N>, Image<&[u8], $n>>(self.as_ref()) + .scale::<scale::Nearest>(w, h), + ) + }; + (o $n:literal) => { + transmute::<Image<Box<[u8]>, 1>, Image<Box<[u8]>, N>>( + transmute::<Image<Vec<u8>, N>, Image<&[u8], 1>>(self.as_ref().to_owned()) + .scale::<scale::Nearest>(w, h), + ) + }; + } + // SAFETY: #[allow(clippy::undocumented_unsafe_blocks)] + buf = unsafe { + match N { + 1 => n![1], + 2 => n![o 2], + 3 => n![3], + 4 => n![o 4], + _ => unreachable!(), + } + }; buf.as_ref() } else { self.as_ref() @@ -83,7 +80,18 @@ where for [a, b] in i .flatten() .chunks_exact(i.width() as _) - .map(|x| x.iter().copied().map(<[u8; 3] as PFrom<N>>::pfrom)) + .map(|x| { + #[allow(clippy::undocumented_unsafe_blocks)] + x.iter().copied().map(|x| unsafe { + match N { + 1 => <[u8; 3] as PFrom<1>>::pfrom(transmute(x)), + 2 => <[u8; 3] as PFrom<2>>::pfrom(transmute(x)), + 3 => <[u8; 3] as PFrom<3>>::pfrom(transmute(x)), + 4 => <[u8; 3] as PFrom<4>>::pfrom(transmute(x)), + _ => unreachable!(), + } + }) + }) .array_chunks::<2>() { for (a, b) in a.zip(b) { |