tiny_web/sys/
data.rs

1use std::collections::BTreeMap;
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7use crate::StrOrI64;
8
9use super::{mail::MailProvider, response::Redirect, route::Route};
10
11/// Data transferred between controllers, template, markers, database and cache
12///
13/// # Values
14///
15/// * `None` - No data transferred.
16/// * `Usize(usize)` - No data transferred.
17/// * `I16(i16)` - No data transferred.
18/// * `I32(i32)` - No data transferred.
19/// * `I64(i64)` - i64 data.
20/// * `F32(f32)` - f32 data.
21/// * `F64(f64)` - f64 data.
22/// * `Bool(bool)` - bool data.
23/// * `String(String)` - String data.
24/// * `Date(DateTime<Utc>)` - Chrono dateTime.
25/// * `Json(Value)` - Serde json.
26/// * `Vec(Vec<Data>)` - List of `Data`.
27/// * `Map(BTreeMap<i64, Data>)` - Map of `Data`.
28/// * `Route(Route)` - Route data.
29/// * `Redirect(Redirect)` - Redirect data.
30/// * `MailProvider(MailProvider)` - Mail provider data.
31#[derive(Debug, Serialize, Deserialize, Clone)]
32pub enum Data {
33    /// No data transferred.
34    None,
35    /// usize data.
36    Usize(usize),
37    /// i16 data.
38    I16(i16),
39    /// i32 data.
40    I32(i32),
41    /// i64 data.
42    I64(i64),
43    /// f32 data.
44    F32(f32),
45    /// f64 data.
46    F64(f64),
47    /// bool data.
48    Bool(bool),
49    /// String data.
50    String(String),
51    /// DateTime.
52    Date(DateTime<Utc>),
53    /// Json
54    Json(Value),
55    /// List of `Data`.
56    Vec(Vec<Data>),
57    /// Raw data,
58    Raw(Vec<u8>),
59    /// Map of `Data`.
60    Map(BTreeMap<i64, Data>),
61    /// Route data.
62    #[serde(skip_serializing, skip_deserializing)]
63    Route(Route),
64    /// Redirect data.
65    #[serde(skip_serializing, skip_deserializing)]
66    Redirect(Redirect),
67    /// Mail provider data
68    #[serde(skip_serializing, skip_deserializing)]
69    MailProvider(MailProvider),
70}
71
72macro_rules! impl_from_for_data {
73    ($($type:ty => $variant:ident),* $(,)?) => {
74        $(
75            impl From<$type> for Data {
76                fn from(value: $type) -> Self {
77                    Data::$variant(value)
78                }
79            }
80
81            impl From<Data> for $type {
82                fn from(value: Data) -> Self {
83                    if let Data::$variant(inner) = value {
84                        inner
85                    } else {
86                        panic!("Cannot convert {:?} to {}", value, stringify!($type))
87                    }
88                }
89            }
90
91            impl<'a> From<&'a Data> for &'a $type {
92                fn from(value: &'a Data) -> Self {
93                    if let Data::$variant(inner) = value {
94                        inner
95                    } else {
96                        panic!("Cannot convert {:?} to {}", value, stringify!($type))
97                    }
98                }
99            }
100
101        )*
102    };
103}
104
105impl_from_for_data!(
106    usize => Usize,
107    i16 => I16,
108    i32 => I32,
109    i64 => I64,
110    f32 => F32,
111    f64 => F64,
112    bool => Bool,
113    String => String,
114    DateTime<Utc> => Date,
115    Value => Json,
116    Vec<Data> => Vec,
117    Vec<u8> => Raw,
118    BTreeMap<i64, Data> => Map,
119);
120
121impl Data {
122    pub fn get<T>(&self, key: impl StrOrI64) -> Option<&T>
123    where
124        for<'a> &'a T: From<&'a Data>,
125    {
126        match self {
127            Data::Vec(vec) => match usize::try_from(key.to_i64()) {
128                Ok(index) => {
129                    let value = vec.get(index)?;
130                    Some(value.into())
131                }
132                #[cfg(not(debug_assertions))]
133                Err(_) => None,
134                #[cfg(debug_assertions)]
135                Err(e) => panic!("The key must be in the range for type usize. Err: {}", e),
136            },
137            Data::Map(map) => {
138                let value = map.get(&key.to_i64())?;
139                Some(value.into())
140            }
141            #[cfg(not(debug_assertions))]
142            _ => None,
143            #[cfg(debug_assertions)]
144            _ => panic!("Must be Data::Map<Data> or Data::Vec<Data>"),
145        }
146    }
147
148    pub fn take<T>(&mut self, key: impl StrOrI64) -> Option<T>
149    where
150        T: From<Data>,
151    {
152        match self {
153            Data::Vec(vec) => match usize::try_from(key.to_i64()) {
154                Ok(index) => {
155                    let value = vec.remove(index);
156                    Some(value.into())
157                }
158                #[cfg(not(debug_assertions))]
159                Err(_) => None,
160                #[cfg(debug_assertions)]
161                Err(e) => panic!("The key must be in the range for type usize. Err: {}", e),
162            },
163            Data::Map(map) => {
164                let value = map.remove(&key.to_i64())?;
165                Some(value.into())
166            }
167            #[cfg(not(debug_assertions))]
168            _ => None,
169            #[cfg(debug_assertions)]
170            _ => panic!("Must be Data::Map<Data> or Data::Vec<Data>"),
171        }
172    }
173}