Skip to main content

mdbook_plotly/code_handler/
until.rs

1// Tmp fix
2#![allow(unexpected_cfgs)]
3
4use crate::code_handler::parse_context::ParseContext;
5use crate::preprocessor::config::{MapEvalConfig, MapNamespaceScope};
6use anyhow::{Context, Result, anyhow};
7use fasteval::{Compiler, EvalNamespace, Evaler, Parser, Slab};
8use serde::{Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned};
9use serde_json::{Map as JsonMap, Value, value::Index};
10use std::{collections::BTreeMap, fmt::Debug, fmt::Display};
11
12#[cfg(feature = "map-parser-extensions")]
13use chrono::{DateTime, NaiveDate, NaiveDateTime, TimeDelta, Utc};
14#[cfg(feature = "map-parser-extensions")]
15use rand::{Rng, RngExt, SeedableRng, rngs::StdRng};
16
17pub type Map = JsonMap<String, Value>;
18
19type Vars = BTreeMap<String, f64>;
20
21#[derive(Clone, Debug)]
22pub enum DataPack<T> {
23    Data(T),
24    Index(String),
25}
26
27#[allow(dead_code)]
28#[inline]
29pub fn must_translate<T, N>(obj: &mut Value, map: &Map, name: N) -> Result<T>
30where
31    T: DeserializeOwned + Serialize + Debug + Clone,
32    N: Index + Display,
33{
34    must_translate_with_config(obj, map, &MapEvalConfig::default(), name)
35}
36
37#[allow(dead_code)]
38#[inline]
39pub fn must_translate_from_context<T, N>(
40    obj: &mut Value,
41    context: &ParseContext<'_>,
42    name: N,
43) -> Result<T>
44where
45    T: DeserializeOwned + Serialize + Debug + Clone,
46    N: Index + Display,
47{
48    must_translate_with_config(obj, context.map(), context.map_eval(), name)
49}
50
51#[inline]
52pub fn must_translate_with_config<T, N>(
53    obj: &mut Value,
54    map: &Map,
55    map_eval: &MapEvalConfig,
56    name: N,
57) -> Result<T>
58where
59    T: DeserializeOwned + Serialize + Debug + Clone,
60    N: Index + Display,
61{
62    take_optional(obj, map, map_eval, &name)?.ok_or_else(|| anyhow!("missing `{}` field", name))
63}
64
65#[inline]
66fn take_optional<T, N>(
67    obj: &mut Value,
68    map: &Map,
69    map_eval: &MapEvalConfig,
70    name: &N,
71) -> Result<Option<T>>
72where
73    T: DeserializeOwned + Serialize + Debug + Clone,
74    N: Index + Display,
75{
76    let Some(value) = obj.get_mut(name) else {
77        return Ok(None);
78    };
79
80    serde_json::from_value::<DataPack<T>>(value.take())
81        .with_context(|| format!("failed to deserialize field '{}'", name))?
82        .unwrap(map, map_eval)
83        .with_context(|| format!("failed to unwrap DataPack for field '{}'", name))
84        .map(Some)
85}
86
87#[inline]
88fn try_deser<T: DeserializeOwned>(value: Value, context: &'static str) -> Result<T> {
89    serde_json::from_value(value).context(context)
90}
91
92#[inline]
93fn json_number(value: f64) -> Result<Value> {
94    serde_json::Number::from_f64(value)
95        .map(Value::Number)
96        .ok_or_else(|| anyhow!("failed to create JSON number from {}", value))
97}
98
99#[inline]
100fn usize_count(count: u64, field: &str) -> Result<usize> {
101    usize::try_from(count).with_context(|| format!("{} is too large for this platform", field))
102}
103
104fn value_to_f64(value: &Value) -> Option<f64> {
105    match value {
106        Value::Number(n) => n.as_f64(),
107        Value::Bool(v) => Some(if *v { 1.0 } else { 0.0 }),
108        Value::String(s) => s.parse::<f64>().ok(),
109        _ => None,
110    }
111}
112
113fn lookup_path<'a>(map: &'a Map, name: &str) -> Option<&'a Value> {
114    let path = name.strip_prefix("map.").unwrap_or(name);
115    let mut parts = path.split('.');
116    let first = parts.next()?;
117    let mut value = map.get(first)?;
118
119    for part in parts {
120        match value {
121            Value::Object(obj) => value = obj.get(part)?,
122            Value::Array(arr) => {
123                let idx = part.parse::<usize>().ok()?;
124                value = arr.get(idx)?;
125            }
126            _ => return None,
127        }
128    }
129
130    Some(value)
131}
132
133fn map_value<'a>(map: &'a Map, index: &str) -> Result<&'a Value> {
134    lookup_path(map, index).ok_or_else(|| anyhow!("missing map value `{}`", index))
135}
136
137struct MapNamespace<'a> {
138    map: &'a Map,
139    vars: &'a Vars,
140    scope: &'a MapNamespaceScope,
141}
142
143impl<'a> MapNamespace<'a> {
144    fn new(map: &'a Map, vars: &'a Vars, scope: &'a MapNamespaceScope) -> Self {
145        Self { map, vars, scope }
146    }
147
148    fn lookup_map_value(&self, name: &str) -> Option<f64> {
149        match self.scope {
150            MapNamespaceScope::FullMap => lookup_path(self.map, name).and_then(value_to_f64),
151            MapNamespaceScope::ExportsOnly => {
152                let path = if name.starts_with("map.exports.") {
153                    name.to_owned()
154                } else {
155                    format!("exports.{name}")
156                };
157                lookup_path(self.map, &path).and_then(value_to_f64)
158            }
159        }
160    }
161}
162
163impl EvalNamespace for MapNamespace<'_> {
164    fn lookup(&mut self, name: &str, _args: Vec<f64>, _keybuf: &mut String) -> Option<f64> {
165        self.vars
166            .get(name)
167            .copied()
168            .or_else(|| self.lookup_map_value(name))
169    }
170}
171
172struct EvalContext {
173    parser: Parser,
174    slab: Slab,
175    config: MapEvalConfig,
176}
177
178impl EvalContext {
179    fn new(config: &MapEvalConfig) -> Self {
180        Self {
181            parser: Parser::new(),
182            slab: Slab::new(),
183            config: config.clone(),
184        }
185    }
186
187    fn eval(&mut self, expr: &str, map: &Map, vars: &Vars) -> Result<f64> {
188        let mut namespace = MapNamespace::new(map, vars, &self.config.namespace_scope);
189
190        if !self.config.enabled || !self.config.compile_expressions {
191            let expr_ref = self
192                .parser
193                .parse(expr, &mut self.slab.ps)
194                .with_context(|| format!("failed to parse expression `{}`", expr))?
195                .from(&self.slab.ps);
196
197            return expr_ref
198                .eval(&self.slab, &mut namespace)
199                .with_context(|| format!("failed to evaluate expression `{}`", expr));
200        }
201
202        let expr_ref = self
203            .parser
204            .parse(expr, &mut self.slab.ps)
205            .with_context(|| format!("failed to parse expression `{}`", expr))?
206            .from(&self.slab.ps);
207
208        let compiled = expr_ref.compile(&self.slab.ps, &mut self.slab.cs);
209        Ok(fasteval::eval_compiled!(
210            compiled,
211            &self.slab,
212            &mut namespace
213        ))
214    }
215}
216
217impl<T> DataPack<T>
218where
219    T: DeserializeOwned + Serialize + Debug + Clone,
220{
221    pub fn unwrap(self, map: &Map, map_eval: &MapEvalConfig) -> Result<T> {
222        match self {
223            Self::Data(data) => Ok(data),
224            Self::Index(index) => {
225                let value = map_value(map, &index)?.clone();
226                Self::parse_value(map, value, map_eval)
227                    .with_context(|| format!("failed to resolve map value `{}`", index))
228            }
229        }
230    }
231
232    pub fn unwrap_from_context(self, context: &ParseContext<'_>) -> Result<T> {
233        self.unwrap(context.map(), context.map_eval())
234    }
235
236    fn parse_value(map: &Map, value: Value, map_eval: &MapEvalConfig) -> Result<T> {
237        if value.is_object() && value.get("type").is_some() {
238            Self::parse_map(map, value, map_eval)
239        } else {
240            serde_json::from_value(value).context("failed to deserialize value")
241        }
242    }
243
244    fn parse_map(map: &Map, mut value: Value, map_eval: &MapEvalConfig) -> Result<T> {
245        let value_type = value
246            .get("type")
247            .and_then(Value::as_str)
248            .ok_or_else(|| anyhow!("`type` must be a string"))?
249            .to_owned();
250
251        let mut eval = EvalContext::new(map_eval);
252        let vars = Vars::new();
253
254        match value_type.as_str() {
255            "raw" => must_translate_with_config(&mut value, map, map_eval, "data"),
256            "g-number" => parse_g_number(map, &mut value, &mut eval, &vars),
257            "g-number-list" => parse_g_number_list(map, &mut value, &mut eval),
258            "g-range" => parse_g_range(map, &mut value),
259            "g-repeat" => parse_g_repeat(map, &mut value),
260            "g-linear" => parse_g_linear(map, &mut value),
261            "if" => parse_if(map, &mut value, &mut eval, &vars),
262            #[cfg(feature = "map-parser-extensions")]
263            "time" => parse_time(map, &mut value),
264            #[cfg(feature = "map-parser-extensions")]
265            "g-random" => parse_g_random(map, &mut value),
266            #[cfg(feature = "map-parser-extensions")]
267            "g-choose" => parse_g_choose(map, &mut value),
268            "g-env" => parse_g_env(map, &mut value),
269            "g-join" => parse_g_join(map, &mut value),
270            _ => Err(anyhow!("unknown type `{}`", value_type)),
271        }
272    }
273}
274
275fn parse_g_number<T>(map: &Map, value: &mut Value, eval: &mut EvalContext, vars: &Vars) -> Result<T>
276where
277    T: DeserializeOwned,
278{
279    let expr: String = must_translate(value, map, "expr")?;
280    try_deser(
281        json_number(eval.eval(&expr, map, vars)?)?,
282        "failed to deserialize generated number",
283    )
284}
285
286fn parse_g_number_list<T>(map: &Map, value: &mut Value, eval: &mut EvalContext) -> Result<T>
287where
288    T: DeserializeOwned,
289{
290    let index_begin: u64 = must_translate(value, map, "begin")?;
291    let index_end: u64 = must_translate(value, map, "end")?;
292    let expr: String = must_translate(value, map, "expr")?;
293
294    let len = index_end.saturating_sub(index_begin);
295    let mut result = Vec::with_capacity(usize_count(len, "g-number-list length")?);
296    let mut vars = Vars::new();
297
298    let compiled = eval
299        .parser
300        .parse(&expr, &mut eval.slab.ps)
301        .with_context(|| format!("failed to parse expression `{}`", expr))?
302        .from(&eval.slab.ps)
303        .compile(&eval.slab.ps, &mut eval.slab.cs);
304
305    for i in index_begin..index_end {
306        vars.insert("i".to_owned(), i as f64);
307        let mut namespace = MapNamespace::new(map, &vars, &eval.config.namespace_scope);
308        let value = if eval.config.enabled && eval.config.compile_expressions {
309            fasteval::eval_compiled!(compiled, &eval.slab, &mut namespace)
310        } else {
311            eval.eval(&expr, map, &vars)?
312        };
313        result.push(json_number(value)?);
314    }
315
316    try_deser(
317        Value::Array(result),
318        "failed to deserialize generated number list",
319    )
320}
321
322fn parse_g_range<T>(map: &Map, value: &mut Value) -> Result<T>
323where
324    T: DeserializeOwned,
325{
326    let begin: f64 = must_translate(value, map, "begin")?;
327    let end: f64 = must_translate(value, map, "end")?;
328    let step: f64 = take_optional(value, map, &MapEvalConfig::default(), &"step")?.unwrap_or(1.0);
329
330    if step <= 0.0 {
331        return Err(anyhow!("step must be positive"));
332    }
333
334    let capacity = if end > begin {
335        ((end - begin) / step).ceil() as usize
336    } else {
337        0
338    };
339    let mut result = Vec::with_capacity(capacity);
340    let mut current = begin;
341
342    while current < end {
343        result.push(json_number(current)?);
344        current += step;
345    }
346
347    try_deser(
348        Value::Array(result),
349        "failed to deserialize generated range",
350    )
351}
352
353fn parse_g_repeat<T>(map: &Map, value: &mut Value) -> Result<T>
354where
355    T: DeserializeOwned + Serialize + Debug + Clone,
356{
357    let val: Value = must_translate(value, map, "value")?;
358    let count: u64 = must_translate(value, map, "count")?;
359    let count = usize_count(count, "count")?;
360    let result = vec![val; count];
361    try_deser(
362        Value::Array(result),
363        "failed to deserialize repeated values",
364    )
365}
366
367fn parse_g_linear<T>(map: &Map, value: &mut Value) -> Result<T>
368where
369    T: DeserializeOwned,
370{
371    let begin: f64 = must_translate(value, map, "begin")?;
372    let end: f64 = must_translate(value, map, "end")?;
373    let count: u64 = must_translate(value, map, "count")?;
374
375    if count == 0 {
376        return Err(anyhow!("count must be positive"));
377    }
378
379    let count_usize = usize_count(count, "count")?;
380    let mut result = Vec::with_capacity(count_usize);
381
382    if count == 1 {
383        result.push(json_number(begin)?);
384    } else {
385        let step = (end - begin) / ((count - 1) as f64);
386        for i in 0..count {
387            result.push(json_number(begin + (i as f64) * step)?);
388        }
389    }
390
391    try_deser(
392        Value::Array(result),
393        "failed to deserialize linear spaced values",
394    )
395}
396
397fn parse_if<T>(map: &Map, value: &mut Value, eval: &mut EvalContext, vars: &Vars) -> Result<T>
398where
399    T: DeserializeOwned + Serialize + Debug + Clone,
400{
401    let condition: String = must_translate(value, map, "condition")?;
402    let true_val: Value = must_translate(value, map, "true")?;
403    let false_val: Value = must_translate(value, map, "false")?;
404    let selected = if eval.eval(&condition, map, vars)? != 0.0 {
405        true_val
406    } else {
407        false_val
408    };
409
410    DataPack::<T>::parse_value(map, selected, &eval.config)
411}
412
413#[cfg(feature = "map-parser-extensions")]
414fn parse_time<T>(map: &Map, value: &mut Value) -> Result<T>
415where
416    T: DeserializeOwned,
417{
418    let start: String = must_translate(value, map, "start")?;
419    let end: String = must_translate(value, map, "end")?;
420    let interval: String = must_translate(value, map, "interval")?;
421    let format: Option<String> = take_optional(value, map, &MapEvalConfig::default(), &"format")?;
422
423    let start_dt = parse_time_str(&start)?;
424    let end_dt = parse_time_str(&end)?;
425    let step = parse_duration_str(&interval)?;
426
427    if step <= TimeDelta::zero() {
428        return Err(anyhow!("interval must be positive"));
429    }
430
431    let mut result = Vec::new();
432    let mut current = start_dt;
433
434    while current <= end_dt {
435        let ts = format.as_ref().map_or_else(
436            || current.to_rfc3339(),
437            |fmt| current.format(fmt).to_string(),
438        );
439        result.push(Value::String(ts));
440
441        let Some(next) = current.checked_add_signed(step) else {
442            break;
443        };
444        current = next;
445    }
446
447    try_deser(Value::Array(result), "failed to deserialize time values")
448}
449
450#[cfg(feature = "map-parser-extensions")]
451fn parse_g_random<T>(map: &Map, value: &mut Value) -> Result<T>
452where
453    T: DeserializeOwned,
454{
455    let min: f64 = must_translate(value, map, "min")?;
456    let max: f64 = must_translate(value, map, "max")?;
457
458    if min >= max {
459        return Err(anyhow!("min ({}) must be less than max ({})", min, max));
460    }
461
462    let integer = value
463        .get("integer")
464        .and_then(Value::as_bool)
465        .unwrap_or(false);
466    let seed: Option<u64> = take_optional(value, map, &MapEvalConfig::default(), &"seed")?;
467    let count: Option<u64> = take_optional(value, map, &MapEvalConfig::default(), &"count")?;
468
469    let gen_value = |rng: &mut dyn Rng| -> Result<Value> {
470        if integer {
471            if min.fract() != 0.0 || max.fract() != 0.0 {
472                return Err(anyhow!("integer random bounds must be whole numbers"));
473            }
474            Ok(Value::from(rng.random_range(min as i64..max as i64)))
475        } else {
476            json_number(rng.random_range(min..max))
477        }
478    };
479
480    match count {
481        Some(0) => Err(anyhow!("count must be positive")),
482        Some(count) => {
483            let count = usize_count(count, "count")?;
484            let values = with_rng(seed, |rng| {
485                (0..count)
486                    .map(|_| gen_value(rng))
487                    .collect::<Result<Vec<_>>>()
488            })?;
489            try_deser(Value::Array(values), "failed to deserialize g-random array")
490        }
491        None => {
492            let value = with_rng(seed, |rng| gen_value(rng))?;
493            try_deser(value, "failed to deserialize g-random single value")
494        }
495    }
496}
497
498#[cfg(feature = "map-parser-extensions")]
499fn parse_g_choose<T>(map: &Map, value: &mut Value) -> Result<T>
500where
501    T: DeserializeOwned + Serialize + Debug + Clone,
502{
503    let options: Vec<Value> = must_translate(value, map, "options")?;
504    if options.is_empty() {
505        return Err(anyhow!("options must not be empty for g-choose"));
506    }
507
508    let seed: Option<u64> = take_optional(value, map, &MapEvalConfig::default(), &"seed")?;
509    let count: Option<u64> = take_optional(value, map, &MapEvalConfig::default(), &"count")?;
510
511    match count {
512        Some(0) => Err(anyhow!("count must be positive")),
513        Some(count) => {
514            let count = usize_count(count, "count")?;
515            let selected = with_rng(seed, |rng| {
516                (0..count)
517                    .map(|_| options[rng.random_range(0..options.len())].clone())
518                    .collect::<Vec<_>>()
519            });
520            try_deser(
521                Value::Array(selected),
522                "failed to deserialize g-choose array",
523            )
524        }
525        None => {
526            let picked = with_rng(seed, |rng| {
527                options[rng.random_range(0..options.len())].clone()
528            });
529            try_deser(picked, "failed to deserialize g-choose single value")
530        }
531    }
532}
533
534fn parse_g_env<T>(map: &Map, value: &mut Value) -> Result<T>
535where
536    T: DeserializeOwned,
537{
538    let name: String = must_translate(value, map, "name")?;
539    let default: Option<String> = take_optional(value, map, &MapEvalConfig::default(), &"default")?;
540    let env_val = std::env::var(&name).ok().or(default).ok_or_else(|| {
541        anyhow!(
542            "environment variable '{}' is not set and no default provided",
543            name
544        )
545    })?;
546
547    try_deser(Value::String(env_val), "failed to deserialize env value")
548}
549
550fn parse_g_join<T>(map: &Map, value: &mut Value) -> Result<T>
551where
552    T: DeserializeOwned,
553{
554    let values: Vec<String> = must_translate(value, map, "values")?;
555    let separator: String =
556        take_optional(value, map, &MapEvalConfig::default(), &"separator")?.unwrap_or_default();
557    try_deser(
558        Value::String(values.join(&separator)),
559        "failed to deserialize joined string",
560    )
561}
562
563#[cfg(feature = "map-parser-extensions")]
564fn parse_duration_str(s: &str) -> Result<TimeDelta> {
565    let s = s.trim();
566    if s.is_empty() {
567        return Err(anyhow!("duration string is empty"));
568    }
569
570    let mut total = TimeDelta::zero();
571    let mut num_str = String::new();
572
573    for ch in s.chars() {
574        if ch.is_ascii_digit() || ch == '.' {
575            num_str.push(ch);
576            continue;
577        }
578
579        if ch.is_whitespace() {
580            continue;
581        }
582
583        if !ch.is_alphabetic() {
584            return Err(anyhow!("unexpected character '{}' in duration string", ch));
585        }
586
587        if num_str.is_empty() {
588            return Err(anyhow!("missing number before duration unit '{}'", ch));
589        }
590
591        let num: f64 = num_str
592            .parse()
593            .with_context(|| format!("invalid number in duration: '{}'", num_str))?;
594        if num <= 0.0 {
595            return Err(anyhow!("duration components must be positive"));
596        }
597        num_str.clear();
598
599        let seconds = match ch.to_ascii_lowercase() {
600            's' => num,
601            'm' => num * 60.0,
602            'h' => num * 3_600.0,
603            'd' => num * 86_400.0,
604            'w' => num * 604_800.0,
605            other => return Err(anyhow!("unknown duration unit: '{}'", other)),
606        };
607
608        let delta = TimeDelta::try_seconds(seconds as i64)
609            .ok_or_else(|| anyhow!("duration overflow: {}{}", num, ch))?;
610        total = total
611            .checked_add(&delta)
612            .ok_or_else(|| anyhow!("duration overflow"))?;
613    }
614
615    if !num_str.is_empty() {
616        return Err(anyhow!("trailing number without unit: '{}'", num_str));
617    }
618    if total.is_zero() {
619        return Err(anyhow!("duration must be positive, got: '{}'", s));
620    }
621
622    Ok(total)
623}
624
625#[cfg(feature = "map-parser-extensions")]
626fn parse_time_str(s: &str) -> Result<DateTime<Utc>> {
627    let s = s.trim();
628
629    if let Some(rest) = s.strip_prefix("now") {
630        let base = Utc::now();
631        if rest.is_empty() {
632            return Ok(base);
633        }
634
635        let sign_char = rest
636            .chars()
637            .next()
638            .ok_or_else(|| anyhow!("expected '+' or '-' after 'now'"))?;
639        let duration_str = &rest[sign_char.len_utf8()..];
640        let delta = parse_duration_str(duration_str)?;
641
642        return match sign_char {
643            '+' => base
644                .checked_add_signed(delta)
645                .ok_or_else(|| anyhow!("time overflow for '{}'", s)),
646            '-' => base
647                .checked_sub_signed(delta)
648                .ok_or_else(|| anyhow!("time overflow for '{}'", s)),
649            _ => Err(anyhow!("expected '+' or '-' after 'now', got '{}'", rest)),
650        };
651    }
652
653    if let Ok(dt) = DateTime::parse_from_rfc3339(s) {
654        return Ok(dt.with_timezone(&Utc));
655    }
656
657    for fmt in [
658        "%Y-%m-%dT%H:%M:%S%.f%:z",
659        "%Y-%m-%dT%H:%M:%S%.f",
660        "%Y-%m-%dT%H:%M:%S%:z",
661        "%Y-%m-%dT%H:%M:%S",
662        "%Y-%m-%d %H:%M:%S",
663    ] {
664        if let Ok(dt) = DateTime::parse_from_str(s, fmt) {
665            return Ok(dt.with_timezone(&Utc));
666        }
667        if let Ok(naive) = NaiveDateTime::parse_from_str(s, fmt) {
668            return Ok(naive.and_utc());
669        }
670    }
671
672    if let Ok(date) = NaiveDate::parse_from_str(s, "%Y-%m-%d") {
673        return date
674            .and_hms_opt(0, 0, 0)
675            .map(|s| s.and_utc())
676            .ok_or_else(|| anyhow!("invalid date: '{}'", s));
677    }
678
679    Err(anyhow!(
680        "unable to parse time string: '{}'. Supported formats: RFC 3339, \
681         'YYYY-MM-DDTHH:MM:SS', 'YYYY-MM-DD HH:MM:SS', 'YYYY-MM-DD', \
682         'now', 'now+duration', 'now-duration'",
683        s
684    ))
685}
686
687#[cfg(feature = "map-parser-extensions")]
688fn with_rng<F, R>(seed: Option<u64>, f: F) -> R
689where
690    F: FnOnce(&mut dyn Rng) -> R,
691{
692    if let Some(seed) = seed {
693        let mut rng = StdRng::seed_from_u64(seed);
694        f(&mut rng)
695    } else {
696        let mut rng = rand::rng();
697        f(&mut rng)
698    }
699}
700
701impl<'de, T> Deserialize<'de> for DataPack<T>
702where
703    T: DeserializeOwned + Serialize + Debug + Clone,
704{
705    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
706    where
707        D: Deserializer<'de>,
708    {
709        let value = Value::deserialize(deserializer)?;
710
711        if let Some(index) = value.as_str().and_then(|s| s.strip_prefix("map.")) {
712            return Ok(Self::Index(index.to_owned()));
713        }
714
715        serde_json::from_value::<T>(value)
716            .map(Self::Data)
717            .map_err(serde::de::Error::custom)
718    }
719}
720
721impl<T> Serialize for DataPack<T>
722where
723    T: DeserializeOwned + Serialize + Debug + Clone,
724{
725    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
726    where
727        S: Serializer,
728    {
729        match self {
730            Self::Data(data) => data.serialize(serializer),
731            Self::Index(index) => serializer.serialize_str(&format!("map.{index}")),
732        }
733    }
734}
735
736use plotly::color;
737
738// This is to make Json look clearer when it is written.
739#[allow(clippy::enum_variant_names)]
740#[derive(Clone, Debug, Serialize)]
741#[serde(rename_all = "snake_case")]
742pub enum Color {
743    NamedColor(color::NamedColor),
744    RgbColor(color::Rgb),
745    RgbaColor(color::Rgba),
746}
747
748impl color::Color for Color {}
749
750impl<'de> Deserialize<'de> for Color {
751    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
752    where
753        D: Deserializer<'de>,
754    {
755        let value = Value::deserialize(deserializer)?;
756
757        if let Some(s) = value.as_str()
758            && let Ok(named) = serde_json::from_str::<color::NamedColor>(&format!("\"{s}\""))
759        {
760            return Ok(Self::NamedColor(named));
761        }
762
763        if let Ok(rgb) = serde_json::from_value::<color::Rgb>(value.clone()) {
764            return Ok(Self::RgbColor(rgb));
765        }
766
767        if let Ok(rgba) = serde_json::from_value::<color::Rgba>(value) {
768            return Ok(Self::RgbaColor(rgba));
769        }
770
771        Err(serde::de::Error::custom("invalid color format"))
772    }
773}