dbgbb/
lib.rs

1//! # dbgbb!
2//!
3//! A framework for analyzing debugging data in a Mathematica/Jupyter notebook.
4mod external;
5mod reader;
6mod rename;
7mod sender;
8
9#[doc(hidden)]
10pub use array_object::{ArrayObject, Pack, TryConcat};
11
12#[doc(hidden)]
13pub use bulletin_board_common::*;
14
15#[doc(hidden)]
16pub use reader::read_bulletin;
17pub use rename::Rename;
18pub use sender::Buffer;
19
20#[doc(hidden)]
21pub use sender::SENDER;
22
23use std::collections::HashMap;
24use std::sync::{LazyLock, Mutex};
25
26#[doc(hidden)]
27pub static COUNTER: LazyLock<Mutex<HashMap<String, u64>>> =
28    LazyLock::new(|| Mutex::new(HashMap::new()));
29
30#[doc(hidden)]
31pub static DATA_ACC: LazyLock<Mutex<HashMap<(String, String, String), Vec<ArrayObject>>>> =
32    LazyLock::new(|| Mutex::new(HashMap::new()));
33
34/// Send the debug data to the server.
35///
36/// Usage:
37/// ```
38/// use dbgbb::dbgbb;
39/// for a in 0..3 {
40///     for b in 0..3 {
41///         dbgbb!(a, b);
42///         dbgbb!(every => 3, a, b);
43///         dbgbb!(oneshot => 5, a, b);
44///     }
45/// }
46/// ```
47#[macro_export]
48macro_rules! dbgbb {
49    ($($x:expr),*) => {{
50        let sender = dbgbb::SENDER.lock().unwrap();
51        use dbgbb::{Rename, Pack};
52        let mut objs = vec![];
53        $(
54            let title = match $x.get_name() {
55                Some(name) => name,
56                None => stringify!($x).to_string(),
57            };
58            let tag = format!("{}:{}:{}", file!(), line!(), column!());
59            let obj: dbgbb::ArrayObject = $x.clone().try_into().unwrap();
60            objs.push((title, tag, obj));
61        )*
62        sender.post(objs).unwrap();
63    }};
64    (every => $n:literal, $($x:expr),*) => {{
65        let mut map = dbgbb::COUNTER.lock().unwrap();
66        let count = map.entry(format!("{}:{}:{}", file!(), line!(), column!())).or_insert(0);
67        if *count % $n == 0 {
68            dbgbb!($($x),*);
69        }
70        *count += 1;
71    }};
72    (oneshot => $n:literal, $($x:expr),*) => {{
73        let mut map = dbgbb::COUNTER.lock().unwrap();
74        let count = map.entry(format!("{}:{}:{}", file!(), line!(), column!())).or_insert(0);
75        if *count == $n {
76            dbgbb!($($x),*);
77        }
78        *count += 1;
79    }};
80}
81
82/// Accumulate and send the debug data to the server.
83///
84/// Usage:
85/// ```
86/// use dbgbb::dbgbb_acc;
87/// for a in 0..3 {
88///     for b in 0..3 {
89///         dbgbb_acc!(label => "i", a, b);
90///         dbgbb_acc!(label => "j", every => 2, a, b);
91///     }
92/// }
93/// dbgbb_acc!("i" => post);
94/// dbgbb_acc!("j" => post);
95/// ```
96#[macro_export]
97macro_rules! dbgbb_acc {
98    (label => $label:literal, $($x:expr),*) => {{
99        use dbgbb::Rename;
100        let mut map = dbgbb::DATA_ACC.lock().unwrap();
101        $(
102            let title = match $x.get_name() {
103                Some(name) => name,
104                None => stringify!($x).to_string(),
105            };
106            let tag = format!("{}:{}:{}", file!(), line!(), column!());
107            let entry = map.entry(($label.to_string(), title, tag)).or_insert(vec![]);
108            let obj: dbgbb::ArrayObject = $x.clone().try_into().unwrap();
109            entry.push(obj);
110        )*
111    }};
112    (label => $label:literal, every => $n:literal, $($x:expr),*) => {{
113        let mut map = dbgbb::COUNTER.lock().unwrap();
114        let count = map.entry(format!("{}:{}:{}", file!(), line!(), column!())).or_insert(0);
115        if *count % $n == 0 {
116            dbgbb_acc!(label => $label, $($x),*);
117        }
118        *count += 1;
119    }};
120    ($label:literal => post) => {{
121        use dbgbb::{Pack, TryConcat};
122        let mut objs = vec![];
123        let sender = dbgbb::SENDER.lock().unwrap();
124        let mut map = dbgbb::DATA_ACC.lock().unwrap();
125        let keys: Vec<_> = map.keys()
126            .filter(|key| key.0 == $label)
127            .map(|key|key.clone())
128            .collect();
129        for key in keys {
130            let obj = map.remove(&key).unwrap().try_concat().unwrap();
131            objs.push((key.1, key.2, obj));
132        }
133        sender.post(objs).unwrap();
134    }};
135}
136
137/// Read data from the server.
138///
139/// Usage:
140/// ```
141/// use dbgbb::dbgbb_read;
142/// let vv: Vec<i64> = dbgbb_read!("vv");
143/// let vv2: Vec<i64> = dbgbb_read!("vv", rev => 0);
144/// let a: Vec<u64> = dbgbb_read!("a", "src/lib.rs:9:9");
145/// let b: i64 = dbgbb_read!("b", "src/lib.rs:8:9", rev => 0);
146/// ```
147#[macro_export]
148macro_rules! dbgbb_read {
149    ($title:literal, $tag:literal, rev => $revision:literal) => {{
150        let obj = dbgbb::read_bulletin(
151            $title.to_string(),
152            Some($tag.to_string()),
153            Some($revision as u64),
154        );
155        obj.try_into().unwrap()
156    }};
157    ($title:literal, $tag:literal) => {{
158        let obj = dbgbb::read_bulletin($title.to_string(), Some($tag.to_string()), None);
159        obj.try_into().unwrap()
160    }};
161    ($title:literal, rev => $revision:literal) => {{
162        let obj = dbgbb::read_bulletin($title.to_string(), None, Some($revision as u64));
163        obj.try_into().unwrap()
164    }};
165    ($title:literal) => {{
166        let obj = dbgbb::read_bulletin($title.to_string(), None, None);
167        obj.try_into().unwrap()
168    }};
169}
170
171/// Send each element to the server.
172///
173/// Usage:
174/// ```
175/// use dbgbb::dbgbb_flatten;
176/// let a = vec![vec![1u32, 2], vec![3, 4]];
177/// dbgbb_flatten!(a, depth => 1);
178/// dbgbb_flatten!(a, depth => 2);
179/// ```
180#[macro_export]
181macro_rules! dbgbb_flatten {
182    ($x:expr, depth => 1) => {{
183        let sender = dbgbb::SENDER.lock().unwrap();
184        use dbgbb::{Pack, Rename};
185        let title = match $x.get_name() {
186            Some(name) => name,
187            None => stringify!($x).to_string(),
188        };
189        let tag = format!("{}:{}:{}", file!(), line!(), column!());
190        let mut objs = vec![];
191        for inner in $x.clone().iter() {
192            let obj: dbgbb::ArrayObject = inner.clone().try_into().unwrap();
193            objs.push((title.clone(), tag.clone(), obj));
194        }
195        sender.post(objs).unwrap();
196    }};
197    ($x:expr, depth => 2) => {{
198        let sender = dbgbb::SENDER.lock().unwrap();
199        use dbgbb::{Pack, Rename};
200        let title = match $x.get_name() {
201            Some(name) => name,
202            None => stringify!($x).to_string(),
203        };
204        let tag = format!("{}:{}:{}", file!(), line!(), column!());
205        let mut objs = vec![];
206        for inner0 in $x.clone().iter() {
207            for inner1 in inner0.iter() {
208                let obj: dbgbb::ArrayObject = inner1.clone().try_into().unwrap();
209                objs.push((title.clone(), tag.clone(), obj));
210            }
211        }
212        sender.post(objs).unwrap();
213    }};
214    ($x:expr, depth => 3) => {{
215        let sender = dbgbb::SENDER.lock().unwrap();
216        use dbgbb::{Pack, Rename};
217        let title = match $x.get_name() {
218            Some(name) => name,
219            None => stringify!($x).to_string(),
220        };
221        let tag = format!("{}:{}:{}", file!(), line!(), column!());
222        let mut objs = vec![];
223        for inner0 in $x.clone().iter() {
224            for inner1 in inner0.iter() {
225                for inner2 in inner1.iter() {
226                    let obj: dbgbb::ArrayObject = inner2.clone().try_into().unwrap();
227                    objs.push((title.clone(), tag.clone(), obj));
228                }
229            }
230        }
231        sender.post(objs).unwrap();
232    }};
233    ($x:expr, depth => 4) => {{
234        let sender = dbgbb::SENDER.lock().unwrap();
235        use dbgbb::{Pack, Rename};
236        let title = match $x.get_name() {
237            Some(name) => name,
238            None => stringify!($x).to_string(),
239        };
240        let tag = format!("{}:{}:{}", file!(), line!(), column!());
241        let mut objs = vec![];
242        for inner0 in $x.clone().iter() {
243            for inner1 in inner0.iter() {
244                for inner2 in inner1.iter() {
245                    for inner3 in inner2.iter() {
246                        let obj: dbgbb::ArrayObject = inner3.clone().try_into().unwrap();
247                        objs.push((title.clone(), tag.clone(), obj));
248                    }
249                }
250            }
251        }
252        sender.post(objs).unwrap();
253    }};
254}
255
256/// Create a single array and send it to the server. The lengths of the elements should be the same.
257///
258/// Usage:
259/// ```
260/// use dbgbb::dbgbb_concat;
261/// let a = vec![vec![1u32, 2], vec![3, 4]];
262/// dbgbb_concat!(a, depth => 1);
263/// ```
264#[macro_export]
265macro_rules! dbgbb_concat {
266    ($x:expr, depth => 1) => {{
267        let sender = dbgbb::SENDER.lock().unwrap();
268        use dbgbb::{Pack, Rename, TryConcat};
269        let title = match $x.get_name() {
270            Some(name) => name,
271            None => stringify!($x).to_string(),
272        };
273        let tag = format!("{}:{}:{}", file!(), line!(), column!());
274        let mut objs = vec![];
275        for inner in $x.clone().iter() {
276            let obj: dbgbb::ArrayObject = inner.clone().try_into().unwrap();
277            objs.push(obj);
278        }
279        let cat = objs.try_concat().unwrap();
280        sender.post(vec![(title, tag, cat)]).unwrap();
281    }};
282    ($x:expr, depth => 2) => {{
283        let sender = dbgbb::SENDER.lock().unwrap();
284        use dbgbb::{Pack, Rename, TryConcat};
285        let title = match $x.get_name() {
286            Some(name) => name,
287            None => stringify!($x).to_string(),
288        };
289        let tag = format!("{}:{}:{}", file!(), line!(), column!());
290        let mut objs0 = vec![];
291        for inner0 in $x.clone().iter() {
292            let mut objs1 = vec![];
293            for inner1 in inner0.iter() {
294                let obj: dbgbb::ArrayObject = inner1.clone().try_into().unwrap();
295                objs1.push(obj);
296            }
297            let cat = objs1.try_concat().unwrap();
298            objs0.push(cat);
299        }
300        let cat = objs0.try_concat().unwrap();
301        sender.post(vec![(title, tag, cat)]).unwrap();
302    }};
303    ($x:expr, depth => 3) => {{
304        let sender = dbgbb::SENDER.lock().unwrap();
305        use dbgbb::{Pack, Rename, TryConcat};
306        let title = match $x.get_name() {
307            Some(name) => name,
308            None => stringify!($x).to_string(),
309        };
310        let tag = format!("{}:{}:{}", file!(), line!(), column!());
311        let mut objs0 = vec![];
312        for inner0 in $x.clone().iter() {
313            let mut objs1 = vec![];
314            for inner1 in inner0.iter() {
315                let mut objs2 = vec![];
316                for inner2 in inner1.iter() {
317                    let obj: dbgbb::ArrayObject = inner2.clone().try_into().unwrap();
318                    objs2.push(obj);
319                }
320                let cat = objs2.try_concat().unwrap();
321                objs1.push(cat);
322            }
323            let cat = objs1.try_concat().unwrap();
324            objs0.push(cat);
325        }
326        let cat = objs0.try_concat().unwrap();
327        sender.post(vec![(title, tag, cat)]).unwrap();
328    }};
329    ($x:expr, depth => 4) => {{
330        let sender = dbgbb::SENDER.lock().unwrap();
331        use dbgbb::{Pack, Rename, TryConcat};
332        let title = match $x.get_name() {
333            Some(name) => name,
334            None => stringify!($x).to_string(),
335        };
336        let tag = format!("{}:{}:{}", file!(), line!(), column!());
337        let mut objs0 = vec![];
338        for inner0 in $x.clone().iter() {
339            let mut objs1 = vec![];
340            for inner1 in inner0.iter() {
341                let mut objs2 = vec![];
342                for inner2 in inner1.iter() {
343                    let mut objs3 = vec![];
344                    for inner3 in inner2.iter() {
345                        let obj: dbgbb::ArrayObject = inner3.clone().try_into().unwrap();
346                        objs3.push(obj);
347                    }
348                    let cat = objs3.try_concat().unwrap();
349                    objs2.push(cat);
350                }
351                let cat = objs2.try_concat().unwrap();
352                objs1.push(cat);
353            }
354            let cat = objs1.try_concat().unwrap();
355            objs0.push(cat);
356        }
357        let cat = objs0.try_concat().unwrap();
358        sender.post(vec![(title, tag, cat)]).unwrap();
359    }};
360}
361
362/// Send each element to the server adding the index to the tag.
363///
364/// Usage:
365/// ```
366/// use dbgbb::dbgbb_index;
367/// let a = vec![vec![1u32, 2], vec![3, 4]];
368/// dbgbb_index!(a, depth => 1);
369/// dbgbb_index!(a, depth => 2);
370/// ```
371#[macro_export]
372macro_rules! dbgbb_index {
373    ($x:expr, depth => 1) => {{
374        let sender = dbgbb::SENDER.lock().unwrap();
375        use dbgbb::{Pack, Rename};
376        let title = match $x.get_name() {
377            Some(name) => name,
378            None => stringify!($x).to_string(),
379        };
380        let tag = format!("{}:{}:{}", file!(), line!(), column!());
381        let mut objs = vec![];
382        for (i, inner) in $x.clone().iter().enumerate() {
383            let obj: dbgbb::ArrayObject = inner.clone().try_into().unwrap();
384            objs.push((title.clone(), format!("{tag}:[{i}]"), obj));
385        }
386        sender.post(objs).unwrap();
387    }};
388    ($x:expr, depth => 2) => {{
389        let sender = dbgbb::SENDER.lock().unwrap();
390        use dbgbb::{Pack, Rename};
391        let title = match $x.get_name() {
392            Some(name) => name,
393            None => stringify!($x).to_string(),
394        };
395        let tag = format!("{}:{}:{}", file!(), line!(), column!());
396        let mut objs = vec![];
397        for (i, inner0) in $x.clone().iter().enumerate() {
398            for (j, inner1) in inner0.iter().enumerate() {
399                let obj: dbgbb::ArrayObject = inner1.clone().try_into().unwrap();
400                objs.push((title.clone(), format!("{tag}:[{i},{j}]"), obj));
401            }
402        }
403        sender.post(objs).unwrap();
404    }};
405    ($x:expr, depth => 3) => {{
406        let sender = dbgbb::SENDER.lock().unwrap();
407        use dbgbb::{Pack, Rename};
408        let title = match $x.get_name() {
409            Some(name) => name,
410            None => stringify!($x).to_string(),
411        };
412        let tag = format!("{}:{}:{}", file!(), line!(), column!());
413        let mut objs = vec![];
414        for (i, inner0) in $x.clone().iter().enumerate() {
415            for (j, inner1) in inner0.iter().enumerate() {
416                for (k, inner2) in inner1.iter().enumerate() {
417                    let obj: dbgbb::ArrayObject = inner2.clone().try_into().unwrap();
418                    objs.push((title.clone(), format!("{tag}:[{i},{j},{k}]"), obj));
419                }
420            }
421        }
422        sender.post(objs).unwrap();
423    }};
424    ($x:expr, depth => 4) => {{
425        let sender = dbgbb::SENDER.lock().unwrap();
426        use dbgbb::{Pack, Rename};
427        let title = match $x.get_name() {
428            Some(name) => name,
429            None => stringify!($x).to_string(),
430        };
431        let tag = format!("{}:{}:{}", file!(), line!(), column!());
432        let mut objs = vec![];
433        for (i, inner0) in $x.clone().iter().enumerate() {
434            for (j, inner1) in inner0.iter().enumerate() {
435                for (k, inner2) in inner1.iter().enumerate() {
436                    for (l, inner3) in inner2.iter().enumerate() {
437                        let obj: dbgbb::ArrayObject = inner3.clone().try_into().unwrap();
438                        objs.push((title.clone(), format!("{tag}:[{i},{j},{k},{l}]"), obj));
439                    }
440                }
441            }
442        }
443        sender.post(objs).unwrap();
444    }};
445}