1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
//! Procedural macros for `#[export]` and `#[init]`.
//!
//! Emitted paths are resolved dynamically at expansion time via
//! `proc-macro-crate`: if the caller's `Cargo.toml` has `wolfram-export` the
//! macro emits `::wolfram_export::*`; if it has `wolfram-library-link` (legacy)
//! it emits `::wolfram_library_link::*`. Both crates expose the same hidden
//! runtime surface so generated code resolves correctly in both cases.
use TokenStream;
use TokenStream as TokenStream2;
use quote;
use ;
//======================================
// #[init]
//======================================
/// Designate an initialization function to run once, when this library is
/// loaded via Wolfram LibraryLink — distinct from [`export`], which wraps a
/// function called on *every* invocation from Wolfram.
///
/// The annotated function must take no arguments and return `()`. `#[init]`
/// can be applied to at most one function in a library, and a library isn't
/// required to define one at all.
///
/// Behind the scenes, the macro generates a `WolframLibrary_initialize()` C
/// symbol — [the well-known entry point][lib-init] the Wolfram Kernel calls
/// automatically when the library is loaded, before any exported function
/// runs.
///
/// # Panics
///
/// Panics inside the `#[init]` function are caught and reported to the Kernel
/// as an error code. If initialization panics, the Kernel will not load any
/// of this library's other exported functions.
///
/// # Example
///
/// ```
/// use wolfram_export::init;
///
/// #[init]
/// fn init_my_library() {
/// println!("library is now initialized");
/// }
/// ```
///
/// [lib-init]: https://reference.wolfram.com/language/LibraryLink/tutorial/LibraryStructure.html#280210622
//======================================
// #[export] — one macro, three wire formats, picked by a keyword argument.
//======================================
/// Export a function as a Wolfram LibraryLink function, in one of three wire
/// formats picked by a keyword argument. All three need
/// `LibraryFunctionLoad` on the Wolfram side and none of them need the
/// `automate-function-loading-boilerplate` feature to *work* — that feature
/// only affects whether `cargo wl build` can discover the load call for you.
///
/// | Attribute | Wire format | Cargo feature (on `wolfram-export`) |
/// |------------------|--------------------------|--------------------------------------|
/// | `#[export]` | native `MArgument` ABI | `native` (in the default feature set) |
/// | `#[export(wstp)]`| WSTP `LinkObject` | `wstp` |
/// | `#[export(wxf)]` | typed WXF `ByteArray` | `wxf` |
///
/// ```toml
/// # Cargo.toml
/// wolfram-export = { version = "0.6", features = ["wstp", "wxf"] } # native is on by default
/// ```
///
/// # `#[export]` — native mode (default)
///
/// Parameters and the return type must implement `FromArg`/`IntoArg`:
/// `bool`, `i64`, `f64`, `String`, `NumericArray`, and references thereof.
/// This is the fastest mode — arguments cross the LibraryLink ABI with no
/// intermediate encoding.
///
/// ```
/// # mod scope {
/// use wolfram_export::export;
///
/// #[export]
/// fn add(a: i64, b: i64) -> i64 { a + b }
///
/// #[export]
/// fn greet(name: String) -> String { format!("Hello, {name}!") }
/// # }
/// ```
///
/// # `#[export(wstp)]` — WSTP mode
///
/// The function receives a `Vec<Expr>` (all arguments as a list) and returns
/// an `Expr`, or takes a `&mut Link` for low-level control over the wire.
/// Use this mode when the function's arguments or return value don't fit a
/// fixed native/WXF shape — e.g. variadic arguments, or streaming a result
/// incrementally.
///
/// ```
/// # mod scope {
/// use wolfram_export::export;
/// use wolfram_expr::{expr, Expr, ExprKind};
///
/// // High-level: Vec<Expr> in, Expr out.
/// #[export(wstp)]
/// fn reverse(args: Vec<Expr>) -> Expr {
/// let list = args.into_iter().next().expect("expected 1 arg");
/// if let ExprKind::Normal(n) = list.kind() {
/// let head = n.head().clone();
/// expr!(head[..n.elements().iter().rev().cloned()])
/// } else {
/// list
/// }
/// }
/// # }
/// ```
///
/// # `#[export(wxf)]` — typed WXF mode
///
/// The generated wrapper reads a WXF-encoded `ByteArray` MArgument,
/// deserializes all arguments via `FromWXF`, calls your function, and
/// serializes the return value via `ToWXF` back into a `ByteArray`. Panics
/// are caught and returned as structured `Failure["RustPanic", …]`
/// expressions. Use this mode for structured arguments/return values
/// (structs, enums, `Option`/`Result`) without hand-writing WSTP plumbing.
///
/// ```
/// # mod scope {
/// use wolfram_export::export;
/// use wolfram_expr::{expr, Expr};
/// use wolfram_serialize::{ToWXF, FromWXF};
///
/// // Primitives and Vec<T> work out of the box.
/// #[export(wxf)]
/// fn scale(values: Vec<f64>, factor: f64) -> Vec<f64> {
/// values.into_iter().map(|v| v * factor).collect()
/// }
///
/// // `Expr` implements `ToWXF`/`FromWXF` directly (in `wolfram-expr`), so a
/// // function can take and return untyped Wolfram Language expressions —
/// // useful when the shape isn't known ahead of time, or a derive isn't worth
/// // it. Build the result with the `expr!` macro.
/// #[export(wxf)]
/// fn add_hold(e: Expr) -> Expr {
/// expr!(System::Hold[e])
/// }
///
/// // Structs need #[derive(ToWXF, FromWXF)].
/// #[derive(ToWXF, FromWXF)]
/// struct Point { x: f64, y: f64 }
///
/// #[export(wxf)]
/// fn midpoint(a: Point, b: Point) -> Point {
/// Point { x: (a.x + b.x) / 2.0, y: (a.y + b.y) / 2.0 }
/// }
///
/// // Option<T> and Result<T,E> are supported too.
/// #[export(wxf)]
/// fn safe_div(a: f64, b: f64) -> Option<f64> {
/// if b == 0.0 { None } else { Some(a / b) }
/// }
/// # }
/// ```
///
/// On the Wolfram side a struct maps to an `Association`:
///
/// ```wolfram
/// midpoint[<|"x" -> 0.0, "y" -> 0.0|>, <|"x" -> 2.0, "y" -> 4.0|>]
/// (* Returns <|"x" -> 1.0, "y" -> 2.0|> *)
/// ```