pub mod base16;
pub mod base24;
mod color;
pub mod tinted8;
use serde::{Deserialize, Serialize};
use std::{fmt, str::FromStr};
pub use crate::scheme::color::Color;
pub use crate::scheme::color::{ColorName, ColorType, ColorVariant};
use crate::TintedBuilderError;
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum Scheme {
Base16(base16::Scheme),
Base24(base24::Scheme),
Tinted8(Box<tinted8::Scheme>),
}
impl Scheme {
pub fn from_yaml(yaml: &str) -> Result<Self, TintedBuilderError> {
let raw: serde_yaml::Value =
serde_yaml::from_str(yaml).map_err(TintedBuilderError::YamlDeserialize)?;
let system = raw
.get("system")
.or_else(|| raw.get("scheme").and_then(|s| s.get("system")))
.and_then(serde_yaml::Value::as_str)
.ok_or_else(|| TintedBuilderError::SchemeMissingProperty("system".to_string()))?
.parse::<SchemeSystem>()?;
match system {
SchemeSystem::Base16 => {
let scheme: base16::Scheme =
serde_yaml::from_str(yaml).map_err(TintedBuilderError::YamlDeserialize)?;
Ok(Self::Base16(scheme))
}
SchemeSystem::Base24 => {
let scheme: base24::Scheme =
serde_yaml::from_str(yaml).map_err(TintedBuilderError::YamlDeserialize)?;
Ok(Self::Base24(scheme))
}
SchemeSystem::Tinted8 => {
let scheme: tinted8::Scheme =
serde_yaml::from_str(yaml).map_err(TintedBuilderError::YamlDeserialize)?;
Ok(Self::Tinted8(Box::new(scheme)))
}
}
}
#[must_use]
pub fn get_scheme_author(&self) -> String {
match self {
Self::Base16(scheme) => scheme.author.clone(),
Self::Base24(scheme) => scheme.author.clone(),
Self::Tinted8(scheme) => scheme.scheme.author.clone(),
}
}
#[must_use]
pub fn get_scheme_description(&self) -> String {
match self {
Self::Base16(scheme) => scheme.description.clone().unwrap_or_default(),
Self::Base24(scheme) => scheme.description.clone().unwrap_or_default(),
Self::Tinted8(scheme) => scheme.scheme.description.clone().unwrap_or_default(),
}
}
#[must_use]
pub fn get_scheme_name(&self) -> String {
match self {
Self::Base16(scheme) => scheme.name.clone(),
Self::Base24(scheme) => scheme.name.clone(),
Self::Tinted8(scheme) => scheme.scheme.name.clone(),
}
}
#[must_use]
pub fn get_scheme_slug(&self) -> String {
match self {
Self::Base16(scheme) => scheme.slug.clone(),
Self::Base24(scheme) => scheme.slug.clone(),
Self::Tinted8(scheme) => scheme.scheme.slug.clone(),
}
}
#[must_use]
pub const fn get_scheme_system(&self) -> SchemeSystem {
match self {
Self::Base16(_) => SchemeSystem::Base16,
Self::Base24(_) => SchemeSystem::Base24,
Self::Tinted8(_) => SchemeSystem::Tinted8,
}
}
#[must_use]
pub fn get_scheme_variant(&self) -> SchemeVariant {
match self {
Self::Base16(scheme) => scheme.variant.clone(),
Self::Base24(scheme) => scheme.variant.clone(),
Self::Tinted8(scheme) => scheme.variant.clone(),
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Default, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum SchemeSystem {
#[default]
Base16,
Base24,
Tinted8,
}
#[derive(Debug, Clone, Default, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub struct SchemeSupports {
#[serde(rename = "styling-spec")]
pub styling_spec: String,
}
impl SchemeSystem {
#[must_use]
pub const fn as_str(&self) -> &str {
match self {
Self::Base16 => "base16",
Self::Base24 => "base24",
Self::Tinted8 => "tinted8",
}
}
#[must_use]
pub const fn variants() -> &'static [Self] {
&[Self::Base16, Self::Base24, Self::Tinted8]
}
}
impl fmt::Display for SchemeSystem {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str())?;
Ok(())
}
}
impl FromStr for SchemeSystem {
type Err = TintedBuilderError;
fn from_str(system_str: &str) -> Result<Self, Self::Err> {
match system_str {
"base16" => Ok(Self::Base16),
"base24" => Ok(Self::Base24),
"tinted8" => Ok(Self::Tinted8),
_ => Err(TintedBuilderError::InvalidSchemeSystem(
system_str.to_string(),
)),
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Default, Deserialize, PartialEq, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum SchemeVariant {
#[default]
Dark,
Light,
}
impl FromStr for SchemeVariant {
type Err = TintedBuilderError;
fn from_str(variant_str: &str) -> Result<Self, Self::Err> {
match variant_str {
"light" => Ok(Self::Light),
"dark" => Ok(Self::Dark),
_ => Err(TintedBuilderError::InvalidSchemeVariant(
variant_str.to_string(),
)),
}
}
}
impl SchemeVariant {
#[must_use]
pub const fn as_str(&self) -> &str {
match self {
Self::Dark => "dark",
Self::Light => "light",
}
}
}
impl fmt::Display for SchemeVariant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str())?;
Ok(())
}
}