1use crate::*;
6use std::io::Write;
7
8#[derive(Debug, PartialEq)]
10pub struct Arg {
11 pub name: &'static str,
12 pub arg_type: &'static str,
13 pub default: Option<&'static str>,
14}
15
16#[derive(Debug, PartialEq)]
18pub struct Func {
19 pub doc: &'static str,
20 pub rust_name: &'static str,
21 pub mod_name: &'static str,
22 pub r_name: &'static str,
23 pub args: Vec<Arg>,
24 pub return_type: &'static str,
25 pub func_ptr: *const u8,
26 pub hidden: bool,
27 pub invisible: Option<bool>,
28}
29
30#[derive(Debug, PartialEq)]
32pub struct Impl {
33 pub doc: &'static str,
34 pub name: &'static str,
35 pub methods: Vec<Func>,
36}
37
38#[derive(Debug, PartialEq)]
40pub struct Metadata {
41 pub name: &'static str,
42 pub functions: Vec<Func>,
43 pub impls: Vec<Impl>,
44}
45
46struct RArg {
47 name: String,
48 default: Option<&'static str>,
49}
50
51impl RArg {
52 fn is_self(&self) -> bool {
53 self.name == "self"
54 }
55
56 fn to_actual_arg(&self) -> String {
57 self.name.clone()
58 }
59
60 fn to_formal_arg(&self) -> String {
61 match self.default {
62 Some(default_val) => format!("{} = {}", self.name, default_val),
63 None => self.name.clone(),
64 }
65 }
66}
67
68impl From<&Arg> for RArg {
69 fn from(arg: &Arg) -> Self {
70 Self {
71 name: sanitize_identifier(arg.name),
72 default: arg.default,
73 }
74 }
75}
76
77impl From<Arg> for Robj {
78 fn from(val: Arg) -> Self {
79 use crate as extendr_api;
80 let mut result = List::from_values(&[r!(val.name), r!(val.arg_type)]);
81 result
82 .set_names(&["name", "arg_type"])
83 .expect("From<Arg> failed");
84 result.into()
85 }
86}
87
88impl From<Func> for Robj {
89 fn from(val: Func) -> Self {
90 use crate as extendr_api;
91 let mut result = List::from_values(&[
92 r!(val.doc),
93 r!(val.rust_name),
94 r!(val.mod_name),
95 r!(val.r_name),
96 r!(List::from_values(val.args)),
97 r!(val.return_type),
98 r!(val.hidden),
99 r!(val.invisible.unwrap_or(false)),
100 ]);
101 result
102 .set_names(&[
103 "doc",
104 "rust_name",
105 "mod_name",
106 "r_name",
107 "args",
108 "return.type",
109 "hidden",
110 "invisible",
111 ])
112 .expect("From<Func> failed");
113 result.into()
114 }
115}
116
117impl From<Impl> for Robj {
118 fn from(val: Impl) -> Self {
119 use crate as extendr_api;
120 let mut result = List::from_values(&[
121 r!(val.doc),
122 r!(val.name),
123 r!(List::from_values(val.methods)),
124 ]);
125 result
126 .set_names(&["doc", "name", "methods"])
127 .expect("From<Impl> failed");
128 result.into()
129 }
130}
131
132impl From<Metadata> for Robj {
133 fn from(val: Metadata) -> Self {
134 use crate as extendr_api;
135 let mut result = List::from_values(&[
136 r!(val.name),
137 r!(List::from_values(val.functions)),
138 r!(List::from_values(val.impls)),
139 ]);
140 result
141 .set_names(&["name", "functions", "impls"])
142 .expect("From<Metadata> failed");
143 result.into()
144 }
145}
146
147fn write_doc(w: &mut Vec<u8>, doc: &str) -> std::io::Result<()> {
148 if !doc.is_empty() {
149 write!(w, "#'")?;
150 for c in doc.chars() {
151 if c == '\n' {
152 write!(w, "\n#'")?;
153 } else {
154 write!(w, "{}", c)?;
155 }
156 }
157 writeln!(w)?;
158 }
159 Ok(())
160}
161
162fn sanitize_identifier(name: &str) -> String {
165 if name.starts_with('_') {
166 format!("`{}`", name)
167 } else if name.starts_with("r#") {
168 name.strip_prefix("r#").unwrap().into()
169 } else {
170 name.to_string()
171 }
172}
173
174fn join_str(input: impl Iterator<Item = String>, sep: &str) -> String {
175 input.collect::<Vec<String>>().join(sep)
176}
177
178fn write_function_wrapper(
180 w: &mut Vec<u8>,
181 func: &Func,
182 package_name: &str,
183 use_symbols: bool,
184) -> std::io::Result<()> {
185 if func.hidden {
186 return Ok(());
187 }
188
189 write_doc(w, func.doc)?;
190
191 let r_args: Vec<RArg> = func.args.iter().map(Into::into).collect();
192 let actual_args = r_args.iter().map(|a| a.to_actual_arg());
193 let formal_args = r_args.iter().map(|a| a.to_formal_arg());
194
195 let should_be_invisible = match func.invisible {
196 Some(true) => true,
197 Some(false) => false,
198 None => {
199 func.return_type == "()" || func.return_type == "Result"
201 }
202 };
203
204 if should_be_invisible {
205 write!(
206 w,
207 "{} <- function({}) invisible(.Call(",
208 sanitize_identifier(func.r_name),
209 join_str(formal_args, ", ")
210 )?;
211 } else {
212 write!(
213 w,
214 "{} <- function({}) .Call(",
215 sanitize_identifier(func.r_name),
216 join_str(formal_args, ", ")
217 )?;
218 }
219
220 if use_symbols {
221 write!(w, "wrap__{}", func.mod_name)?;
222 } else {
223 write!(w, "\"wrap__{}\"", func.mod_name)?;
224 }
225
226 if !func.args.is_empty() {
227 write!(w, ", {}", join_str(actual_args, ", "))?;
228 }
229
230 if !use_symbols {
231 write!(w, ", PACKAGE = \"{}\"", package_name)?;
232 }
233
234 if should_be_invisible {
235 writeln!(w, "))\n")?;
236 } else {
237 writeln!(w, ")\n")?;
238 }
239
240 Ok(())
241}
242
243fn write_method_wrapper(
245 w: &mut Vec<u8>,
246 func: &Func,
247 package_name: &str,
248 use_symbols: bool,
249 class_name: &str,
250) -> std::io::Result<()> {
251 if func.hidden {
252 return Ok(());
253 }
254
255 let r_args: Vec<RArg> = func.args.iter().map(Into::into).collect();
256 let actual_args = r_args.iter().map(|a| a.to_actual_arg());
257
258 let formal_args = r_args
261 .iter()
262 .skip_while(|a| a.is_self())
263 .map(|a| a.to_formal_arg());
264
265 let should_be_invisible = match func.invisible {
268 Some(true) => true,
269 Some(false) => false,
270 None => func.return_type == "()" || func.return_type == "Result",
271 };
272
273 if should_be_invisible {
274 write!(
275 w,
276 "{}${} <- function({}) invisible(.Call(",
277 sanitize_identifier(class_name),
278 sanitize_identifier(func.r_name),
279 join_str(formal_args, ", ")
280 )?;
281 } else {
282 write!(
283 w,
284 "{}${} <- function({}) .Call(",
285 sanitize_identifier(class_name),
286 sanitize_identifier(func.r_name),
287 join_str(formal_args, ", ")
288 )?;
289 }
290
291 if use_symbols {
293 write!(w, "wrap__{}__{}", class_name, func.mod_name)?;
294 } else {
295 write!(w, "\"wrap__{}__{}\"", class_name, func.mod_name)?;
296 }
297
298 if actual_args.len() != 0 {
299 write!(w, ", {}", join_str(actual_args, ", "))?;
300 }
301
302 if !use_symbols {
303 write!(w, ", PACKAGE = \"{}\"", package_name)?;
304 }
305
306 if should_be_invisible {
307 writeln!(w, "))\n")?;
308 } else {
309 writeln!(w, ")\n")?;
310 }
311
312 Ok(())
313}
314
315fn write_impl_wrapper(
317 w: &mut Vec<u8>,
318 name: &str,
319 impls: &[Impl],
320 package_name: &str,
321 use_symbols: bool,
322) -> std::io::Result<()> {
323 let mut exported = false;
324 {
325 for imp in impls.iter().filter(|imp| imp.name == name) {
326 if !exported {
327 exported = imp.doc.contains("@export");
328 }
329 write_doc(w, imp.doc)?;
330 }
331 }
332
333 let imp_name_fixed = sanitize_identifier(name);
334
335 writeln!(w, "{} <- new.env(parent = emptyenv())\n", imp_name_fixed)?;
337
338 for imp in impls.iter().filter(|imp| imp.name == name) {
339 for func in &imp.methods {
340 write_method_wrapper(w, func, package_name, use_symbols, imp.name)?;
343 }
344 }
345
346 if exported {
347 writeln!(w, "#' @rdname {}", name)?;
348 writeln!(w, "#' @usage NULL")?;
349 }
350
351 writeln!(w, "#' @export")?;
356
357 writeln!(w, "`$.{}` <- function (self, name) {{ func <- {}[[name]]; environment(func) <- environment(); func }}\n", name, imp_name_fixed)?;
361
362 writeln!(w, "#' @export")?;
363 writeln!(w, "`[[.{}` <- `$.{}`\n", name, name)?;
364
365 Ok(())
366}
367
368impl Metadata {
369 pub fn make_r_wrappers(
370 &self,
371 use_symbols: bool,
372 package_name: &str,
373 ) -> std::io::Result<String> {
374 let mut w = Vec::new();
375
376 writeln!(
377 w,
378 r#"# Generated by extendr: Do not edit by hand
379#
380# This file was created with the following call:
381# .Call("wrap__make_{}_wrappers", use_symbols = {}, package_name = "{}")
382"#,
383 self.name,
384 if use_symbols { "TRUE" } else { "FALSE" },
385 package_name
386 )?;
387
388 if use_symbols {
389 writeln!(w, "#' @usage NULL")?;
390 writeln!(w, "#' @useDynLib {}, .registration = TRUE", package_name)?;
391 writeln!(w, "NULL")?;
392 writeln!(w)?;
393 }
394
395 for func in &self.functions {
396 write_function_wrapper(&mut w, func, package_name, use_symbols)?;
397 }
398
399 for name in self.impl_names() {
400 write_impl_wrapper(&mut w, name, &self.impls, package_name, use_symbols)?;
401 }
402
403 unsafe { Ok(String::from_utf8_unchecked(w)) }
404 }
405
406 fn impl_names<'a>(&'a self) -> Vec<&'a str> {
407 let mut vec: Vec<&str> = vec![];
408 for impls in &self.impls {
409 if !vec.contains(&impls.name) {
410 vec.push(&impls.name)
411 }
412 }
413 vec
414 }
415}