pub enum CallAttribution {
Wrapper,
Caller,
Argument,
NoCall,
Generic,
GenericEager,
}Expand description
Which frame a generated wrapper hands to .Call(.., .call = ..) and uses as
the raise fallback (.miniextendr_raise_condition(.val, <default>)).
Variants§
Wrapper
.call = sys.call(): the wrapper’s own call, as written (default).
Caller
.call = .mx_call, where the wrapper body first binds
.mx_call <- .miniextendr_caller_call(): the caller’s call as written,
resolved by the preamble helper in miniextendr-api/src/registry.rs
(one line per wrapper since #1552, four before). The helper looks two
frames up the calling chain for the wrapper’s caller. It falls back to
the wrapper’s own call when there is no parent frame (top level) or the
parent frame is not a closure: eval()’d code such as a testthat block
or source() has the eval primitive as its frame function, whose call
names eval. For a noexport entry point behind a hand-written R
function (#[miniextendr(noexport, call = caller)]).
A standalone wrapper with this attribution also takes a trailing
.call = NULL formal (CallAttribution::formal, #1613), which the
prelude hands to the helper: a hand-written helper sitting between the
public function and the entry point passes its own caller’s frame
(call = parent.frame() in the helper’s formals, .call = call in its
body), and the condition names the public function. .call also takes a
call object, used as is. S3 methods keep the zero-argument prelude: a
trailing formal would break generic/method consistency.
Argument
.call = .mx_call, where the wrapper body first binds
.mx_call <- if (is.null(.call)) sys.call() else .miniextendr_caller_call(.call, own = TRUE): the wrapper’s own call,
as for CallAttribution::Wrapper, unless the caller passes another
as the trailing .call = NULL formal (#1834). Selected by
#[miniextendr(call_arg)] on a standalone function, exported or not:
an R function composing exported functions (applying them through
do.call(), say) passes .call = environment() and every condition
names its own call. The helper resolves a frame or a call as under
CallAttribution::Caller; a frame no closure owns gives the
wrapper’s own call. The success path without .call costs one
is.null(). Never parsed from call = ...: it is wrapper
attribution plus the formal, so a Call marker reads the resolved
call.
NoCall
.call = FALSE: no call at all (#1851). Selected by
#[miniextendr(call = none)] on a standalone function (an S3 method
included) or by the crate default call_attribution = "none", which
applies to every standalone function. Every condition the wrapper
raises then has a NULL conditionCall(), like R’s call. = FALSE:
the R-side checks and the match_arg helpers are passed NULL, the
slot carries FALSE, the marker the raise helper already reads as “no
call” (what call = none on a condition macro writes, see
ConditionCall::None), and the raise fallback is NULL. There is no
marker spelling: a Call / CallerCall parameter receives the call,
and this attribution has none, so either one is a compile error with
it, as is call_arg (whose .call would have nothing to replace).
Generic
.call = environment(): the wrapper’s own frame, turned into a call
only when a condition is raised (#1851). The attribution of every
generated S3 method that would otherwise be wrapper: a standalone
s3(...) function, an impl-block or trait s3 / vctrs method
(CallAttribution::for_s3_method). The raise helper and
.miniextendr_arg_error resolve the frame with
.miniextendr_frame_call (miniextendr-api/src/registry.rs), which
names the generic the user called when R dispatched the method
(.Generic is bound in the frame: summary(x, a = 1) for
summary.cls(x, a = 1), x[i] for `[.cls`(x, i)) and writes a
replacement generic’s call as the assignment, x$name <- value,
without the value R passed. A direct call of the method keeps the
method’s name. The success path evaluates environment() instead of
sys.call(), the same cost; the rewrite runs only on a raise.
GenericEager
.call = .mx_call, where the wrapper body first binds
.mx_call <- .miniextendr_frame_call(environment()): the
CallAttribution::Generic call resolved before the .Call(), for an
S3 method with a Call parameter, whose C wrapper binds it from the
slot and so needs a call object there (#1851). Costs the frame scan on
every call, so only the marker selects it.
Implementations§
Source§impl CallAttribution
impl CallAttribution
Sourcepub fn parse_name(name: &str) -> Option<Self>
pub fn parse_name(name: &str) -> Option<Self>
The spelling shared by the attribute (call = wrapper | caller | none)
and the crate default (call_attribution = "wrapper" | "caller" | "none").
Sourcepub fn name(self) -> &'static str
pub fn name(self) -> &'static str
The attribute spelling of this attribution. CallAttribution::Argument
is wrapper attribution with the call_arg option, and the two S3
forms are wrapper attribution on a dispatched method, so all three
share wrapper’s spelling.
Sourcepub fn marker_name(self) -> Option<&'static str>
pub fn marker_name(self) -> Option<&'static str>
The parameter marker type that selects this attribution (#1566): Call
for wrapper, CallerCall for caller. none has no marker: a
marker receives the call, and none passes none.
Sourcepub fn for_s3_method(self, has_call_marker: bool) -> Self
pub fn for_s3_method(self, has_call_marker: bool) -> Self
The attribution of a generated S3 method (#1851): wrapper becomes
CallAttribution::Generic, or CallAttribution::GenericEager when
the method takes a Call parameter (has_call_marker), which needs
the call resolved before the .Call(). caller and none are
explicit choices and stay; Argument never reaches an S3 method
(call_arg is refused on them).
Sourcepub fn resolve(
marker: Option<Self>,
attribute: Option<Self>,
crate_default: Option<Self>,
internal_entry: bool,
) -> Self
pub fn resolve( marker: Option<Self>, attribute: Option<Self>, crate_default: Option<Self>, internal_entry: bool, ) -> Self
Resolve a standalone function’s attribution from its three spellings
(#1566), most specific first: the Call / CallerCall parameter
marker, the call = wrapper | caller | none attribute, the crate’s
[package.metadata.miniextendr] call_attribution default and finally
the framework default, wrapper. A crate default of caller applies
to internal entry points (noexport / internal) only; an exported
function’s caller is arbitrary user code, so it keeps wrapper. A
crate default of none applies to every standalone function, like
wrapper (#1851). The explicit spellings are validated before this
runs (a caller marker or attribute on an exported function is a
compile error, not a fallback). Class and trait methods always use
wrapper, except the R6 / S7 lambda frames
(DotCallBuilder::null_call_attribution) and the S3 methods
(CallAttribution::for_s3_method).
Sourcepub fn with_call_arg(self, call_arg: bool) -> Self
pub fn with_call_arg(self, call_arg: bool) -> Self
Apply the call_arg option (#1834) to a resolved attribution:
wrapper becomes CallAttribution::Argument. The option is
validated before this runs: it is a compile error with call = caller
or a CallerCall parameter (whose wrapper already takes .call), on
an S3 method and on an extern "C-unwind" function, and the caller
leaves the crate default out of CallAttribution::resolve when it
is set, so caller never reaches here with it.
Sourcepub fn dot_call_expr(self) -> &'static str
pub fn dot_call_expr(self) -> &'static str
The expression the .Call() line passes as .call: the call as
written, the frame it is read from on a raise, or FALSE for none.
Sourcepub fn dot_call_arg(self) -> &'static str
pub fn dot_call_arg(self) -> &'static str
The .call = ... argument for the .Call() line.
Sourcepub fn raise_default(self) -> &'static str
pub fn raise_default(self) -> &'static str
The fallback call handed to .miniextendr_raise_condition: the same
value as the slot, except that none passes NULL (the helper reads
FALSE in the slot as “no call” and would read it here too; NULL is
the plainer spelling).
Sourcepub fn prelude(self, call_formal: bool) -> String
pub fn prelude(self, call_formal: bool) -> String
The statement the wrapper body needs before anything else: empty for
CallAttribution::Wrapper, CallAttribution::NoCall and
CallAttribution::Generic; the others bind .mx_call. It is the
first part of the wrapper prelude, ahead of the R-side checks
(preconditions, match.arg), so that those checks can attribute their
failures to the caller too (#1548). call_formal says whether the
wrapper has the .call formal (CallAttribution::formal); the
helper then resolves whatever the caller passed there (#1613). Under
CallAttribution::Argument a NULL .call is the wrapper’s own
call, read inline so that a call without .call costs one is.null()
(#1834); the wrapper always has the formal there, since the option is
refused on S3 methods. CallAttribution::GenericEager resolves the
method frame’s call up front (#1851).
Sourcepub fn formal(self) -> Option<&'static str>
pub fn formal(self) -> Option<&'static str>
The trailing formal a standalone wrapper with this attribution takes:
.call = NULL for CallAttribution::Caller (#1613), so a
hand-written helper between the public function and the entry point
can pass on the call to report, and for CallAttribution::Argument
(#1834), so an R function composing exported functions can. NULL
keeps the wrapper’s default (the caller’s call, or its own); an
environment names the closure owning that frame (parent.frame() from
a helper, environment() from the composing function); a call object
is used as is. Rust identifiers cannot start with ., so the name
never collides with a parameter. The caller leaves S3 methods out.
Sourcepub fn param_doc(self) -> Option<&'static str>
pub fn param_doc(self) -> Option<&'static str>
The generated @param text for the CallAttribution::formal. It is
written as the author’s own line would be, not as a filler, so a block
on a page or an inheritance source no author block documents .call
for still documents it (see crate::roxygen::push_fn_param_tags).
Sourcepub fn r_check_call(self) -> Option<&'static str>
pub fn r_check_call(self) -> Option<&'static str>
The call an R-side check raised in the wrapper body should carry:
.mx_call when the prelude binds it, NULL for none, the frame
(environment(), which .miniextendr_arg_error resolves) for an S3
method, otherwise None (the check keeps its own attribution, which
is the wrapper’s frame).
Sourcepub fn match_arg_statement(
self,
param: &str,
choices: &str,
aliases: Option<&str>,
attrs: &ParamAttrs,
) -> String
pub fn match_arg_statement( self, param: &str, choices: &str, aliases: Option<&str>, attrs: &ParamAttrs, ) -> String
The R statement validating a choice parameter (match_arg / choices).
choices is the R expression for the choice list: a literal
c("a", "b"), or the write-time placeholder for an enum. attrs are
the parameter’s own attributes, which carry several_ok and the
type’s layers.
Every form is one call to a preamble helper (.miniextendr_match_arg
for a scalar, .miniextendr_match_arg_several for several_ok,
#1472), guarded by the layers of the parameter type: !missing(..)
for Missing<..> (#1551), with !identical(.., <choices>) for a
single choice, whose formal reads as omitted (#2152; the .Call()
argument forwards the sentinel for it, see
RArgumentBuilder::with_absent_formals), then !is.null(..) for Option<..>
(#1473), or is.character(..) || is.factor(..) for Either<T, R> and
Either<Vec<T>, R> (#1612), which leaves NULL out too: Rust reads it
as None under Option, and otherwise converts it to the R arm, even
for several_ok, whose plain form reads NULL as every choice. The
helpers name the argument in their messages, read a factor as its
labels, and attribute the error to the wrapper’s own call by default;
under CallAttribution::Caller the statement passes .mx_call so the
caller is named instead (#1548), and under
CallAttribution::Argument so that the call passed as .call is.
The list is spelled out because the helpers, unlike
base::match.arg(param), do not read it off the formal.
aliases is the match_arg parameter’s write-time
match_arg_keys::aliases_placeholder, written last as , <placeholder>:
the wrapper writer turns it into the type’s aliases = argument, or
removes it for a type without aliases (#1843). None for a literal
choices(...) list, which has no aliases.
Trait Implementations§
Source§impl Clone for CallAttribution
impl Clone for CallAttribution
impl Copy for CallAttribution
Source§impl Debug for CallAttribution
impl Debug for CallAttribution
Source§impl Default for CallAttribution
impl Default for CallAttribution
Source§impl Eq for CallAttribution
impl Eq for CallAttribution
1.0.0 (const: unstable) · Source§#[doc(hidden)]fn assert_receiver_is_total_eq(&self)
#[doc(hidden)]fn assert_receiver_is_total_eq(&self)
implementation detail of #[derive(Eq)]
Source§#[doc(hidden)]fn assert_fields_are_eq(&self)
#[doc(hidden)]fn assert_fields_are_eq(&self)
derive_eq_internals)Source§impl PartialEq for CallAttribution
impl PartialEq for CallAttribution
impl StructuralPartialEq for CallAttribution
impl TrivialClone for CallAttribution
Auto Trait Implementations§
impl Freeze for CallAttribution
impl RefUnwindSafe for CallAttribution
impl Send for CallAttribution
impl Sync for CallAttribution
impl Unpin for CallAttribution
impl UnsafeUnpin for CallAttribution
impl UnwindSafe for CallAttribution
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> Printable for T
Source§impl<T> SizeHint for Twhere
T: ?Sized,
impl<T> SizeHint for Twhere
T: ?Sized,
Source§default fn lower_bound(&self) -> usize
default fn lower_bound(&self) -> usize
core_io_internals)[u8; 12] could return any value between 0 and
12 inclusively as a correct implementation. Read moreSource§impl<T> SizedTypeProperties for T
impl<T> SizedTypeProperties for T
Source§#[doc(hidden)]const SIZE: usize = _
#[doc(hidden)]const SIZE: usize = _
sized_type_properties)Source§#[doc(hidden)]const ALIGN: usize = _
#[doc(hidden)]const ALIGN: usize = _
sized_type_properties)Source§#[doc(hidden)]const ALIGNMENT: Alignment = _
#[doc(hidden)]const ALIGNMENT: Alignment = _
ptr_alignment_type)Source§#[doc(hidden)]const IS_ZST: bool = _
#[doc(hidden)]const IS_ZST: bool = _
sized_type_properties)Source§#[doc(hidden)]const LAYOUT: Layout = _
#[doc(hidden)]const LAYOUT: Layout = _
sized_type_properties)Source§#[doc(hidden)]const MAX_SLICE_LEN: usize = _
#[doc(hidden)]const MAX_SLICE_LEN: usize = _
sized_type_properties)[Self]. Read moreLayout§
Note: Most layout information is completely unstable and may even differ between compilations. The only exception is types with certain repr(...) attributes. Please see the Rust Reference's “Type Layout” chapter for details on type layout guarantees.
Size: 1 byte
Size for each variant:
Wrapper: 0 bytesCaller: 0 bytesArgument: 0 bytesNoCall: 0 bytesGeneric: 0 bytesGenericEager: 0 bytes