fast image operations
Diffstat (limited to 'src/term/bloc.rs')
-rw-r--r--src/term/bloc.rs76
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) {