1use crate::robj::IntoRobj;
6use crate::*;
7use std::io::Write;
8
9#[derive(Debug, PartialEq)]
11pub struct Arg {
12 pub name: &'static str,
13 pub arg_type: &'static str,
14}
15
16#[derive(Debug, PartialEq)]
18pub struct Func {
19 pub doc: &'static str,
20 pub name: &'static str,
21 pub args: Vec<Arg>,
22 pub return_type: &'static str,
23 pub func_ptr: *const u8,
24 pub hidden: bool,
25}
26
27#[derive(Debug, PartialEq)]
29pub struct Impl {
30 pub doc: &'static str,
31 pub name: &'static str,
32 pub methods: Vec<Func>,
33}
34
35#[derive(Debug, PartialEq)]
37pub struct Metadata {
38 pub name: &'static str,
39 pub functions: Vec<Func>,
40 pub impls: Vec<Impl>,
41}
42
43impl From<Arg> for Robj {
44 fn from(val: Arg) -> Self {
45 List::from_values(&[r!(val.name), r!(val.arg_type)])
46 .into_robj()
47 .set_names(&["name", "arg_type"])
48 .expect("From<Arg> failed")
49 }
50}
51
52impl From<Func> for Robj {
53 fn from(val: Func) -> Self {
54 List::from_values(&[
55 r!(val.doc),
56 r!(val.name),
57 r!(List::from_values(val.args)),
58 r!(val.return_type),
59 r!(val.hidden),
60 ])
61 .into_robj()
62 .set_names(&["doc", "name", "args", "return.type", "hidden"])
63 .expect("From<Func> failed")
64 }
65}
66
67impl From<Impl> for Robj {
68 fn from(val: Impl) -> Self {
69 List::from_values(&[
70 r!(val.doc),
71 r!(val.name),
72 r!(List::from_values(val.methods)),
73 ])
74 .into_robj()
75 .set_names(&["doc", "name", "methods"])
76 .expect("From<Impl> failed")
77 }
78}
79
80impl From<Metadata> for Robj {
81 fn from(val: Metadata) -> Self {
82 List::from_values(&[
83 r!(val.name),
84 r!(List::from_values(val.functions)),
85 r!(List::from_values(val.impls)),
86 ])
87 .into_robj()
88 .set_names(&["name", "functions", "impls"])
89 .expect("From<Metadata> failed")
90 }
91}
92
93fn write_doc(w: &mut Vec<u8>, doc: &str) -> std::io::Result<()> {
94 if !doc.is_empty() {
95 write!(w, "#'")?;
96 for c in doc.chars() {
97 if c == '\n' {
98 write!(w, "\n#'")?;
99 } else {
100 write!(w, "{}", c)?;
101 }
102 }
103 writeln!(w)?;
104 }
105 Ok(())
106}
107
108fn sanitize_identifier(name: &str) -> String {
110 if name.starts_with('_') {
111 format!("`{}`", name)
112 } else {
113 name.to_string()
114 }
115}
116
117fn write_function_wrapper(
119 w: &mut Vec<u8>,
120 func: &Func,
121 package_name: &str,
122 use_symbols: bool,
123) -> std::io::Result<()> {
124 if func.hidden {
125 return Ok(());
126 }
127
128 write_doc(w, func.doc)?;
129
130 let args = func
131 .args
132 .iter()
133 .map(|arg| sanitize_identifier(arg.name))
134 .collect::<Vec<_>>()
135 .join(", ");
136
137 if func.return_type == "()" {
138 write!(
139 w,
140 "{} <- function({}) invisible(.Call(",
141 sanitize_identifier(func.name),
142 args
143 )?;
144 } else {
145 write!(
146 w,
147 "{} <- function({}) .Call(",
148 sanitize_identifier(func.name),
149 args
150 )?;
151 }
152
153 if use_symbols {
154 write!(w, "wrap__{}", func.name)?;
155 } else {
156 write!(w, "\"wrap__{}\"", func.name)?;
157 }
158
159 if !func.args.is_empty() {
160 write!(w, ", {}", args)?;
161 }
162
163 if !use_symbols {
164 write!(w, ", PACKAGE = \"{}\"", package_name)?;
165 }
166
167 if func.return_type == "()" {
168 writeln!(w, "))\n")?;
169 } else {
170 writeln!(w, ")\n")?;
171 }
172
173 Ok(())
174}
175
176fn write_method_wrapper(
178 w: &mut Vec<u8>,
179 func: &Func,
180 package_name: &str,
181 use_symbols: bool,
182 class_name: &str,
183) -> std::io::Result<()> {
184 if func.hidden {
185 return Ok(());
186 }
187
188 let actual_args = func
189 .args
190 .iter()
191 .map(|arg| sanitize_identifier(arg.name))
192 .collect::<Vec<_>>();
193 let formal_args = if !actual_args.is_empty() && actual_args[0] == "self" {
194 actual_args
197 .iter()
198 .skip(1)
199 .map(|x| x.to_string())
200 .collect::<Vec<_>>()
201 } else {
202 actual_args.clone()
203 };
204
205 let formal_args = formal_args.join(", ");
206 let actual_args = actual_args.join(", ");
207
208 if func.return_type == "()" {
211 write!(
212 w,
213 "{}${} <- function({}) invisible(.Call(",
214 sanitize_identifier(class_name),
215 sanitize_identifier(func.name),
216 formal_args
217 )?;
218 } else {
219 write!(
220 w,
221 "{}${} <- function({}) .Call(",
222 sanitize_identifier(class_name),
223 sanitize_identifier(func.name),
224 formal_args
225 )?;
226 }
227
228 if use_symbols {
230 write!(w, "wrap__{}__{}", class_name, func.name)?;
231 } else {
232 write!(w, "\"wrap__{}__{}\"", class_name, func.name)?;
233 }
234
235 if !actual_args.is_empty() {
236 write!(w, ", {}", actual_args)?;
237 }
238
239 if !use_symbols {
240 write!(w, ", PACKAGE = \"{}\"", package_name)?;
241 }
242
243 if func.return_type == "()" {
244 writeln!(w, "))\n")?;
245 } else {
246 writeln!(w, ")\n")?;
247 }
248
249 Ok(())
250}
251
252fn write_impl_wrapper(
254 w: &mut Vec<u8>,
255 imp: &Impl,
256 package_name: &str,
257 use_symbols: bool,
258) -> std::io::Result<()> {
259 let exported = imp.doc.contains("@export");
260
261 write_doc(w, imp.doc)?;
262
263 let imp_name_fixed = sanitize_identifier(imp.name);
264
265 writeln!(w, "{} <- new.env(parent = emptyenv())\n", imp_name_fixed)?;
267
268 for func in &imp.methods {
269 write_method_wrapper(w, func, package_name, use_symbols, imp.name)?;
272 }
273
274 if exported {
275 writeln!(w, "#' @rdname {}", imp.name)?;
276 writeln!(w, "#' @usage NULL")?;
277 }
278
279 writeln!(w, "#' @export")?;
284
285 writeln!(w, "`$.{}` <- function (self, name) {{ func <- {}[[name]]; environment(func) <- environment(); func }}\n", imp.name, imp_name_fixed)?;
289
290 Ok(())
291}
292
293impl Metadata {
294 pub fn make_r_wrappers(
295 &self,
296 use_symbols: bool,
297 package_name: &str,
298 ) -> std::io::Result<String> {
299 let mut w = Vec::new();
300
301 writeln!(
302 w,
303 r#"# Generated by extendr: Do not edit by hand
304#
305# This file was created with the following call:
306# .Call("wrap__make_{}_wrappers", use_symbols = {}, package_name = "{}")
307"#,
308 self.name,
309 if use_symbols { "TRUE" } else { "FALSE" },
310 package_name
311 )?;
312
313 if use_symbols {
314 writeln!(w, "#' @docType package")?;
315 writeln!(w, "#' @usage NULL")?;
316 writeln!(w, "#' @useDynLib {}, .registration = TRUE", package_name)?;
317 writeln!(w, "NULL")?;
318 writeln!(w)?;
319 }
320
321 for func in &self.functions {
322 write_function_wrapper(&mut w, func, package_name, use_symbols)?;
323 }
324
325 for imp in &self.impls {
326 write_impl_wrapper(&mut w, imp, package_name, use_symbols)?;
327 }
328 unsafe { Ok(String::from_utf8_unchecked(w)) }
329 }
330}