use wolfram_library_link::{
self as wll,
expr::{Expr, ExprKind, Number, Symbol},
wstp::Link,
};
wll::generate_loader!(load_wstp_functions);
#[wll::export(wstp)]
fn square_wstp(link: &mut Link) {
let arg_count: usize = link.test_head("System`List").unwrap();
if arg_count != 1 {
panic!("square_wstp: expected to get a single argument");
}
let x = link.get_i64().expect("expected Integer argument");
link.put_i64(x * x).unwrap();
}
#[wll::export(wstp)]
fn count_args(link: &mut Link) {
let arg_count: usize = link.test_head("System`List").unwrap();
link.new_packet().unwrap();
link.put_i64(i64::try_from(arg_count).unwrap()).unwrap();
}
#[wll::export(wstp)]
fn total_args_i64(link: &mut Link) {
let arg_count: usize = link.test_head("System`List").unwrap();
let mut total: i64 = 0;
for _ in 0..arg_count {
let term = link.get_i64().expect("expected Integer argument");
total += term;
}
link.put_i64(total).unwrap();
}
#[wll::export(wstp)]
fn string_join(link: &mut Link) {
use wstp::LinkStr;
let arg_count = link.test_head("System`List").unwrap();
let mut buffer = String::new();
for _ in 0..arg_count {
let elem: LinkStr<'_> = link.get_string_ref().expect("expected String argument");
buffer.push_str(elem.as_str());
}
link.put_str(buffer.as_str()).unwrap();
}
#[wll::export(wstp)]
fn link_expr_identity(link: &mut Link) {
let expr = link.get_expr().unwrap();
assert!(!link.is_ready());
link.put_expr(&expr).unwrap();
}
#[wll::export(wstp)]
fn expr_string_join(link: &mut Link) {
let expr = link.get_expr().unwrap();
let list = expr.try_as_normal().unwrap();
assert!(list.has_head(&Symbol::new("System`List")));
let mut buffer = String::new();
for elem in list.elements() {
match elem.kind() {
ExprKind::String(str) => buffer.push_str(str),
_ => panic!("expected String argument, got: {:?}", elem),
}
}
link.put_str(buffer.as_str()).unwrap()
}
#[wll::export(wstp)]
fn total(args: Vec<Expr>) -> Expr {
let mut total = Number::Integer(0);
for (index, arg) in args.into_iter().enumerate() {
let number = match arg.try_as_number() {
Some(number) => number,
None => panic!(
"expected argument at position {} to be a number, got {}",
index + 1,
arg
),
};
use Number::{Integer, Real};
total = match (total, number) {
(Integer(total), Integer(term)) => Integer(total + term),
(Integer(int), Real(real)) | (Real(real), Integer(int)) => {
Number::real(int as f64 + *real)
},
(Real(total), Real(term)) => Real(total + term),
}
}
Expr::number(total)
}