miniextendr_macros/miniextendr_impl/
vctrs_class.rs1use super::{ParsedImpl, VctrsKind};
12
13const VCTRS_IMPORTS: &str =
15 "@importFrom vctrs new_vctr new_rcrd new_list_of vec_ptype2 vec_cast vec_ptype_abbr";
16
17pub fn generate_vctrs_class(parsed_impl: &ParsedImpl) -> super::ClassWrapper {
47 use crate::r_class_formatter::{
48 ClassDocBuilder, MethodDocBuilder, ParsedImplExt, should_export_from_tags,
49 };
50
51 let class_name = parsed_impl.class_name();
52 let type_ident = &parsed_impl.type_ident;
53 let class_doc_tags = &parsed_impl.doc_tags;
54 let vctrs_attrs = &parsed_impl.vctrs_attrs;
55 let should_export =
56 should_export_from_tags(class_doc_tags, parsed_impl.noexport || parsed_impl.internal);
57 let class_has_no_rd = crate::roxygen::has_roxygen_tag(class_doc_tags, "noRd")
73 || (parsed_impl.noexport && !parsed_impl.internal);
74
75 let ctor_name = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("new_{0}",
class_name.to_lowercase()))
})format!("new_{}", class_name.to_lowercase());
77
78 let mut w = super::ClassWrapper::default();
79 let mut lines = Vec::new();
80 crate::roxygen::push_roxygen_tags(&mut w.class_docs, class_doc_tags);
83
84 if let Some(ctx) = parsed_impl.constructor_context() {
86 lines.push(ctx.source_comment(type_ident));
87 let mut ctor_doc_tags = Vec::new();
88 ctor_doc_tags.extend(class_doc_tags.iter().cloned());
89 ctor_doc_tags.extend(ctx.method.doc_tags.iter().cloned());
90 let ctor_choice_docs = ctx.choice_param_docs();
91
92 let class_docs = ClassDocBuilder::new(&class_name, type_ident, &ctor_doc_tags, "vctrs S3")
93 .with_ctor_params(&ctx.params, &ctor_choice_docs)
94 .with_imports(VCTRS_IMPORTS)
95 .with_export_control(parsed_impl.internal, parsed_impl.noexport);
96 lines.extend(class_docs.build());
97 w.class_docs = class_docs.docs();
98 w.mark_class_doc_lines(&mut lines, parsed_impl);
99
100 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} <- function({1}) {{",
ctor_name, ctx.params))
})format!("{} <- function({}) {{", ctor_name, ctx.params));
102 for check in ctx.precondition_checks() {
103 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" {0}", check))
})format!(" {}", check));
104 }
105 for line in ctx.match_arg_prelude() {
107 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" {0}", line))
})format!(" {}", line));
108 }
109 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" .val <- {0}", ctx.static_call()))
})format!(" .val <- {}", ctx.static_call()));
110 lines.extend(crate::method_return_builder::condition_check_lines(" "));
111 lines.push(" data <- .val".to_string());
112
113 match vctrs_attrs.kind {
114 VctrsKind::Vctr => {
115 let inherit_arg = match vctrs_attrs.inherit_base_type {
117 Some(true) => ", inherit_base_type = TRUE",
118 Some(false) => ", inherit_base_type = FALSE",
119 None => "",
120 };
121 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" vctrs::new_vctr(data, class = \"{0}\"{1})",
class_name, inherit_arg))
})format!(
122 " vctrs::new_vctr(data, class = \"{}\"{})",
123 class_name, inherit_arg
124 ));
125 }
126 VctrsKind::Rcrd => {
127 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" vctrs::new_rcrd(data, class = \"{0}\")",
class_name))
})format!(
129 " vctrs::new_rcrd(data, class = \"{}\")",
130 class_name
131 ));
132 }
133 VctrsKind::ListOf => {
134 let ptype_arg = vctrs_attrs
136 .ptype
137 .as_ref()
138 .map(|p| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", ptype = {0}", p))
})format!(", ptype = {}", p))
139 .unwrap_or_default();
140 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!(" vctrs::new_list_of(data, class = \"{0}\"{1})",
class_name, ptype_arg))
})format!(
141 " vctrs::new_list_of(data, class = \"{}\"{})",
142 class_name, ptype_arg
143 ));
144 }
145 }
146 lines.push("}".to_string());
147 lines.push(String::new());
148 } else {
149 super::s3_class::no_constructor_head(
150 parsed_impl,
151 &mut w,
152 &mut lines,
153 "vctrs S3",
154 Some(VCTRS_IMPORTS),
155 );
156 }
157
158 if let Some(abbr) = &vctrs_attrs.abbr {
160 if class_has_no_rd {
161 lines.push("#' @noRd".to_string());
164 } else {
165 lines.push(super::member_default(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @rdname {0}", class_name))
})format!("#' @rdname {}", class_name)));
166 }
167 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @method vec_ptype_abbr {0}",
class_name))
})format!("#' @method vec_ptype_abbr {}", class_name));
168 lines.push("#' @export".to_string());
169 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("vec_ptype_abbr.{0} <- function(x, ...) \"{1}\"",
class_name, abbr))
})format!(
170 "vec_ptype_abbr.{} <- function(x, ...) \"{}\"",
171 class_name, abbr
172 ));
173 lines.push(String::new());
174 }
175
176 if class_has_no_rd {
179 lines.push("#' @noRd".to_string());
180 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @method vec_ptype2 {0}.{1}",
class_name, class_name))
})format!(
181 "#' @method vec_ptype2 {}.{}",
182 class_name, class_name
183 ));
184 } else {
185 lines.push(super::member_default(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @rdname {0}", class_name))
})format!("#' @rdname {}", class_name)));
186 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @method vec_ptype2 {0}.{1}",
class_name, class_name))
})format!(
187 "#' @method vec_ptype2 {}.{}",
188 class_name, class_name
189 ));
190 lines.push(super::member_default(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @param x A {0} vector.",
class_name))
})format!(
191 "#' @param x A {} vector.",
192 class_name
193 )));
194 lines.push(super::member_default(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @param y A {0} vector.",
class_name))
})format!(
195 "#' @param y A {} vector.",
196 class_name
197 )));
198 lines.push(super::member_default(
199 "#' @param ... Additional arguments (unused).".to_string(),
200 ));
201 }
202 lines.push("#' @export".to_string());
203 match vctrs_attrs.kind {
204 VctrsKind::Vctr => {
205 let base_type = vctrs_attrs
206 .base
207 .as_ref()
208 .map(|b| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}()", b))
})format!("{}()", b))
209 .unwrap_or_else(|| "double()".to_string());
210 let inherit_arg = match vctrs_attrs.inherit_base_type {
211 Some(true) => ", inherit_base_type = TRUE",
212 Some(false) => ", inherit_base_type = FALSE",
213 None => "",
214 };
215 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("vec_ptype2.{0}.{0} <- function(x, y, ...) vctrs::new_vctr({1}, class = \"{0}\"{2})",
class_name, base_type, inherit_arg))
})format!(
216 "vec_ptype2.{c}.{c} <- function(x, y, ...) vctrs::new_vctr({base}, class = \"{c}\"{inherit})",
217 c = class_name,
218 base = base_type,
219 inherit = inherit_arg
220 ));
221 }
222 VctrsKind::Rcrd => {
223 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("vec_ptype2.{0}.{0} <- function(x, y, ...) x[0]",
class_name))
})format!(
225 "vec_ptype2.{c}.{c} <- function(x, y, ...) x[0]",
226 c = class_name
227 ));
228 }
229 VctrsKind::ListOf => {
230 let ptype_arg = vctrs_attrs
231 .ptype
232 .as_ref()
233 .map(|p| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!(", ptype = {0}", p))
})format!(", ptype = {}", p))
234 .unwrap_or_default();
235 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("vec_ptype2.{0}.{0} <- function(x, y, ...) vctrs::new_list_of(list(), class = \"{0}\"{1})",
class_name, ptype_arg))
})format!(
236 "vec_ptype2.{c}.{c} <- function(x, y, ...) vctrs::new_list_of(list(), class = \"{c}\"{ptype})",
237 c = class_name,
238 ptype = ptype_arg
239 ));
240 }
241 }
242 lines.push(String::new());
243
244 if class_has_no_rd {
246 lines.push("#' @noRd".to_string());
247 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @method vec_cast {0}.{1}",
class_name, class_name))
})format!("#' @method vec_cast {}.{}", class_name, class_name));
248 } else {
249 lines.push(super::member_default(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @rdname {0}", class_name))
})format!("#' @rdname {}", class_name)));
250 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @method vec_cast {0}.{1}",
class_name, class_name))
})format!("#' @method vec_cast {}.{}", class_name, class_name));
251 lines.push(super::member_default(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @param x A {0} vector to cast.",
class_name))
})format!(
252 "#' @param x A {} vector to cast.",
253 class_name
254 )));
255 lines.push(super::member_default(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @param to A {0} prototype.",
class_name))
})format!(
256 "#' @param to A {} prototype.",
257 class_name
258 )));
259 lines.push(super::member_default(
260 "#' @param ... Additional arguments (unused).".to_string(),
261 ));
262 }
263 lines.push("#' @export".to_string());
264 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("vec_cast.{0}.{0} <- function(x, to, ...) x",
class_name))
})format!(
265 "vec_cast.{c}.{c} <- function(x, to, ...) x",
266 c = class_name
267 ));
268 lines.push(String::new());
269 w.head = std::mem::take(&mut lines);
270
271 for ctx in parsed_impl.static_method_contexts() {
277 lines.push(ctx.source_comment(type_ident));
278
279 let is_protocol = ctx.method.method_attrs.vctrs_protocol.is_some();
280 let fn_name = if let Some(ref proto) = ctx.method.method_attrs.vctrs_protocol {
281 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}.{1}", proto, class_name))
})format!("{}.{}", proto, class_name)
283 } else {
284 let method_name = ctx.method.r_method_name();
285 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}_{1}",
class_name.to_lowercase(), method_name))
})format!("{}_{}", class_name.to_lowercase(), method_name)
286 };
287 let r_name = fn_name.clone();
288
289 let mx_doc = ctx.choice_param_docs();
290 let method_name = ctx.method.r_method_name();
291 if is_protocol {
292 let proto = ctx.method.method_attrs.vctrs_protocol.as_ref().unwrap();
293 let method_doc =
294 MethodDocBuilder::new(&class_name, &method_name, type_ident, &ctx.method.doc_tags)
295 .with_source_method(&ctx.method.ident)
296 .with_r_params(&ctx.params)
297 .with_choice_param_docs(&mx_doc)
298 .with_r_name(r_name.clone())
299 .with_class_no_rd(class_has_no_rd);
300 lines.extend(method_doc.build());
301 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("#\' @method {0} {1}", proto,
class_name))
})format!("#' @method {} {}", proto, class_name));
302 lines.push("#' @export".to_string());
303 } else {
304 let method_doc =
305 MethodDocBuilder::new(&class_name, &method_name, type_ident, &ctx.method.doc_tags)
306 .with_source_method(&ctx.method.ident)
307 .with_r_params(&ctx.params)
308 .with_choice_param_docs(&mx_doc)
309 .with_r_name(r_name.clone())
310 .with_class_no_rd(class_has_no_rd);
311 lines.extend(method_doc.build());
312 if should_export {
316 lines.push("#' @export".to_string());
317 }
318 }
319
320 let formals = if is_protocol && !ctx.method.has_dots {
324 if ctx.params.is_empty() {
325 "...".to_string()
326 } else {
327 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}, ...", ctx.params))
})format!("{}, ...", ctx.params)
328 }
329 } else {
330 ctx.params.to_string()
331 };
332 lines.push(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0} <- function({1}) {{",
crate::naming::r_def_name(&fn_name), formals))
})format!(
333 "{} <- function({}) {{",
334 crate::naming::r_def_name(&fn_name),
335 formals
336 ));
337
338 ctx.emit_method_prelude(&mut lines, " ", &fn_name, &formals);
339
340 let strategy = crate::ReturnStrategy::for_method(ctx.method);
341 let return_builder = crate::MethodReturnBuilder::new(ctx.static_call())
342 .with_strategy(strategy)
343 .with_invisible(ctx.method.is_invisible())
344 .with_class_name(class_name.clone())
345 .with_return_class_from_method(ctx.method, &type_ident.to_string());
346 lines.extend(return_builder.build_s3_body());
347
348 lines.push("}".to_string());
349 lines.push(String::new());
350 }
351
352 w.members = lines;
353 w
354}
355
356#[cfg(test)]
358pub fn generate_vctrs_r_wrapper(parsed_impl: &ParsedImpl) -> String {
359 generate_vctrs_class(parsed_impl).render()
360}