1//! The argument-count marker: [`NArgs`].
2//!
3//! R tells some calls apart only by how many arguments were written. A `[`
4//! method receives `x[1:3]` and `x[1:3, ]` with the same `i` and a missing `j`;
5//! only `nargs()` says the second call had an empty argument (2 against 3), and
6//! `[.data.frame` decides between list-style and matrix-style subscripting on
7//! it. A `#[miniextendr]` function that needs the count takes a parameter of
8//! type `NArgs`:
9//!
10//! ```ignore
11//! use miniextendr_api::{Missing, NArgs, SEXP, miniextendr};
12//!
13//! /// `[.mx_vec1`: one subscript only.
14//! #[miniextendr(s3(generic = "[", class = "mx_vec1"))]
15//! pub fn mx_vec1_subset(
16//! x: Vec<f64>,
17//! i: Missing<Vec<i32>>,
18//! _j: Missing<SEXP>,
19//! _drop: Missing<SEXP>,
20//! nargs: NArgs,
21//! ) -> Result<Vec<f64>, String> {
22//! if nargs.get() > 2 {
23//! return Err("an mx_vec1 takes one subscript: x[i]".into());
24//! }
25//! // ...
26//! # let _ = (x, i); Ok(Vec::new())
27//! }
28//! ```
29//!
30//! The parameter is not an R formal: the generated R wrapper passes `nargs()`
31//! at its position in the `.Call()`, so the method above is
32//! `` `[.mx_vec1` <- function(x, i, j, drop) `` and the Rust function gets the
33//! count. It is the count R's `nargs()` gives in the generated function's own
34//! frame, as typed:
35//!
36//! | Typed | `nargs()` |
37//! |---|---|
38//! | `x[1:3]` | 2 |
39//! | `x[1:3, ]` | 3 |
40//! | `x[, 1:3]` | 3 |
41//! | `x[1, 2]` | 3 |
42//! | `x[1, , drop = FALSE]` | 4 |
43//! | `x[]` | 2 |
44//! | `x[i] <- v` / `x[i, ] <- v` | 3 / 4 |
45//!
46//! - `x` counts, and so does every empty argument (`x[1, ]`) and a named
47//! argument such as `drop = FALSE`. A formal with a default that the caller
48//! left out does not.
49//! - It is the generated function's own call that is counted. For an S3
50//! method that is the generic's call as dispatched (`[.mx_vec1` above sees
51//! the call to `[`), with the arguments a `...` formal collects. An
52//! inherent R6 or environment-class method counts its own call without the
53//! object (`obj$pick(1)` is 1). A trait method's function takes the object
54//! as its first argument, which counts, and `obj$method(1)` passes it on
55//! (2, as for `Type$Trait$method(obj, 1)`).
56//! - The wrapper calls `nargs()` only when the function takes an `NArgs`
57//! parameter; every other wrapper is unchanged.
58//!
59//! `NArgs` is a parameter type only, matched by its last path segment like the
60//! other markers (`NArgs`, `miniextendr_api::NArgs`); `&NArgs` and
61//! `Option<NArgs>` are not the marker. It takes no per-parameter option
62//! (`default`, `match_arg`, `coerce`, `no_na`, ...), a function takes at most
63//! one, and an `extern "C-unwind"` function cannot take it (it has no generated
64//! R wrapper to pass the count). Standalone functions, `s3(...)` methods, and
65//! the methods of impl blocks and trait impls accept it. It holds a plain
66//! number, so it does not keep the function on R's main thread.
6768use crate::SEXP;
69use crate::from_r::{SexpError, TryFromSexp};
70use crate::into_r::IntoR;
7172/// The number of arguments in the generated R function's own call, as typed
73/// (`nargs()`): `x` included, an empty argument (`x[1, ]`) included, a named
74/// `drop = FALSE` included. See the [module docs](self).
75#[repr(transparent)]
76#[derive(#[automatically_derived]
impl ::core::fmt::Debug for NArgs {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "NArgs",
&&self.0)
}
}Debug, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for NArgs { }
#[automatically_derived]
impl ::core::clone::Clone for NArgs {
#[inline]
fn clone(&self) -> Self {
let _: ::core::clone::AssertParamIsClone<usize>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for NArgs { }Copy, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for NArgs { }
#[automatically_derived]
impl ::core::cmp::PartialEq for NArgs {
#[inline]
fn eq(&self, other: &Self) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for NArgs {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<usize>;
}
}Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for NArgs {
#[inline]
fn partial_cmp(&self, other: &Self)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
}
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for NArgs {
#[inline]
fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
::core::cmp::Ord::cmp(&self.0, &other.0)
}
}Ord, #[automatically_derived]
impl ::core::hash::Hash for NArgs {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.0, state)
}
}Hash)]
77pub struct NArgs(usize);
7879impl NArgs {
80/// Wrap a count. Generated code converts the parameter from `nargs()`;
81 /// this is for calling such a function from Rust.
82#[inline]
83pub const fn new(count: usize) -> Self {
84NArgs(count)
85 }
8687/// The count.
88#[inline]
89pub const fn get(self) -> usize {
90self.0
91}
92}
9394impl From<NArgs> for usize {
95#[inline]
96fn from(nargs: NArgs) -> usize {
97nargs.0
98}
99}
100101impl std::fmt::Displayfor NArgs {
102fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103self.0.fmt(f)
104 }
105}
106107/// The integer scalar `nargs()` returns, as a non-negative count.
108impl TryFromSexpfor NArgs {
109type Error = SexpError;
110111#[inline]
112fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
113usize::try_from_sexp(sexp).map(NArgs)
114 }
115116#[inline]
117unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
118unsafe { usize::try_from_sexp_unchecked(sexp) }.map(NArgs)
119 }
120}
121122/// The count as an R integer, for a `#[miniextendr]` trait's method that takes
123/// an `NArgs` parameter (its view passes each argument to the vtable as a
124/// SEXP).
125impl IntoRfor NArgs {
126type Error = <usizeas IntoR>::Error;
127128#[inline]
129fn try_into_sexp(self) -> Result<SEXP, Self::Error> {
130self.0.try_into_sexp()
131 }
132133#[inline]
134unsafe fn try_into_sexp_unchecked(self) -> Result<SEXP, Self::Error> {
135unsafe { self.0.try_into_sexp_unchecked() }
136 }
137}