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