mdbook_plotly/preprocessor/handlers/code_handler/
until.rs1use anyhow::{Result, anyhow};
2use serde::{Deserialize, Deserializer, Serialize, Serializer, de::DeserializeOwned};
3use serde_json::{Map as JsonMap, Value, value::Index};
4use std::fmt::{Debug, Display};
5
6pub type Map = JsonMap<String, Value>;
7
8#[inline]
9pub fn must_translate<T, N>(obj: &mut Value, map: &Map, name: N) -> Result<T>
10where
11 T: DeserializeOwned + Serialize + Debug + Clone,
12 N: Index + Display,
13{
14 let result = obj
15 .get_mut(&name)
16 .ok_or(anyhow!("missing `{}` field", name))?;
17 let result = serde_json::from_value::<DataPack<T>>(result.take())?.unwrap(map)?;
18 Ok(result)
19}
20
21#[derive(Clone, Debug)]
22pub enum DataPack<T> {
23 Data(T),
24 Index(String),
25}
26
27impl<T> DataPack<T>
28where
29 T: DeserializeOwned + Serialize + Debug + Clone,
30{
31 fn parse_map(map: &Map, mut value: Value) -> Result<T> {
32 if !value.is_object() {
33 let direct_result = serde_json::from_value::<T>(value.clone())?;
34 return Ok(direct_result);
35 }
36 let value_type = &value["type"];
37 let value_type = if !value_type.is_string() {
38 return Err(anyhow!("`type` must be a string"));
39 } else {
40 value_type.as_str().unwrap()
42 };
43 use fasteval::ez_eval;
44 match value_type {
45 "raw" => {
46 let result = must_translate(&mut value, map, "data")?;
47 Ok(result)
48 }
49 "g-number-list" => {
51 let index_begin: u64 = must_translate(&mut value, map, "begin")?;
52 let index_end: u64 = must_translate(&mut value, map, "end")?;
53 let expr: String = must_translate(&mut value, map, "expr")?;
54 let mut result = vec![];
55 let mut namespace = fasteval::StrToF64Namespace::new();
56 for i in index_begin..index_end {
57 namespace.insert("i", i as f64);
58 let data = ez_eval(&expr, &mut namespace)?;
59 result.push(Value::from(data));
60 }
61 Ok(serde_json::from_value(result.into())?)
62 }
63 "g-number" => {
64 let expr: String = must_translate(&mut value, map, "expr")?;
65 let data = ez_eval(&expr, &mut fasteval::EmptyNamespace {})?;
66 Ok(serde_json::from_value(data.into())?)
67 }
68 _ => Err(anyhow!("unknown type `{}`", value_type)),
69 }
70 }
71
72 pub fn unwrap(self, map: &Map) -> Result<T> {
73 let result = match self {
74 Self::Data(data) => data,
75 Self::Index(index) => {
76 let value = map
77 .get(&index)
78 .ok_or_else(|| anyhow!("Invalid index: {}", &index))?;
79 Self::parse_map(map, value.clone())?
80 }
81 };
82 Ok(result)
83 }
84}
85
86impl<'de, T> Deserialize<'de> for DataPack<T>
87where
88 T: DeserializeOwned + Serialize + Debug + Clone,
89{
90 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
91 where
92 D: Deserializer<'de>,
93 {
94 let value = Value::deserialize(deserializer)?;
95 if let Value::String(ref s) = value
96 && let Some(idx) = s.strip_prefix("map.")
97 {
98 return Ok(DataPack::Index(idx.to_string()));
99 }
100 serde_json::from_value::<T>(value)
101 .map(DataPack::Data)
102 .map_err(serde::de::Error::custom)
103 }
104}
105
106impl<T> Serialize for DataPack<T>
107where
108 T: DeserializeOwned + Serialize + Debug + Clone,
109{
110 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
111 where
112 S: Serializer,
113 {
114 match self {
115 Self::Data(data) => data.serialize(serializer),
116 Self::Index(index) => serializer.serialize_str(&format!("map.{index}")),
117 }
118 }
119}
120
121use plotly::color;
122
123#[allow(clippy::enum_variant_names)]
125#[derive(Clone, Debug, Serialize, Deserialize)]
126#[serde(rename_all = "snake_case")]
127pub enum Color {
128 NamedColor(color::NamedColor),
129 RgbColor(color::Rgb),
130 RgbaColor(color::Rgba),
131}
132
133impl color::Color for Color {}