use arrayvec::ArrayVec;
use num_traits::cast::AsPrimitive;
use palette::rgb::Srgb;
use palette::{lab::Lab, IntoColor};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct BaseColor {
pub name: String,
pub lab: Lab,
}
impl BaseColor {
#[inline]
pub fn new<S, F>(name: S, l: F, a: F, b: F) -> BaseColor
where
S: Into<String>,
F: AsPrimitive<f32>,
{
BaseColor {
name: name.into(),
lab: Lab::new(l.as_(), a.as_(), b.as_()),
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct Palette<const N: usize> {
pub name: String,
#[serde(with = "serde_arrays")]
pub colors: [BaseColor; N],
}
pub type Base16Palette = Palette<16>;
pub type Base16Colors = [BaseColor; 16];
impl<const N: usize> Palette<N> {
#[inline]
pub fn new<S>(name: S, colors: [BaseColor; N]) -> Palette<N>
where
S: Into<String>,
{
Palette {
name: name.into(),
colors,
}
}
}
#[derive(Serialize, Debug)]
pub struct DerivedColor<'a> {
pub base: &'a BaseColor,
pub srgb: Srgb<u8>,
pub srgb_hex: String,
}
impl<'a> From<&'a BaseColor> for DerivedColor<'a> {
fn from(base: &'a BaseColor) -> Self {
let srgb: Srgb = base.lab.into_color();
let srgb_u8: Srgb<u8> = srgb.into_format();
let srgb_hex = format!("{:x}", srgb_u8);
Self {
base,
srgb: srgb_u8,
srgb_hex,
}
}
}
#[derive(Serialize, Debug)]
pub struct DerivedPalette<'a, const N: usize> {
pub name: &'a str,
#[serde(with = "serde_arrays")]
pub colors: [DerivedColor<'a>; N],
}
pub type Base16DerivedPalette<'a> = DerivedPalette<'a, 16>;
pub type Base16DerivedColors<'a> = [DerivedColor<'a>; 16];
impl<'a, const N: usize> From<&'a Palette<N>> for DerivedPalette<'a, N> {
fn from(base_palette: &'a Palette<N>) -> Self {
let colors: [DerivedColor<'a>; N] = base_palette
.colors
.iter()
.map(DerivedColor::from)
.collect::<ArrayVec<_, N>>()
.into_inner()
.unwrap();
Self {
name: &base_palette.name,
colors,
}
}
}