|
1 | 1 | use clap::ValueEnum; |
2 | 2 |
|
| 3 | +use serde::ser::SerializeSeq; |
3 | 4 | use serde::Deserialize; |
4 | 5 | use serde::Serialize; |
5 | 6 | use strum::Display; |
6 | 7 | use strum::EnumString; |
7 | 8 |
|
8 | | -#[derive(Copy, Clone, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, PartialEq)] |
| 9 | +#[derive(Copy, Clone, Debug, Display, EnumString, ValueEnum, PartialEq)] |
9 | 10 | #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] |
10 | 11 | pub enum AnimationStyle { |
11 | 12 | Linear, |
@@ -38,4 +39,81 @@ pub enum AnimationStyle { |
38 | 39 | EaseInBounce, |
39 | 40 | EaseOutBounce, |
40 | 41 | EaseInOutBounce, |
| 42 | + #[value(skip)] |
| 43 | + CubicBezier(f64, f64, f64, f64), |
| 44 | +} |
| 45 | + |
| 46 | +// Custom serde implementation |
| 47 | +impl<'de> Deserialize<'de> for AnimationStyle { |
| 48 | + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
| 49 | + where |
| 50 | + D: serde::Deserializer<'de>, |
| 51 | + { |
| 52 | + struct AnimationStyleVisitor; |
| 53 | + |
| 54 | + impl<'de> serde::de::Visitor<'de> for AnimationStyleVisitor { |
| 55 | + type Value = AnimationStyle; |
| 56 | + |
| 57 | + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { |
| 58 | + formatter.write_str("a string or an array of four f64 values") |
| 59 | + } |
| 60 | + |
| 61 | + // Handle string variants (e.g., "EaseInOutExpo") |
| 62 | + fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> |
| 63 | + where |
| 64 | + E: serde::de::Error, |
| 65 | + { |
| 66 | + value.parse().map_err(|_| E::unknown_variant(value, &[])) |
| 67 | + } |
| 68 | + |
| 69 | + // Handle CubicBezier array (e.g., [0.32, 0.72, 0.0, 1.0]) |
| 70 | + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> |
| 71 | + where |
| 72 | + A: serde::de::SeqAccess<'de>, |
| 73 | + { |
| 74 | + let x1 = seq |
| 75 | + .next_element()? |
| 76 | + .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; |
| 77 | + let y1 = seq |
| 78 | + .next_element()? |
| 79 | + .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?; |
| 80 | + let x2 = seq |
| 81 | + .next_element()? |
| 82 | + .ok_or_else(|| serde::de::Error::invalid_length(2, &self))?; |
| 83 | + let y2 = seq |
| 84 | + .next_element()? |
| 85 | + .ok_or_else(|| serde::de::Error::invalid_length(3, &self))?; |
| 86 | + |
| 87 | + // Ensure no extra elements |
| 88 | + if seq.next_element::<serde::de::IgnoredAny>()?.is_some() { |
| 89 | + return Err(serde::de::Error::invalid_length(5, &self)); |
| 90 | + } |
| 91 | + |
| 92 | + Ok(AnimationStyle::CubicBezier(x1, y1, x2, y2)) |
| 93 | + } |
| 94 | + } |
| 95 | + |
| 96 | + deserializer.deserialize_any(AnimationStyleVisitor) |
| 97 | + } |
| 98 | +} |
| 99 | + |
| 100 | +impl Serialize for AnimationStyle { |
| 101 | + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
| 102 | + where |
| 103 | + S: serde::Serializer, |
| 104 | + { |
| 105 | + match self { |
| 106 | + // Serialize CubicBezier as an array |
| 107 | + AnimationStyle::CubicBezier(x1, y1, x2, y2) => { |
| 108 | + let mut seq = serializer.serialize_seq(Some(4))?; |
| 109 | + seq.serialize_element(x1)?; |
| 110 | + seq.serialize_element(y1)?; |
| 111 | + seq.serialize_element(x2)?; |
| 112 | + seq.serialize_element(y2)?; |
| 113 | + seq.end() |
| 114 | + } |
| 115 | + // Serialize all other variants as strings |
| 116 | + _ => serializer.serialize_str(&self.to_string()), |
| 117 | + } |
| 118 | + } |
41 | 119 | } |
0 commit comments