use crate::{Color, Duration, Interpolatable, PathElement, Percent, Rotation, Size};
use std::{any::Any, fmt::Display, rc::Rc};
use self::numeric::Numeric;
pub use coercion_impls::{is_typed_binding_safe, CoercionRules};
use serde::{Deserialize, Serialize};
mod arithmetic;
mod coercion_impls;
pub mod functions;
mod macros;
pub mod numeric;
mod to_from_impls;
pub type RcPaxValue = Rc<PaxValue>;
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[serde(crate = "crate::serde")]
pub enum PaxValue {
Bool(bool),
Numeric(Numeric),
String(String),
Size(Size),
Percent(Percent),
Color(Box<Color>),
Rotation(Rotation),
Duration(Duration),
PathElement(Box<PathElement>),
Option(Box<Option<PaxValue>>),
Vec(Vec<PaxValue>),
Range(Box<PaxValue>, Box<PaxValue>),
Object(Vec<(String, PaxValue)>),
Enum(Box<(String, String, Vec<PaxValue>)>),
}
impl Clone for PaxValue {
fn clone(&self) -> Self {
match self {
PaxValue::Bool(b) => PaxValue::Bool(*b),
PaxValue::Numeric(n) => PaxValue::Numeric(n.clone()),
PaxValue::String(s) => PaxValue::String(s.clone()),
PaxValue::Size(s) => PaxValue::Size(s.clone()),
PaxValue::Percent(p) => PaxValue::Percent(p.clone()),
PaxValue::Color(c) => PaxValue::Color(c.clone()),
PaxValue::Rotation(r) => PaxValue::Rotation(r.clone()),
PaxValue::Duration(d) => PaxValue::Duration(d.clone()),
PaxValue::PathElement(pe) => PaxValue::PathElement(pe.clone()),
PaxValue::Option(opt) => PaxValue::Option(opt.clone()),
PaxValue::Vec(v) => PaxValue::Vec(v.clone()),
PaxValue::Range(start, end) => PaxValue::Range(start.clone(), end.clone()),
PaxValue::Object(pairs) => PaxValue::Object(pairs.clone()),
PaxValue::Enum(contents) => {
let (name, variant, values) = contents.as_ref();
PaxValue::Enum(Box::new((name.clone(), variant.clone(), values.clone())))
}
}
}
}
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::Duration(d) => write!(f, "{}", d),
PaxValue::PathElement(path_elem) => {
write!(f, "PathElement::")?;
match path_elem.as_ref() {
PathElement::Empty => write!(f, "Empty"),
PathElement::Point(s1, s2) => write!(f, "Point({}, {})", s1, s2),
PathElement::Line => write!(f, "Line"),
PathElement::Quadratic(s1, s2) => write!(f, "Quadratic({}, {})", s1, s2),
PathElement::Cubic(v1, v2, v3, v4) => {
write!(f, "Cubic({}, {}, {}, {})", v1, v2, v3, v4)
}
PathElement::Close => write!(f, "Close"),
}?;
Ok(())
}
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(contents) => {
let (name, variant, values) = contents.as_ref();
if (name == "Fill" || name == "Stroke") && variant == "__layer" && values.len() == 1
{
return write!(f, "{} {}", name, values[0]);
}
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 nested_properties(&self) -> Vec<crate::properties::UntypedProperty> {
Vec::new()
}
fn to_pax_value(self) -> PaxValue;
fn to_pax_value_in_graph(self) -> PaxValue
where
Self: Sized,
{
crate::properties::with_graph_conversion(|| self.to_pax_value())
}
}
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)
}
}