1use std::{
2 fmt::{self},
3 str::FromStr,
4};
5
6use chumsky::span::SimpleSpan;
7use colorsys::{Hsl, Rgb};
8use indexmap::IndexMap;
9
10use crate::{FilterReturnType, engine::format_color_all};
11
12#[derive(Debug, Clone)]
13pub enum Value {
14 Ident(String),
15 Int(i64),
16 Float(f64),
17 Color(Rgb),
18 HslColor(Hsl),
19 LazyColor {
20 color: Rgb,
21 scheme: Option<String>, },
23 Bool(bool),
24 Map(IndexMap<String, Value>),
25 Array(Vec<Value>),
26 Null,
27}
28
29pub enum ColorValue {
30 Rgb(Rgb),
31 Hsl(Hsl),
32}
33
34#[derive(Debug, Clone)]
35pub struct SpannedValue {
36 pub value: Value,
37 pub span: SimpleSpan,
38}
39
40impl SpannedValue {
41 pub fn new(value: Value, span: SimpleSpan) -> Self {
42 Self { value, span }
43 }
44}
45
46impl From<&str> for Value {
47 fn from(val: &str) -> Self {
48 Value::Ident(val.to_string())
49 }
50}
51
52impl From<String> for Value {
53 fn from(val: String) -> Self {
54 Value::Ident(val)
55 }
56}
57
58impl From<f64> for Value {
59 fn from(val: f64) -> Self {
60 Value::Int(val as i64)
61 }
62}
63
64impl From<i32> for Value {
65 fn from(val: i32) -> Self {
66 Value::Int(val as i64)
67 }
68}
69
70impl From<i64> for Value {
71 fn from(val: i64) -> Self {
72 Value::Int(val)
73 }
74}
75
76impl From<bool> for Value {
77 fn from(val: bool) -> Self {
78 Value::Bool(val)
79 }
80}
81
82impl From<FilterReturnType> for Value {
83 fn from(value: FilterReturnType) -> Self {
84 match value {
85 FilterReturnType::String(s) => Value::Ident(s),
86 FilterReturnType::Rgb(rgb) => Value::Color(rgb),
87 FilterReturnType::Hsl(hsl) => Value::HslColor(hsl),
88 FilterReturnType::Bool(b) => Value::Bool(b),
89 }
90 }
91}
92
93fn format_float(f: f64) -> String {
94 if f.fract() == 0.0 {
95 return format!("{}", f as i64);
96 }
97 let s = format!("{:.2}", f);
98 let s = s.trim_end_matches('0'); s.trim_end_matches('.').to_string()
100}
101
102impl fmt::Display for Value {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 match self {
105 Value::Ident(v) => write!(f, "{}", v),
106 Value::Int(v) => write!(f, "{}", v),
107 Value::Float(v) => write!(f, "{}", format_float(*v)),
108 Value::Bool(v) => write!(f, "{}", v),
109 Value::Color(color) | Value::LazyColor { color, scheme: _ } => {
110 let formats = format_color_all(color.clone());
111 write!(f, "{:?}", formats)
112 }
113 Value::HslColor(color) => {
114 let formats = format_color_all(color.clone().into());
115 write!(f, "{:?}", formats)
116 }
117 Value::Map(v) => write!(f, "{:?}", v),
118 Value::Array(v) => write!(f, "{:?}", v),
119 Value::Null => write!(f, "Null"),
120 }
121 }
122}
123
124impl Value {
125 pub fn variant_name(&self) -> String {
126 match self {
127 Value::Ident(_) => "String",
128 Value::Int(_) => "Int",
129 Value::Float(_) => "Float",
130 Value::Bool(_) => "Bool",
131 Value::Color(_) => "Color",
132 Value::HslColor(_) => "Hsl Color",
133 Value::LazyColor {
134 color: _,
135 scheme: _,
136 } => "Color",
137 Value::Map(_) => "Map",
138 Value::Null => "Null",
139 Value::Array(_) => "Array",
140 }
141 .to_string()
142 }
143
144 pub fn get_int(&self) -> Option<i64> {
145 match self {
146 Value::Int(v) => Some(*v),
147 _ => None,
148 }
149 }
150
151 pub fn get_float(&self) -> Option<f64> {
152 match self {
153 Value::Int(v) => Some(*v as f64),
154 Value::Float(v) => Some(*v),
155 _ => None,
156 }
157 }
158
159 pub fn is_color(&self) -> bool {
160 match self {
161 Value::Color(_) => true,
162 Value::LazyColor {
163 color: _,
164 scheme: _,
165 } => true,
166 Value::HslColor(_) => true,
167 _ => false,
168 }
169 }
170
171 pub fn get_color(self) -> Option<ColorValue> {
172 match self {
173 Value::Color(color) => Some(ColorValue::Rgb(color)),
174 Value::LazyColor { color, scheme: _ } => Some(ColorValue::Rgb(color)),
175 Value::HslColor(color) => Some(ColorValue::Hsl(color)),
176 _ => None,
177 }
178 }
179}
180
181impl From<serde_json::Value> for Value {
182 fn from(v: serde_json::Value) -> Self {
183 match v {
184 serde_json::Value::Null => Value::Null,
185 serde_json::Value::Bool(b) => Value::Bool(b),
186 serde_json::Value::Number(n) => {
187 if let Some(i) = n.as_i64() {
188 Value::Int(i)
189 } else if let Some(f) = n.as_f64() {
190 Value::Float(f)
191 } else {
192 panic!("Invalid number format");
193 }
194 }
195 serde_json::Value::String(s) => {
196 if let Ok(color) = Rgb::from_str(&s) {
197 Value::Color(color)
198 } else {
199 Value::Ident(s)
200 }
201 }
202 serde_json::Value::Array(arr) => {
203 Value::Array(arr.into_iter().map(Value::from).collect())
204 }
205 serde_json::Value::Object(map) => {
206 Value::Map(map.into_iter().map(|(k, v)| (k, Value::from(v))).collect())
207 }
208 }
209 }
210}