bulletin_board_mathematica/
lib.rs

1use std::time::Duration;
2use bulletin_board_client::{
3    adaptor::Pair, adaptor::VecShape, adaptor::VecVecShape, ArrayObject, DataType,
4};
5use wolfram_library_link::{self as wll, generate_loader, wstp};
6
7generate_loader!(load_dbgbb);
8
9#[wll::export(wstp)]
10fn set_addr(link: &mut wstp::Link) {
11    assert_eq!(link.test_head("System`List").unwrap(), 1);
12    let addr = link.get_string().unwrap();
13    bulletin_board_client::set_addr(&addr);
14    link.put_str("Server address updated").unwrap();
15}
16
17#[wll::export(wstp)]
18fn set_timeout(link: &mut wstp::Link) {
19    let argc = link.test_head("System`List").unwrap();
20    match argc {
21        0 => bulletin_board_client::set_timeout(None),
22        1 => {
23            let timeout = link.get_i64().unwrap();
24            bulletin_board_client::set_timeout(Some(Duration::from_millis(
25                timeout.try_into().unwrap(),
26            )));
27        }
28        _ => panic!(),
29    };
30
31    link.put_str("Server address updated").unwrap();
32}
33
34#[wll::export(wstp)]
35fn post_integer(link: &mut wstp::Link) {
36    assert_eq!(link.test_head("System`List").unwrap(), 3);
37    let title = link.get_string().unwrap();
38    let tag = link.get_string().unwrap();
39    let val = link.get_i64().unwrap();
40    let obj = val.try_into().unwrap();
41    bulletin_board_client::post(&title, &tag, obj).unwrap();
42    link.put_str("Sent").unwrap();
43}
44
45#[wll::export(wstp)]
46fn post_real(link: &mut wstp::Link) {
47    assert_eq!(link.test_head("System`List").unwrap(), 3);
48    let title = link.get_string().unwrap();
49    let tag = link.get_string().unwrap();
50    let val = link.get_f64().unwrap();
51    let obj = val.try_into().unwrap();
52    bulletin_board_client::post(&title, &tag, obj).unwrap();
53    link.put_str("Sent").unwrap();
54}
55
56#[wll::export(wstp)]
57fn post_complex(link: &mut wstp::Link) {
58    assert_eq!(link.test_head("System`List").unwrap(), 4);
59    let title = link.get_string().unwrap();
60    let tag = link.get_string().unwrap();
61    let re = link.get_f64().unwrap();
62    let im = link.get_f64().unwrap();
63    let obj = Pair(re, im).try_into().unwrap();
64    bulletin_board_client::post(&title, &tag, obj).unwrap();
65    link.put_str("Sent").unwrap();
66}
67
68#[wll::export(wstp)]
69fn post_string(link: &mut wstp::Link) {
70    assert_eq!(link.test_head("System`List").unwrap(), 3);
71    let title = link.get_string().unwrap();
72    let tag = link.get_string().unwrap();
73    let val = link.get_string().unwrap();
74    let obj = val.try_into().unwrap();
75    bulletin_board_client::post(&title, &tag, obj).unwrap();
76    link.put_str("Sent").unwrap();
77}
78
79#[wll::export(wstp)]
80fn post_integer_array(link: &mut wstp::Link) {
81    assert_eq!(link.test_head("System`List").unwrap(), 3);
82    {
83        let title = link.get_string().unwrap();
84        let tag = link.get_string().unwrap();
85        let arr = link.get_i64_array().unwrap();
86        let shape = arr.dimensions().into_iter().map(|&x| x as u64).collect();
87        let data = arr.data().into_iter().copied().collect();
88        let obj = VecShape(data, shape).try_into().unwrap();
89        bulletin_board_client::post(&title, &tag, obj).unwrap();
90    }
91    link.put_str("Sent").unwrap();
92}
93
94#[wll::export(wstp)]
95fn post_real_array(link: &mut wstp::Link) {
96    assert_eq!(link.test_head("System`List").unwrap(), 3);
97    {
98        let title = link.get_string().unwrap();
99        let tag = link.get_string().unwrap();
100        let arr = link.get_f64_array().unwrap();
101        let shape = arr.dimensions().into_iter().map(|&x| x as u64).collect();
102        let data = arr.data().into_iter().copied().collect();
103        let obj = VecShape(data, shape).try_into().unwrap();
104        bulletin_board_client::post(&title, &tag, obj).unwrap();
105    }
106    link.put_str("Sent").unwrap();
107}
108
109#[wll::export(wstp)]
110fn post_complex_array(link: &mut wstp::Link) {
111    assert_eq!(link.test_head("System`List").unwrap(), 4);
112    {
113        let title = link.get_string().unwrap();
114        let tag = link.get_string().unwrap();
115        let (re, shape) = {
116            let re_arr = link.get_f64_array().unwrap();
117            let re = re_arr.data().into_iter().copied().collect();
118            let shape = re_arr.dimensions().into_iter().map(|&x| x as u64).collect();
119            (re, shape)
120        };
121        let im = {
122            let im_arr = link.get_f64_array().unwrap();
123            im_arr.data().into_iter().copied().collect()
124        };
125        let obj = VecVecShape(re, im, shape).try_into().unwrap();
126        bulletin_board_client::post(&title, &tag, obj).unwrap();
127    }
128    link.put_str("Sent").unwrap();
129}
130
131#[wll::export(wstp)]
132fn post_string_array(link: &mut wstp::Link) {
133    assert_eq!(link.test_head("System`List").unwrap(), 4);
134    {
135        let title = link.get_string().unwrap();
136        let tag = link.get_string().unwrap();
137        let len = link.test_head("System`List").unwrap();
138        let mut data = vec![];
139        for _ in 0..len {
140            let text = link.get_string().unwrap();
141            data.push(text);
142        }
143        let shape = link
144            .get_i64_array()
145            .unwrap()
146            .data()
147            .into_iter()
148            .map(|&x| x.try_into().unwrap())
149            .collect();
150        let obj = VecShape(data, shape).try_into().unwrap();
151        bulletin_board_client::post(&title, &tag, obj).unwrap();
152    }
153    link.put_str("Sent").unwrap();
154}
155
156#[wll::export(wstp)]
157fn read(link: &mut wstp::Link) {
158    let argc = link.test_head("System`List").unwrap();
159    let (title, tag, revisions) = match argc {
160        1 => (link.get_string().unwrap(), None, vec![]),
161        2 => {
162            let title = link.get_string().unwrap();
163            if link.get_type().unwrap() == wstp::TokenType::String {
164                (title, Some(link.get_string().unwrap()), vec![])
165            } else {
166                if link.get_type().unwrap() == wstp::TokenType::Integer {
167                    (
168                        title,
169                        None,
170                        vec![link.get_i64().unwrap().try_into().unwrap()],
171                    )
172                } else {
173                    (
174                        title,
175                        None,
176                        link.get_i64_array()
177                            .unwrap()
178                            .data()
179                            .into_iter()
180                            .map(|&x| x.try_into().unwrap())
181                            .collect(),
182                    )
183                }
184            }
185        }
186        3 => {
187            let title = link.get_string().unwrap();
188            let tag = Some(link.get_string().unwrap());
189            if link.get_type().unwrap() == wstp::TokenType::Integer {
190                (
191                    title,
192                    tag,
193                    vec![link.get_i64().unwrap().try_into().unwrap()],
194                )
195            } else {
196                (
197                    title,
198                    tag,
199                    link.get_i64_array()
200                        .unwrap()
201                        .data()
202                        .into_iter()
203                        .map(|&x| x.try_into().unwrap())
204                        .collect(),
205                )
206            }
207        }
208        _ => panic!(),
209    };
210    let list = bulletin_board_client::read(&title, tag.as_deref(), revisions).unwrap();
211    if list.len() > 1 {
212        link.put_function("System`List", list.len()).unwrap();
213    }
214    for data in list {
215        put_data(link, data);
216    }
217}
218
219fn put_data(link: &mut wstp::Link, data: ArrayObject) {
220    match data.datatype() {
221        DataType::UnsignedInteger | DataType::SignedInteger => {
222            if data.dimension() == 0 {
223                let val = data.try_into().unwrap();
224                link.put_i64(val).unwrap();
225            } else {
226                let VecShape(val, shape) = data.try_into().unwrap();
227                let shape: Vec<usize> = shape.into_iter().map(|x| x.try_into().unwrap()).collect();
228                link.put_i64_array(&val, &shape).unwrap();
229            }
230        }
231        DataType::Real => {
232            if data.dimension() == 0 {
233                let val = data.try_into().unwrap();
234                link.put_f64(val).unwrap();
235            } else {
236                let VecShape(val, shape) = data.try_into().unwrap();
237                let shape: Vec<usize> = shape.into_iter().map(|x| x.try_into().unwrap()).collect();
238                link.put_f64_array(&val, &shape).unwrap();
239            }
240        }
241        DataType::Complex => {
242            if data.dimension() == 0 {
243                let Pair(re, im) = data.try_into().unwrap();
244                link.put_function("System`Complex", 2).unwrap();
245                link.put_f64(re).unwrap();
246                link.put_f64(im).unwrap();
247            } else {
248                let VecVecShape(re, im, shape) = data.try_into().unwrap();
249                link.put_function("System`ArrayReshape", 2).unwrap();
250                link.put_function("System`List", re.len()).unwrap();
251                for (re, im) in re.into_iter().zip(im.into_iter()) {
252                    link.put_function("System`Complex", 2).unwrap();
253                    link.put_f64(re).unwrap();
254                    link.put_f64(im).unwrap();
255                }
256                link.put_function("System`List", shape.len()).unwrap();
257                for d in shape {
258                    link.put_i64(d.try_into().unwrap()).unwrap();
259                }
260            }
261        }
262        DataType::String => {
263            if data.dimension() == 0 {
264                let val: String = data.try_into().unwrap();
265                link.put_str(&val).unwrap();
266            } else {
267                let VecShape::<String>(val, shape) = data.try_into().unwrap();
268                link.put_function("System`ArrayReshape", 2).unwrap();
269                link.put_function("System`List", val.len()).unwrap();
270                for s in val {
271                    link.put_str(&s).unwrap();
272                }
273                link.put_function("System`List", shape.len()).unwrap();
274                for d in shape {
275                    link.put_i64(d.try_into().unwrap()).unwrap();
276                }
277            }
278        }
279    }
280}
281
282#[wll::export(wstp)]
283fn relabel(link: &mut wstp::Link) {
284    assert_eq!(link.test_head("System`List").unwrap(), 4);
285    let title_from = link.get_string().unwrap();
286    let tag_from = link.get_string().unwrap();
287    let title_to = link.get_string().unwrap();
288    let tag_to = link.get_string().unwrap();
289    let tag_from = match tag_from.as_str() {
290        "" => None,
291        _ => Some(tag_from.as_str()),
292    };
293    let title_to = match title_to.as_str() {
294        "" => None,
295        _ => Some(title_to.as_str()),
296    };
297    let tag_to = match tag_to.as_str() {
298        "" => None,
299        _ => Some(tag_to.as_str()),
300    };
301    bulletin_board_client::relabel(&title_from, tag_from, title_to, tag_to).unwrap();
302    link.put_str("Sent").unwrap();
303}
304
305#[wll::export(wstp)]
306fn client_version(link: &mut wstp::Link) {
307    assert_eq!(link.test_head("System`List").unwrap(), 0);
308    let client_version = env!("CARGO_PKG_VERSION").to_string();
309    link.put_str(&client_version).unwrap();
310}
311
312#[wll::export(wstp)]
313fn server_version(link: &mut wstp::Link) {
314    assert_eq!(link.test_head("System`List").unwrap(), 0);
315    let server_version = bulletin_board_client::server_version().unwrap();
316    link.put_str(&server_version).unwrap();
317}
318
319#[wll::export(wstp)]
320fn status(link: &mut wstp::Link) {
321    assert_eq!(link.test_head("System`List").unwrap(), 0);
322    let (datasize, memory_used, memory_used_percent, n_bulletins, n_files, n_archives) =
323        bulletin_board_client::status().unwrap();
324    link.put_function("System`List", 6).unwrap();
325    link.put_i64(datasize.try_into().unwrap()).unwrap();
326    link.put_i64(memory_used.try_into().unwrap()).unwrap();
327    link.put_f64(memory_used_percent).unwrap();
328    link.put_i64(n_bulletins.try_into().unwrap()).unwrap();
329    link.put_i64(n_files.try_into().unwrap()).unwrap();
330    link.put_i64(n_archives.try_into().unwrap()).unwrap();
331}
332
333#[wll::export(wstp)]
334fn log(link: &mut wstp::Link) {
335    assert_eq!(link.test_head("System`List").unwrap(), 0);
336    let log = bulletin_board_client::log().unwrap();
337    link.put_str(&log).unwrap();
338}
339
340#[wll::export(wstp)]
341fn view_board(link: &mut wstp::Link) {
342    assert_eq!(link.test_head("System`List").unwrap(), 0);
343    let board = bulletin_board_client::view_board().unwrap();
344    link.put_function("System`List", board.len()).unwrap();
345    for (title, tag, revisions) in board {
346        link.put_function("System`List", 3).unwrap();
347        link.put_str(&title).unwrap();
348        link.put_str(&tag).unwrap();
349        link.put_i64(revisions.try_into().unwrap()).unwrap();
350    }
351}
352
353#[wll::export(wstp)]
354fn get_info(link: &mut wstp::Link) {
355    let argc = link.test_head("System`List").unwrap();
356    let (title, tag) = match argc {
357        1 => (link.get_string().unwrap(), None),
358        2 => (link.get_string().unwrap(), Some(link.get_string().unwrap())),
359        _ => panic!(),
360    };
361    let info = bulletin_board_client::get_info(&title, tag.as_deref()).unwrap();
362    link.put_function("System`List", info.len()).unwrap();
363    for (revision, datasize, timestamp, backend) in info {
364        link.put_function("System`List", 4).unwrap();
365        link.put_i64(revision.try_into().unwrap()).unwrap();
366        link.put_i64(datasize.try_into().unwrap()).unwrap();
367        link.put_str(&timestamp).unwrap();
368        link.put_str(&backend).unwrap();
369    }
370}
371
372#[wll::export(wstp)]
373fn clear_revisions(link: &mut wstp::Link) {
374    let argc = link.test_head("System`List").unwrap();
375    let (title, tag) = match argc {
376        2 => (link.get_string().unwrap(), None),
377        3 => (link.get_string().unwrap(), Some(link.get_string().unwrap())),
378        _ => panic!(),
379    };
380    if link.get_type().unwrap() == wstp::TokenType::Integer {
381        let revision = link.get_i64().unwrap().try_into().unwrap();
382        bulletin_board_client::clear_revisions(&title, tag.as_deref(), vec![revision]).unwrap();
383    } else {
384        let revisions = link
385            .get_i64_array()
386            .unwrap()
387            .data()
388            .into_iter()
389            .map(|&x| x.try_into().unwrap())
390            .collect();
391        bulletin_board_client::clear_revisions(&title, tag.as_deref(), revisions).unwrap();
392    }
393    link.put_str("Sent").unwrap();
394}
395
396#[wll::export(wstp)]
397fn remove(link: &mut wstp::Link) {
398    let argc = link.test_head("System`List").unwrap();
399    let (title, tag) = match argc {
400        1 => (link.get_string().unwrap(), None),
401        2 => (link.get_string().unwrap(), Some(link.get_string().unwrap())),
402        _ => panic!(),
403    };
404    bulletin_board_client::remove(&title, tag.as_deref()).unwrap();
405    link.put_str("Sent").unwrap();
406}
407
408#[wll::export(wstp)]
409fn archive(link: &mut wstp::Link) {
410    let argc = link.test_head("System`List").unwrap();
411    let acv_name = link.get_string().unwrap();
412    let (title, tag) = match argc {
413        2 => (link.get_string().unwrap(), None),
414        3 => (link.get_string().unwrap(), Some(link.get_string().unwrap())),
415        _ => panic!(),
416    };
417    bulletin_board_client::archive(&acv_name, &title, tag.as_deref()).unwrap();
418    link.put_str("Sent").unwrap();
419}
420
421#[wll::export(wstp)]
422fn load(link: &mut wstp::Link) {
423    assert_eq!(link.test_head("System`List").unwrap(), 1);
424    let acv_name = link.get_string().unwrap();
425    bulletin_board_client::load(&acv_name).unwrap();
426    link.put_str("Sent").unwrap();
427}
428
429#[wll::export(wstp)]
430fn list_archive(link: &mut wstp::Link) {
431    assert_eq!(link.test_head("System`List").unwrap(), 0);
432    let list = bulletin_board_client::list_archive().unwrap();
433    link.put_function("System`List", list.len()).unwrap();
434    for name in list {
435        link.put_str(&name).unwrap();
436    }
437}
438
439#[wll::export(wstp)]
440fn rename_archive(link: &mut wstp::Link) {
441    assert_eq!(link.test_head("System`List").unwrap(), 2);
442    let name_from = link.get_string().unwrap();
443    let name_to = link.get_string().unwrap();
444    bulletin_board_client::rename_archive(&name_from, &name_to).unwrap();
445    link.put_str("Sent").unwrap();
446}
447
448#[wll::export(wstp)]
449fn delete_archive(link: &mut wstp::Link) {
450    assert_eq!(link.test_head("System`List").unwrap(), 1);
451    let acv_name = link.get_string().unwrap();
452    bulletin_board_client::delete_archive(&acv_name).unwrap();
453    link.put_str("Sent").unwrap();
454}
455
456#[wll::export(wstp)]
457fn dump(link: &mut wstp::Link) {
458    assert_eq!(link.test_head("System`List").unwrap(), 1);
459    let acv_name = link.get_string().unwrap();
460    bulletin_board_client::dump(&acv_name).unwrap();
461    link.put_str("Sent").unwrap();
462}
463
464#[wll::export(wstp)]
465fn restore(link: &mut wstp::Link) {
466    assert_eq!(link.test_head("System`List").unwrap(), 1);
467    let acv_name = link.get_string().unwrap();
468    bulletin_board_client::restore(&acv_name).unwrap();
469    link.put_str("Sent").unwrap();
470}
471
472#[wll::export(wstp)]
473fn clear_log(link: &mut wstp::Link) {
474    assert_eq!(link.test_head("System`List").unwrap(), 0);
475    bulletin_board_client::clear_log().unwrap();
476    link.put_str("Sent").unwrap();
477}
478
479#[wll::export(wstp)]
480fn reset_server(link: &mut wstp::Link) {
481    assert_eq!(link.test_head("System`List").unwrap(), 0);
482    bulletin_board_client::reset_server().unwrap();
483    link.put_str("Sent").unwrap();
484}
485
486#[wll::export(wstp)]
487fn terminate_server(link: &mut wstp::Link) {
488    assert_eq!(link.test_head("System`List").unwrap(), 0);
489    bulletin_board_client::terminate_server().unwrap();
490    link.put_str("Sent").unwrap();
491}