use crate::{
properties::PropertyValue, Color, ColorChannel, Fill, Interpolatable, Percent, Rotation, Size,
Stroke, Transform2D,
};
use std::{any::Any, collections::HashMap, default, fmt::Display};
use self::numeric::Numeric;
pub use coercion_impls::CoercionRules;
use serde::{Deserialize, Serialize};
mod arithmetic;
mod coercion_impls;
pub mod functions;
mod macros;
pub mod numeric;
mod to_from_impls;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(crate = "crate::serde")]
pub enum PaxValue {
Bool(bool),
Numeric(Numeric),
String(String),
Size(Size),
Percent(Percent),
Color(Color),
Rotation(Rotation),
Option(Box<Option<PaxValue>>),
Vec(Vec<PaxValue>),
Range(Box<PaxValue>, Box<PaxValue>),
Object(HashMap<String, PaxValue>),
Enum(String, String, Vec<PaxValue>),
}
impl Display for PaxValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PaxValue::Bool(b) => write!(f, "{}", b),
PaxValue::Numeric(n) => write!(f, "{}", n),
PaxValue::String(s) => write!(f, "\"{}\"", s),
PaxValue::Size(s) => write!(f, "{}", s),
PaxValue::Percent(p) => write!(f, "{}", p),
PaxValue::Color(c) => write!(f, "{}", c),
PaxValue::Rotation(r) => write!(f, "{}", r),
PaxValue::Option(o) => match o.as_ref() {
Some(v) => write!(f, "Some({})", v),
None => write!(f, "None"),
},
PaxValue::Vec(v) => {
write!(f, "[")?;
for (i, val) in v.iter().enumerate() {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "{}", val)?;
}
write!(f, "]")
}
PaxValue::Range(start, end) => write!(f, "{}..{}", start, end),
PaxValue::Object(o) => {
write!(f, "{{")?;
for (i, (key, val)) in o.iter().enumerate() {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "{}: {}", key, val)?;
}
write!(f, "}}")
}
PaxValue::Enum(name, variant, values) => {
if name == "Color" {
write!(f, "{}", variant)?;
} else {
write!(f, "{}::{}", name, variant)?;
}
if !values.is_empty() {
write!(f, "(")?;
for (i, val) in values.iter().enumerate() {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "{}", val)?;
}
write!(f, ")")?;
}
Ok(())
}
}
}
}
impl Default for PaxValue {
fn default() -> Self {
PaxValue::Numeric(Numeric::F64(0.0))
}
}
pub enum PaxAny {
Builtin(PaxValue),
Any(Box<dyn Any>),
}
impl std::fmt::Debug for PaxAny {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "PaxAny {{ .. }}")
}
}
impl Interpolatable for PaxValue {}
pub trait ToPaxValue {
fn to_pax_value(self) -> PaxValue;
}
pub trait ToFromPaxAny
where
Self: Sized + 'static,
{
fn to_pax_any(self) -> PaxAny;
fn from_pax_any(pax_any: PaxAny) -> Result<Self, String>;
fn ref_from_pax_any(pax_any: &PaxAny) -> Result<&Self, String>;
fn mut_from_pax_any(pax_any: &mut PaxAny) -> Result<&mut Self, String>;
}
impl ToFromPaxAny for PaxValue {
fn to_pax_any(self) -> PaxAny {
PaxAny::Builtin(self)
}
fn from_pax_any(pax_any: PaxAny) -> Result<Self, String> {
match pax_any {
PaxAny::Builtin(val) => Ok(val),
PaxAny::Any(_) => Err("tried to unwrap any as builtin".to_string()),
}
}
fn ref_from_pax_any(pax_any: &PaxAny) -> Result<&Self, String> {
match pax_any {
PaxAny::Builtin(val) => Ok(val),
PaxAny::Any(_) => Err("tried to unwrap any as builtin".to_string()),
}
}
fn mut_from_pax_any(pax_any: &mut PaxAny) -> Result<&mut Self, String> {
match pax_any {
PaxAny::Builtin(val) => Ok(val),
PaxAny::Any(_) => Err("tried to unwrap any as builtin".to_string()),
}
}
}
pub trait ImplToFromPaxAny: 'static {}
impl<T: ImplToFromPaxAny> ToFromPaxAny for T {
fn to_pax_any(self) -> PaxAny {
PaxAny::Any(Box::new(self) as Box<dyn Any>)
}
fn from_pax_any(pax_any: PaxAny) -> Result<Self, String> {
match pax_any {
PaxAny::Any(v) => Ok(*v
.downcast::<Self>()
.map_err(|_e| "downcast failed".to_string())?),
_ => Err("wasn't any".to_string()),
}
}
fn ref_from_pax_any(pax_any: &PaxAny) -> Result<&Self, String> {
match pax_any {
PaxAny::Any(v) => v
.downcast_ref::<Self>()
.ok_or_else(|| "downcast failed".to_string()),
_ => Err("wasn't any".to_string()),
}
}
fn mut_from_pax_any(pax_any: &mut PaxAny) -> Result<&mut Self, String> {
match pax_any {
PaxAny::Any(v) => v
.downcast_mut::<Self>()
.ok_or_else(|| "downcast failed".to_string()),
_ => Err("wasn't any".to_string()),
}
}
}
impl ToFromPaxAny for PaxAny {
fn to_pax_any(self) -> PaxAny {
self
}
fn from_pax_any(pax_any: PaxAny) -> Result<Self, String> {
Ok(pax_any)
}
fn ref_from_pax_any(pax_any: &PaxAny) -> Result<&Self, String> {
Ok(pax_any)
}
fn mut_from_pax_any(pax_any: &mut PaxAny) -> Result<&mut Self, String> {
Ok(pax_any)
}
}