use crate::{IndexedColorMap, Palette, PaletteBuf};
use alloc::vec::Vec;
use core::marker::PhantomData;
pub struct PaletteSubstitution<Input, Output, ColorMap> {
input: PhantomData<Input>,
color_map: ColorMap,
palette: PaletteBuf<Output>,
}
impl<Input, Output, ColorMap> PaletteSubstitution<Input, Output, ColorMap>
where
ColorMap: IndexedColorMap<Input>,
{
#[inline]
fn new_unchecked(color_map: ColorMap, palette: PaletteBuf<Output>) -> Self {
debug_assert_eq!(color_map.palette().len(), palette.len());
Self { input: PhantomData, palette, color_map }
}
#[inline]
pub fn new(
color_map: ColorMap,
palette: PaletteBuf<Output>,
) -> Result<Self, (ColorMap, PaletteBuf<Output>)> {
if color_map.palette().len() == palette.len() {
Ok(Self::new_unchecked(color_map, palette))
} else {
Err((color_map, palette))
}
}
#[must_use]
#[inline]
pub fn from_color_mapping(
color_map: ColorMap,
color_mapping: impl FnMut(&ColorMap::Output) -> Output,
) -> Self {
let palette = color_map.palette().map_ref(color_mapping);
Self::new_unchecked(color_map, palette)
}
#[must_use]
#[inline]
pub fn from_slice_mapping(
color_map: ColorMap,
slice_mapping: impl FnOnce(&[ColorMap::Output]) -> Vec<Output>,
) -> Self {
let palette = PaletteBuf::from_mapping(color_map.palette(), slice_mapping);
Self::new_unchecked(color_map, palette)
}
#[must_use]
#[inline]
pub fn into_parts(self) -> (ColorMap, PaletteBuf<Output>) {
let Self { color_map, palette, .. } = self;
(color_map, palette)
}
#[inline]
pub fn palette(&self) -> &Palette<Output> {
&self.palette
}
#[inline]
pub fn palette_mut(&mut self) -> &mut Palette<Output> {
&mut self.palette
}
#[inline]
pub fn color_map(&self) -> &ColorMap {
&self.color_map
}
#[must_use]
#[inline]
pub fn map<NewOutput>(
self,
mapping: impl FnMut(Output) -> NewOutput,
) -> PaletteSubstitution<Input, NewOutput, ColorMap> {
let Self { input, palette, color_map } = self;
let palette = palette.map(mapping);
PaletteSubstitution { input, color_map, palette }
}
#[allow(clippy::type_complexity)]
#[inline]
pub fn replace_palette<NewOutput>(
self,
palette: PaletteBuf<NewOutput>,
) -> Result<
(
PaletteSubstitution<Input, NewOutput, ColorMap>,
PaletteBuf<Output>,
),
(Self, PaletteBuf<NewOutput>),
> {
if self.palette.len() == palette.len() {
let Self { input, palette: old_palette, color_map } = self;
let color_map = PaletteSubstitution { input, color_map, palette };
Ok((color_map, old_palette))
} else {
Err((self, palette))
}
}
}
impl<Input, Output, ColorMap> IndexedColorMap<Input>
for PaletteSubstitution<Input, Output, ColorMap>
where
ColorMap: IndexedColorMap<Input>,
Output: Clone + Send + Sync,
{
type Output = Output;
#[inline]
fn into_palette(self) -> PaletteBuf<Self::Output> {
self.into_parts().1
}
#[inline]
fn palette(&self) -> &Palette<Self::Output> {
self.palette()
}
#[inline]
fn base_palette(&self) -> &Palette<Input> {
self.color_map().base_palette()
}
#[inline]
fn palette_index(&self, color: &Input) -> u8 {
self.color_map().palette_index(color)
}
#[inline]
fn map_to_indices(&self, input: &[Input]) -> Vec<u8> {
self.color_map().map_to_indices(input)
}
#[inline]
fn map_to_colors_of_palette<T: Clone + Send + Sync>(
&self,
palette: &Palette<T>,
input: &[Input],
) -> Vec<T> {
self.color_map().map_to_colors_of_palette(palette, input)
}
}