chart_js_rs/objects/
helper_objects.rs

1use {
2    crate::{traits::*, utils::FnWithArgs},
3    serde::{
4        de::{self, DeserializeOwned},
5        Deserialize, Serialize,
6    },
7    std::fmt::{Debug, Display},
8};
9
10#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq)]
11#[serde(transparent)]
12pub struct DatasetData(pub serde_json::Value);
13impl DatasetData {
14    pub fn is_empty(&self) -> bool {
15        serde_json::to_value(self)
16            .unwrap()
17            .as_array()
18            .unwrap()
19            .is_empty()
20    }
21
22    pub fn from_single_point_array(iter: impl Iterator<Item = [NumberOrDateString; 1]>) -> Self {
23        DatasetData(serde_json::to_value(iter.collect::<Vec<_>>()).unwrap())
24    }
25
26    pub fn from_minmax_array(iter: impl Iterator<Item = [NumberOrDateString; 2]>) -> Self {
27        DatasetData(serde_json::to_value(iter.collect::<Vec<_>>()).unwrap())
28    }
29}
30impl PartialOrd for DatasetData {
31    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
32        Some(self.cmp(other))
33    }
34}
35impl Ord for DatasetData {
36    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
37        self.0.to_string().cmp(&other.0.to_string())
38    }
39}
40
41#[derive(Debug, Clone, Deserialize, Serialize, Default)]
42pub struct NoDatasets {}
43impl DatasetTrait for NoDatasets {
44    fn labels(self) -> Vec<NumberOrDateString> {
45        Vec::new()
46    }
47}
48#[derive(Debug, Deserialize, Serialize, Default)]
49pub struct NoAnnotations {}
50impl Annotation for NoAnnotations {}
51
52#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
53pub struct Dataset<D: DatasetTrait> {
54    datasets: D,
55    labels: Option<Vec<NumberOrDateString>>,
56}
57impl<D: DatasetTrait> Dataset<D> {
58    pub fn new() -> Self {
59        Self {
60            datasets: D::default(),
61            labels: None,
62        }
63    }
64    pub fn get_datasets(&mut self) -> &mut D {
65        &mut self.datasets
66    }
67    pub fn datasets(mut self, datasets: impl Into<D>) -> Self {
68        self.datasets = datasets.into();
69        let labels = self.datasets.clone();
70        self.labels(labels.labels())
71    }
72    pub fn get_labels(&mut self) -> &mut Option<Vec<NumberOrDateString>> {
73        &mut self.labels
74    }
75    pub fn labels<T: Into<NumberOrDateString>>(
76        mut self,
77        labels: impl IntoIterator<Item = T>,
78    ) -> Self {
79        self.labels = Some(labels.into_iter().map(Into::into).collect());
80        self
81    }
82}
83#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
84#[serde(untagged)]
85pub enum Any {
86    String(String),
87    Int(isize),
88    Bool(bool),
89    Vec(Vec<()>),
90}
91impl From<bool> for Any {
92    fn from(value: bool) -> Self {
93        Self::Bool(value)
94    }
95}
96impl From<String> for Any {
97    fn from(value: String) -> Self {
98        Self::String(value)
99    }
100}
101impl Any {
102    pub fn is_empty(&self) -> bool {
103        match self {
104            Any::String(s) => s.is_empty(),
105            Any::Int(_i) => false,
106            Any::Bool(_b) => false,
107            Any::Vec(v) => v.is_empty(),
108        }
109    }
110}
111impl Display for Any {
112    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113        match self {
114            Any::String(s) => write!(f, "{s}"),
115            Any::Bool(b) => write!(f, "{b}"),
116            Any::Int(i) => write!(f, "{i}"),
117            Any::Vec(_) => write!(f, ""),
118        }
119    }
120}
121#[derive(Debug, Clone, Default, PartialEq, Eq)]
122pub struct NumberOrDateString(String);
123impl From<NumberString> for NumberOrDateString {
124    fn from(value: NumberString) -> Self {
125        value.0.into()
126    }
127}
128impl NumberOrDateString {
129    pub fn is_empty(&self) -> bool {
130        self.0.is_empty()
131    }
132}
133impl PartialOrd for NumberOrDateString {
134    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
135        Some(self.cmp(other))
136    }
137}
138impl Ord for NumberOrDateString {
139    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
140        if let Some((s, o)) = self
141            .0
142            .parse::<rust_decimal::Decimal>()
143            .ok()
144            .zip(other.0.parse::<rust_decimal::Decimal>().ok())
145        {
146            s.cmp(&o)
147        } else {
148            self.0.cmp(&other.0)
149        }
150    }
151}
152impl<T: Display> From<T> for NumberOrDateString {
153    fn from(s: T) -> Self {
154        Self(s.to_string())
155    }
156}
157#[allow(unknown_lints, clippy::to_string_trait_impl)]
158impl ToString for NumberOrDateString {
159    fn to_string(&self) -> String {
160        self.0.to_string()
161    }
162}
163impl Serialize for NumberOrDateString {
164    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
165    where
166        S: serde::Serializer,
167    {
168        let fnum: Result<f64, _> = self.0.parse();
169        let inum: Result<i64, _> = self.0.parse();
170        match (fnum, inum) {
171            (Ok(_), Ok(inum)) => serializer.serialize_i64(inum),
172            (Ok(fnum), _) => serializer.serialize_f64(fnum),
173            _ => serializer.serialize_str(&self.0),
174        }
175    }
176}
177impl<'de> Deserialize<'de> for NumberOrDateString {
178    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
179    where
180        D: serde::Deserializer<'de>,
181    {
182        Any::deserialize(deserializer).map(|soi| Self(soi.to_string()))
183    }
184}
185
186#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
187pub struct BoolString(String);
188impl BoolString {
189    pub fn opt_true() -> Option<BoolString> {
190        BoolString("true".into()).into()
191    }
192    pub fn opt_false() -> Option<BoolString> {
193        BoolString("false".into()).into()
194    }
195    pub fn _true() -> BoolString {
196        BoolString("true".into())
197    }
198    pub fn _false() -> BoolString {
199        BoolString("false".into())
200    }
201    pub fn is_empty(&self) -> bool {
202        self.0.is_empty()
203    }
204}
205impl<T: Display> From<T> for BoolString {
206    fn from(s: T) -> Self {
207        Self(s.to_string())
208    }
209}
210impl Serialize for BoolString {
211    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
212    where
213        S: serde::Serializer,
214    {
215        let bool_: Result<bool, _> = self.0.parse();
216        let any: Result<String, _> = self.0.parse();
217        match (bool_, any) {
218            (Ok(bool_), _) => serializer.serialize_bool(bool_),
219            (_, Ok(any)) => serializer.serialize_str(&any),
220            _ => unreachable!(),
221        }
222    }
223}
224impl<'de> Deserialize<'de> for BoolString {
225    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
226    where
227        D: serde::Deserializer<'de>,
228    {
229        Any::deserialize(deserializer).map(|soi| Self(soi.to_string()))
230    }
231}
232
233#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
234#[serde(untagged)]
235pub enum FnWithArgsOrAny<const N: usize> {
236    Any(Any),
237    FnWithArgs(FnWithArgs<N>),
238}
239impl<const N: usize> FnWithArgsOrAny<N> {
240    pub fn is_empty(&self) -> bool {
241        match self {
242            FnWithArgsOrAny::Any(a) => a.is_empty(),
243            FnWithArgsOrAny::FnWithArgs(fnwa) => fnwa.is_empty(),
244        }
245    }
246}
247impl<const N: usize> Default for FnWithArgsOrAny<N> {
248    fn default() -> Self {
249        FnWithArgsOrAny::Any(Any::from(false))
250    }
251}
252impl<const N: usize, T: Display> From<T> for FnWithArgsOrAny<N> {
253    fn from(s: T) -> Self {
254        Self::Any(s.to_string().into())
255    }
256}
257impl<const N: usize> From<FnWithArgs<N>> for FnWithArgsOrAny<N> {
258    fn from(value: FnWithArgs<N>) -> Self {
259        Self::FnWithArgs(value)
260    }
261}
262
263#[derive(Debug, Clone, Default, PartialEq, Eq)]
264pub struct NumberString(String);
265impl From<NumberOrDateString> for NumberString {
266    fn from(value: NumberOrDateString) -> Self {
267        value.0.into()
268    }
269}
270impl NumberString {
271    pub fn is_empty(&self) -> bool {
272        self.0.is_empty()
273    }
274}
275impl PartialOrd for NumberString {
276    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
277        Some(self.cmp(other))
278    }
279}
280impl Ord for NumberString {
281    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
282        if let Some((s, o)) = self
283            .0
284            .parse::<rust_decimal::Decimal>()
285            .ok()
286            .zip(other.0.parse::<rust_decimal::Decimal>().ok())
287        {
288            s.cmp(&o)
289        } else {
290            self.0.cmp(&other.0)
291        }
292    }
293}
294impl<T: Display> From<T> for NumberString {
295    fn from(s: T) -> Self {
296        Self(s.to_string())
297    }
298}
299#[allow(clippy::to_string_trait_impl)]
300impl ToString for NumberString {
301    fn to_string(&self) -> String {
302        self.0.to_string()
303    }
304}
305impl Serialize for NumberString {
306    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
307    where
308        S: serde::Serializer,
309    {
310        let fnum: Result<f64, _> = self.0.parse();
311        let inum: Result<i64, _> = self.0.parse();
312        match (fnum, inum) {
313            (Ok(_), Ok(inum)) => serializer.serialize_i64(inum),
314            (Ok(fnum), _) => serializer.serialize_f64(fnum),
315            _ => serializer.serialize_str(&self.0),
316        }
317    }
318}
319impl<'de> Deserialize<'de> for NumberString {
320    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
321    where
322        D: serde::Deserializer<'de>,
323    {
324        Any::deserialize(deserializer).map(|soi| Self(soi.to_string()))
325    }
326}
327
328#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)]
329#[serde(untagged)]
330pub enum NumberStringOrT<T: Serialize + DeserializeOwned> {
331    T(T),
332    NumberString(NumberString),
333}
334impl<'de, T: Serialize + DeserializeOwned> Deserialize<'de> for NumberStringOrT<T> {
335    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
336    where
337        D: de::Deserializer<'de>,
338    {
339        // thanks serde :|
340        let value = serde::__private::de::Content::deserialize(deserializer)?;
341        let deserializer = serde::__private::de::ContentRefDeserializer::<D::Error>::new(&value);
342
343        match NumberString::deserialize(deserializer) {
344            Ok(ns) => Ok(Self::NumberString(ns)),
345            Err(_) => T::deserialize(deserializer).map(Self::T),
346        }
347    }
348}
349impl<T: Serialize + DeserializeOwned> NumberStringOrT<T> {
350    pub fn is_empty(&self) -> bool {
351        match self {
352            NumberStringOrT::T(_t) => false,
353            NumberStringOrT::NumberString(ns) => ns.is_empty(),
354        }
355    }
356}
357
358impl<T: Serialize + ChartJsRsObject, U: Serialize + DeserializeOwned> From<T>
359    for NumberStringOrT<U>
360{
361    fn from(value: T) -> Self {
362        serde_json::from_value(serde_json::to_value(value).unwrap()).unwrap()
363    }
364}