Skip to main content

quo_rust/
lib.rs

1mod types;
2
3use crate::types::{QuoPayload, QuoPayloadLanguage, QuoPayloadMeta, QuoPayloadVariable};
4use std::fmt::Debug;
5use std::time::{SystemTime, UNIX_EPOCH};
6use ureq::config::Config;
7
8/// This fn creates a QuoPayload. You might or might not question why this is a separate function: for testing.
9///
10/// # Example
11///
12/// let mut big_number: i128;
13///
14/// big_number = 170141183460469231731687303715884105727;
15///
16/// quo_create_payload(big_number, "big_number", line!(), file!());
17///
18#[cfg(debug_assertions)]
19#[doc(hidden)]
20fn quo_create_payload<T: Debug>(
21    value: T,
22    name: &str,
23    line: u32,
24    file: &str,
25    is_mutable: bool,
26) -> QuoPayload {
27    let var_type = std::any::type_name_of_val(&value).to_string();
28    let name = name;
29    let value = format!("{:?}", value);
30    let line = line;
31    let file = file;
32    let package_name = option_env!("CARGO_PKG_NAME").unwrap_or("Rust project");
33
34    let since_the_epoch = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
35
36    QuoPayload {
37        language: QuoPayloadLanguage::Rust,
38        meta: QuoPayloadMeta {
39            id: 0,
40            uid: since_the_epoch.as_nanos().to_string(),
41            origin: package_name.to_string(),
42            sender_origin: format!("{}:{}", file, line),
43            time_epoch_ms: since_the_epoch.as_millis() as i64,
44            variable: QuoPayloadVariable {
45                var_type: var_type.clone(),
46                name: name.to_string(),
47                value: value.clone(),
48                mutable: is_mutable,
49                // @TODO Correctly detect const.
50                is_constant: name == name.to_uppercase(),
51            },
52        },
53    }
54}
55
56/// This fn sends the provided variable to Quo.
57///
58/// # Example
59///
60/// let mut big_number: i128;
61///
62/// big_number = 170141183460469231731687303715884105727;
63///
64/// quo(big_number, "big_number", line!(), file!());
65///
66#[cfg(debug_assertions)]
67#[doc(hidden)]
68fn quo<T: Debug>(value: T, name: &str, line: u32, file: &str, is_mutable: bool) -> () {
69    #[cfg(debug_assertions)]
70    {
71        let env_host = option_env!("QUO_HOST").unwrap_or("http://127.0.0.1");
72        let env_port = option_env!("QUO_PORT").unwrap_or("7312");
73
74        let body = quo_create_payload(value, name, line, file, is_mutable);
75
76        let send_fn = move || {
77            let quo_server = format!("{}:{}", env_host, env_port);
78
79            let config = Config::builder()
80                .user_agent("Quo-Rust")
81                .build();
82
83            let agent = config.new_agent();
84
85            let _ = match agent.post(quo_server).send_json(body) {
86                Ok(_response) => {}
87                Err(ureq::Error::StatusCode(code)) => {
88                    eprintln!("[Quo] HTTP {} - is Quo running?", code)
89                }
90                Err(e) => {
91                    eprintln!("[Quo] error \"{}\" - is Quo running?", e.to_string())
92                }
93            };
94        };
95
96        #[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
97        {
98            send_fn();
99        }
100
101        #[cfg(not(all(target_arch = "wasm32", not(target_feature = "atomics"))))]
102        {
103            std::thread::spawn(send_fn);
104        }
105    }
106}
107
108#[cfg(debug_assertions)]
109#[doc(hidden)]
110pub fn __private_quo<T: Debug>(
111    value: T,
112    name: &str,
113    line: u32,
114    file: &str,
115    is_mutable: bool,
116) -> () {
117    quo(value, name, line, file, is_mutable)
118}
119
120/// This macro sends the provided variable to Quo using the quo() fn.
121///
122/// # Example
123///
124/// let mut big_number: i128;
125///
126/// big_number = 170141183460469231731687303715884105727;
127///
128/// quo!(big_number);
129///
130#[macro_export]
131macro_rules! quo {
132    ($( mut $var:ident ),*) => {{
133        #[cfg(debug_assertions)]
134        $(
135            $crate::__private_quo(&$var, stringify!($var), line!(), file!(), true);
136        )*
137    }};
138    ($( $var:ident ),*) => {{
139        #[cfg(debug_assertions)]
140        $(
141            $crate::__private_quo(&$var, stringify!($var), line!(), file!(), false);
142        )*
143    }};
144}
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149
150    #[test]
151    fn fn_test() {
152        let fn_test_var = 1234;
153
154        let payload = quo_create_payload(&fn_test_var, "fn_test_var", line!(), file!(), false);
155        assert_eq!(payload.meta.variable.name, "fn_test_var");
156        assert_eq!(payload.meta.variable.value, "1234");
157        assert_eq!(payload.meta.variable.var_type, "&i32");
158        assert!(!payload.meta.variable.mutable);
159        assert!(!payload.meta.variable.is_constant);
160    }
161
162    #[test]
163    fn macro_const_test() {
164        const VAR_I32: i32 = -1234;
165
166        quo!(VAR_I32, VAR_I32, VAR_I32);
167
168        let payload = quo_create_payload(&VAR_I32, "VAR_I32", line!(), file!(), false);
169        assert_eq!(payload.meta.variable.name, "VAR_I32");
170        assert_eq!(payload.meta.variable.value, "-1234");
171        assert_eq!(payload.meta.variable.var_type, "&i32");
172        assert!(!payload.meta.variable.mutable);
173        assert!(payload.meta.variable.is_constant);
174    }
175
176    #[test]
177    fn macro_i32_test() {
178        let var_i32: i32 = -1234;
179
180        let payload = quo_create_payload(&var_i32, "var_i32", line!(), file!(), false);
181        assert_eq!(payload.meta.variable.name, "var_i32");
182        assert_eq!(payload.meta.variable.value, "-1234");
183        assert_eq!(payload.meta.variable.var_type, "&i32");
184        assert!(!payload.meta.variable.mutable);
185        assert!(!payload.meta.variable.is_constant);
186    }
187
188    #[test]
189    fn macro_u32_test() {
190        let var_u32: u32 = 1234;
191
192        let payload = quo_create_payload(&var_u32, "var_u32", line!(), file!(), false);
193        assert_eq!(payload.meta.variable.name, "var_u32");
194        assert_eq!(payload.meta.variable.value, "1234");
195        assert_eq!(payload.meta.variable.var_type, "&u32");
196        assert!(!payload.meta.variable.mutable);
197        assert!(!payload.meta.variable.is_constant);
198    }
199
200    #[test]
201    fn macro_string_test() {
202        let var_string: &str = "string";
203
204        let payload = quo_create_payload(&var_string, "var_string", line!(), file!(), false);
205        assert_eq!(payload.meta.variable.name, "var_string");
206        assert_eq!(payload.meta.variable.value, "\"string\"");
207        assert_eq!(payload.meta.variable.var_type, "&&str");
208        assert!(!payload.meta.variable.mutable);
209        assert!(!payload.meta.variable.is_constant);
210    }
211
212    #[test]
213    fn macro_bool_test() {
214        let var_bool: bool = true;
215
216        let payload = quo_create_payload(&var_bool, "var_bool", line!(), file!(), false);
217        assert_eq!(payload.meta.variable.name, "var_bool");
218        assert_eq!(payload.meta.variable.value, "true");
219        assert_eq!(payload.meta.variable.var_type, "&bool");
220        assert!(!payload.meta.variable.mutable);
221        assert!(!payload.meta.variable.is_constant);
222    }
223
224    #[test]
225    fn macro_tupl_test() {
226        let var_tuple: (bool, String, String, String, u32) = (
227            false,
228            String::from("hope"),
229            String::from("this"),
230            String::from("works"),
231            23423,
232        );
233
234        let payload = quo_create_payload(&var_tuple, "var_tuple", line!(), file!(), false);
235        assert_eq!(payload.meta.variable.name, "var_tuple");
236        assert_eq!(
237            payload.meta.variable.value,
238            "(false, \"hope\", \"this\", \"works\", 23423)"
239        );
240        assert_eq!(
241            payload.meta.variable.var_type,
242            "&(bool, alloc::string::String, alloc::string::String, alloc::string::String, u32)"
243        );
244        assert!(!payload.meta.variable.mutable);
245        assert!(!payload.meta.variable.is_constant);
246    }
247
248    #[test]
249    fn macro_arr_test() {
250        let var_array: [String; 3] = [
251            String::from("hope"),
252            String::from("this"),
253            String::from("works"),
254        ];
255
256        let payload = quo_create_payload(&var_array, "var_array", line!(), file!(), false);
257        assert_eq!(payload.meta.variable.name, "var_array");
258        assert_eq!(
259            payload.meta.variable.value,
260            "[\"hope\", \"this\", \"works\"]"
261        );
262        assert_eq!(
263            payload.meta.variable.var_type,
264            "&[alloc::string::String; 3]"
265        );
266        assert!(!payload.meta.variable.mutable);
267        assert!(!payload.meta.variable.is_constant);
268    }
269
270    #[test]
271    fn macro_vec_test() {
272        let var_vector: Vec<String> = vec![
273            String::from("hope"),
274            String::from("this"),
275            String::from("works"),
276        ];
277
278        let payload = quo_create_payload(&var_vector, "var_vector", line!(), file!(), false);
279        assert_eq!(payload.meta.variable.name, "var_vector");
280        assert_eq!(
281            payload.meta.variable.value,
282            "[\"hope\", \"this\", \"works\"]"
283        );
284        assert_eq!(
285            payload.meta.variable.var_type,
286            "&alloc::vec::Vec<alloc::string::String>"
287        );
288        assert!(!payload.meta.variable.mutable);
289        assert!(!payload.meta.variable.is_constant);
290    }
291
292    #[test]
293    fn macro_mut_test() {
294        let mut var_mut = 1;
295        let payload1 = quo_create_payload(&var_mut, "var_mut", line!(), file!(), true);
296        assert_eq!(payload1.meta.variable.name, "var_mut");
297        assert_eq!(payload1.meta.variable.value, "1");
298        assert_eq!(payload1.meta.variable.var_type, "&i32");
299        assert!(payload1.meta.variable.mutable);
300        assert!(!payload1.meta.variable.is_constant);
301
302        var_mut = 2;
303        let payload2 = quo_create_payload(&var_mut, "var_mut", line!(), file!(), true);
304        assert_eq!(payload2.meta.variable.name, "var_mut");
305        assert_eq!(payload2.meta.variable.value, "2");
306        assert_eq!(payload2.meta.variable.var_type, "&i32");
307        assert!(payload2.meta.variable.mutable);
308        assert!(!payload2.meta.variable.is_constant);
309    }
310
311    #[test]
312    fn macro_immut_test() {
313        let var_immut = 1;
314        let payload = quo_create_payload(&var_immut, "var_immut", line!(), file!(), false);
315        assert_eq!(payload.meta.variable.name, "var_immut");
316        assert_eq!(payload.meta.variable.value, "1");
317        assert_eq!(payload.meta.variable.var_type, "&i32");
318        assert!(!payload.meta.variable.mutable);
319        assert!(!payload.meta.variable.is_constant);
320    }
321
322    #[test]
323    #[allow(dead_code)]
324    fn complex_type_test() {
325        #[derive(Debug)]
326        struct Complex {
327            a: i32,
328            b: String,
329            c: Vec<i32>,
330            d: bool,
331        }
332
333        let var_complex = Complex {
334            a: 1,
335            b: String::from("complex"),
336            c: vec![1, 2, 3],
337            d: true,
338        };
339
340        let payload = quo_create_payload(&var_complex, "var_complex", line!(), file!(), false);
341        assert_eq!(payload.meta.variable.name, "var_complex");
342        assert_eq!(
343            payload.meta.variable.var_type,
344            "&quo_rust::tests::complex_type_test::Complex"
345        );
346        assert!(payload.meta.variable.value.contains("a: 1"));
347        assert!(payload.meta.variable.value.contains("complex"));
348        assert!(!payload.meta.variable.mutable);
349        assert!(!payload.meta.variable.is_constant);
350    }
351
352    #[test]
353    #[allow(dead_code)]
354    fn large_var_test() {
355        #[derive(Debug)]
356        struct Large {
357            a: i32,
358            b: i32,
359            c: i32,
360            d: i32,
361            e: i32,
362            f: i32,
363            g: i32,
364            h: i32,
365            i: i32,
366            j: i32,
367        }
368
369        let var_large = Large {
370            a: 1,
371            b: 2,
372            c: 3,
373            d: 4,
374            e: 5,
375            f: 6,
376            g: 7,
377            h: 8,
378            i: 9,
379            j: 10,
380        };
381
382        let payload = quo_create_payload(&var_large, "var_large", line!(), file!(), false);
383        assert_eq!(payload.meta.variable.name, "var_large");
384        assert_eq!(
385            payload.meta.variable.var_type,
386            "&quo_rust::tests::large_var_test::Large"
387        );
388        assert!(payload.meta.variable.value.contains("j: 10"));
389        assert!(!payload.meta.variable.mutable);
390        assert!(!payload.meta.variable.is_constant);
391    }
392
393    #[test]
394    fn macro_mut_explicit_test() {
395        let mut var_mut = 1;
396        quo!(mut var_mut);
397
398        let payload = quo_create_payload(&var_mut, "var_mut", line!(), file!(), true);
399        assert!(payload.meta.variable.mutable);
400
401        var_mut = 2;
402        quo!(var_mut);
403    }
404}