mdbook_plotly/preprocessor/handlers/code_handler/
until.rs1use anyhow::{Result, anyhow, Context};
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())
18 .with_context(|| format!("failed to deserialize field '{}'", name))?
19 .unwrap(map)
20 .with_context(|| format!("failed to unwrap DataPack for field '{}'", name))?;
21 Ok(result)
22}
23
24#[derive(Clone, Debug)]
25pub enum DataPack<T> {
26 Data(T),
27 Index(String),
28}
29
30impl<T> DataPack<T>
31where
32 T: DeserializeOwned + Serialize + Debug + Clone,
33{
34 fn parse_map(map: &Map, mut value: Value) -> Result<T> {
35 if !value.is_object() {
36 let direct_result = serde_json::from_value::<T>(value.clone())
37 .with_context(|| "failed to deserialize non-object value")?;
38 return Ok(direct_result);
39 }
40 let value_type = if let Some(Value::String(s)) = value.get("type") {
41 s.clone()
42 } else {
43 return Err(anyhow!("`type` must be a string"));
44 };
45 use fasteval::ez_eval;
46 match value_type.as_str() {
47 "raw" => {
48 let result = must_translate(&mut value, map, "data")?;
49 Ok(result)
50 }
51 "g-number-list" => {
53 let index_begin: u64 = must_translate(&mut value, map, "begin")?;
54 let index_end: u64 = must_translate(&mut value, map, "end")?;
55 let expr: String = must_translate(&mut value, map, "expr")?;
56 let mut result = vec![];
57 let mut namespace = fasteval::StrToF64Namespace::new();
58 for i in index_begin..index_end {
59 namespace.insert("i", i as f64);
60 let data = ez_eval(&expr, &mut namespace)?;
61 result.push(Value::from(data));
62 }
63 serde_json::from_value(result.into())
64 .with_context(|| format!("failed to deserialize generated list for type '{}'", value_type))
65 }
66 "g-number" => {
67 let expr: String = must_translate(&mut value, map, "expr")?;
68 let data = ez_eval(&expr, &mut fasteval::EmptyNamespace {})?;
69 serde_json::from_value(data.into())
70 .with_context(|| format!("failed to deserialize generated number for type '{}'", value_type))
71 }
72 "g-range" => {
73 let begin: f64 = must_translate(&mut value, map, "begin")?;
74 let end: f64 = must_translate(&mut value, map, "end")?;
75 let step: f64 = if value.get("step").is_some() {
76 must_translate(&mut value, map, "step")?
77 } else {
78 1.0
79 };
80 if step <= 0.0 {
81 return Err(anyhow!("step must be positive"));
82 }
83 let mut result = vec![];
84 let mut current = begin;
85 while current < end {
86 result.push(Value::from(current));
87 current += step;
88 }
89 serde_json::from_value(result.into())
90 .with_context(|| format!("failed to deserialize generated range for type '{}'", value_type))
91 }
92 "g-repeat" => {
93 let val: Value = must_translate(&mut value, map, "value")?;
94 let count: u64 = must_translate(&mut value, map, "count")?;
95 let result = std::iter::repeat_n(val, count as usize).collect::<Vec<_>>();
96 serde_json::from_value(result.into())
97 .with_context(|| format!("failed to deserialize repeated values for type '{}'", value_type))
98 }
99 "g-linear" => {
100 let begin: f64 = must_translate(&mut value, map, "begin")?;
101 let end: f64 = must_translate(&mut value, map, "end")?;
102 let count: u64 = must_translate(&mut value, map, "count")?;
103 if count == 0 {
104 return Err(anyhow!("count must be positive"));
105 }
106 let mut result = Vec::with_capacity(count as usize);
107 if count == 1 {
108 result.push(Value::from(begin));
109 } else {
110 let step = (end - begin) / ((count - 1) as f64);
111 for i in 0..count {
112 let val = begin + (i as f64) * step;
113 result.push(Value::from(val));
114 }
115 }
116 serde_json::from_value(result.into())
117 .with_context(|| format!("failed to deserialize linear spaced values for type '{}'", value_type))
118 }
119 _ => Err(anyhow!("unknown type `{}`", value_type)),
120 }
121 }
122
123 pub fn unwrap(self, map: &Map) -> Result<T> {
124 let result = match self {
125 Self::Data(data) => data,
126 Self::Index(index) => {
127 let value = map.get(&index).ok_or_else(|| {
128 let available_keys: Vec<_> = map.keys().take(5).cloned().collect();
129 anyhow!(
130 "Invalid index: '{}' (available keys: {}{})",
131 &index,
132 available_keys.join(", "),
133 if map.keys().len() > 5 { ", ..." } else { "" }
134 )
135 })?;
136 Self::parse_map(map, value.clone())
137 .with_context(|| format!("failed to parse map entry '{}'", index))?
138 }
139 };
140 Ok(result)
141 }
142}
143
144impl<'de, T> Deserialize<'de> for DataPack<T>
145where
146 T: DeserializeOwned + Serialize + Debug + Clone,
147{
148 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
149 where
150 D: Deserializer<'de>,
151 {
152 let value = Value::deserialize(deserializer)?;
153 if let Value::String(ref s) = value
154 && let Some(idx) = s.strip_prefix("map.")
155 {
156 return Ok(DataPack::Index(idx.to_string()));
157 }
158 serde_json::from_value::<T>(value)
159 .map(DataPack::Data)
160 .map_err(serde::de::Error::custom)
161 }
162}
163
164impl<T> Serialize for DataPack<T>
165where
166 T: DeserializeOwned + Serialize + Debug + Clone,
167{
168 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
169 where
170 S: Serializer,
171 {
172 match self {
173 Self::Data(data) => data.serialize(serializer),
174 Self::Index(index) => serializer.serialize_str(&format!("map.{index}")),
175 }
176 }
177}
178
179use plotly::color;
180
181#[allow(clippy::enum_variant_names)]
183#[derive(Clone, Debug, Serialize, Deserialize)]
184#[serde(rename_all = "snake_case")]
185pub enum Color {
186 NamedColor(color::NamedColor),
187 RgbColor(color::Rgb),
188 RgbaColor(color::Rgba),
189}
190
191impl color::Color for Color {}