Skip to main content

Quosure

Struct Quosure 

Source
pub struct Quosure<'a> {
    quo: SEXP,
    expr: SEXP,
    env: SEXP,
    _arg: PhantomData<&'a SEXP>,
    _not_send: PhantomData<*const ()>,
}
Expand description

An argument captured as an rlang quosure, rlang::enquo(x): its expression and environment, with rlang’s argument forwarding and injection resolved.

Take it as a #[miniextendr] parameter. The generated wrapper keeps the parameter as an R formal and passes if (missing(x)) quote(expr=) else rlang::enquo(x), which never forces the argument. Unlike Quoted, a wrapper reached through function(col) f(data, {{ col }}) or called as f(data, !!sym) receives the expression the user wrote, in the user’s environment.

The package must list rlang in Imports. The macro cannot see DESCRIPTION; without rlang the wrapper fails when it is called.

The expression and environment are read from the quosure directly (a quosure is a one-sided formula, ~expr, of class quosure whose environment is its .Environment attribute), so Self::expr, Self::env and Self::as_name call no R code. Self::eval_tidy evaluates through rlang::eval_tidy(), which resolves nested quosures and the .data / .env pronouns. Hand Self::sexp to other quosure-aware R functions (tidyselect::eval_select()) with RCall::eval_with_handlers.

An argument holding several selections, a role map such as cols = c(time = TAD, dose = NA), reads entry by entry with Self::args: each argument of the call as a quosure of its own. A quosure found in an R object reads with Self::from_sexp, and Self::new makes one from an expression and an environment.

Fields§

§quo: SEXP§expr: SEXP§env: SEXP§_arg: PhantomData<&'a SEXP>

Borrows the root that keeps the quosure alive: the .Call() argument, the SEXP it was read from, or a ProtectScope.

§_not_send: PhantomData<*const ()>

R objects stay on R’s main thread.

Implementations§

Source§

impl<'a> Quosure<'a>

Source

unsafe fn read(quo: SEXP) -> Self

Read a quosure’s expression and environment.

§Safety

R’s main thread; quo is a quosure, rooted for 'a.

Source

#[doc(hidden)]
pub unsafe fn from_wrapper_arg(arg: &'a SEXP) -> Option<Self>

Read the argument a generated wrapper passed for a Quosure parameter: None when the argument is missing (quote(expr=), or a quosure of the missing argument, which {{ x }} gives for a missing x). Generated code calls this; user code has no reason to.

§Panics

When arg is not a quosure.

§Safety

R’s main thread; arg stays rooted for 'a.

Source

#[doc(hidden)]
pub unsafe fn missing_from_wrapper_arg(arg: &'a SEXP) -> Missing<Self>

Self::from_wrapper_arg for a Missing<Quosure> parameter.

§Safety

As Self::from_wrapper_arg.

Source

pub unsafe fn from_sexp(sexp: &'a SEXP) -> Option<Self>

Read a quosure the caller holds: None when sexp is not one.

A quosure whose expression is a quosure too, which rlang::new_quosure(<quosure>) makes, is looked through: the result is the innermost one, which is what the outer one evaluates to and what tidyselect::eval_select() accepts (it refuses the outer one). A quosure of the missing argument is read as it is: Self::expr is SEXP::missing_arg().

ⓘ
// `call` is the expression of a `Quosure` argument,
// `c(time = {{ t }})` written by a forwarding wrapper.
for (name, arg) in call.args() {
    if let Some(quosure) = unsafe { Quosure::from_sexp(&arg) } {
        // the quosure `{{ t }}` left in the call, as it is
    }
}
§Safety

R’s main thread, inside a miniextendr boundary (a #[miniextendr] body, a with_r_unwind_protect closure; Self::eval_tidy needs one); sexp stays rooted for 'a.

Source

pub unsafe fn new(expr: SEXP, env: SEXP, scope: &'a ProtectScope) -> Self

A quosure of expr in env, rooted by scope.

A bare expression is wrapped with rlang::new_quosure(expr, env). A quosure is returned as it is, through Self::from_sexp (env is not used): wrapping a quosure again makes a formula that tidyselect::eval_select() refuses. So an argument read from a call can go through new() whether or not a wrapper wrote a quosure there. The missing argument (an empty argument, c(a = )) is wrapped too: Self::expr is then SEXP::missing_arg().

Each call protects one value in scope.

§Panics

When env is not an environment, or when expr is not a quosure and rlang cannot be loaded (a package taking a Quosure lists rlang in Imports).

§Safety

As Self::from_sexp; expr and env are rooted by the caller for the call.

Source

pub fn args<'s>( &'s self, scope: &'s ProtectScope, ) -> Option<Vec<(Option<&'s str>, Quosure<'s>)>>

The arguments of the quosure’s call, each as a quosure with its name, rooted by scope; None when the expression is not a call.

c(time = TAD, dose = NA) gives (Some("time"), TAD) and (Some("dose"), NA), each in this quosure’s environment. An argument a wrapper wrote as a quosure (c(time = {{ t }})) comes back as it is, in its own environment, as Self::new returns it; any other is wrapped in this quosure’s environment with rlang::new_quosure(). The name is None for an unnamed argument; the function (c) is not one of the arguments.

ⓘ
#[miniextendr]
pub fn roles(data: SEXP, cols: Quosure) -> Vec<String> {
    let scope = unsafe { ProtectScope::new() };
    let Some(args) = cols.args(&scope) else {
        panic!("`cols` must be a call, `c(role = column, ...)`");
    };
    for (role, quosure) in args {
        // `quosure.expr()` is `NA` / `NULL` as written; hand the others
        // to `tidyselect::eval_select()`.
    }
}

All the quosures are held in one list, which scope protects.

§Panics

As Self::new: when an argument is not a quosure and rlang cannot be loaded.

Source

pub fn sexp(&self) -> SEXP

The quosure itself, for R functions that take one (rlang::eval_tidy(), tidyselect::eval_select()).

Source

pub fn expr(&self) -> SEXP

The quosure’s expression (rlang::quo_get_expr()).

Source

pub fn env(&self) -> SEXP

The quosure’s environment (rlang::quo_get_env()): the empty environment for a constant.

Source

pub fn as_name(&self) -> Option<&'a str>

The name the argument stands for: TIME, "TIME", {{ col }} with col = TIME and !!rlang::sym("TIME") all give "TIME". A quosure nested in the expression is looked through. None for any other expression.

Source

pub fn eval_tidy(&self, data: SEXP) -> SEXP

Evaluate the quosure with data as a data mask, rlang::eval_tidy(quo, data): columns of data win over variables of the same name in the quosure’s environment, and .data$x / .env$x pick one side. data may be NULL.

Evaluated with eval_with_handlers, so the caller’s handlers see what the expression signals.

The value is unprotected: protect it before the next allocation.

Source

pub fn try_eval_tidy(&self, data: SEXP) -> Result<SEXP, REvalError>

eval_tidy with an R error returned as Err, as try_eval_with_handlers returns it: the caller’s handlers still see the quosure’s warnings and messages. A missing rlang is an Err too.

The value is unprotected: protect it before the next allocation.

Source

unsafe fn eval_tidy_with<R>( &self, data: SEXP, eval: unsafe fn(SEXP, SEXP) -> R, ) -> R

rlang::eval_tidy(quo, data) evaluated by eval.

§Safety

As eval_tidy’s: R’s main thread, inside a miniextendr boundary; data rooted by the caller.

Auto Trait Implementations§

§

impl<'a> !Send for Quosure<'a>

§

impl<'a> !Sync for Quosure<'a>

§

impl<'a> Freeze for Quosure<'a>

§

impl<'a> RefUnwindSafe for Quosure<'a>

§

impl<'a> Unpin for Quosure<'a>

§

impl<'a> UnsafeUnpin for Quosure<'a>

§

impl<'a> UnwindSafe for Quosure<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> SizeHint for T
where T: ?Sized,

Source§

default fn lower_bound(&self) -> usize

🔬This is a nightly-only experimental API. (core_io_internals)
Returns a lower bound on the number of elements this container-like item contains. For example, an array [u8; 12] could return any value between 0 and 12 inclusively as a correct implementation. Read more
Source§

default fn upper_bound(&self) -> Option<usize>

🔬This is a nightly-only experimental API. (core_io_internals)
Returns an upper bound on the number of elements this container-like item contains if it can be determined, otherwise None. Read more
Source§

final fn size_hint(&self) -> (usize, Option<usize>)

🔬This is a nightly-only experimental API. (core_io_internals)
Returns an estimate for the number of elements this container like type contains. Read more
Source§

impl<T> SizedTypeProperties for T

Source§

#[doc(hidden)]
const SIZE: usize = _

🔬This is a nightly-only experimental API. (sized_type_properties)
Source§

#[doc(hidden)]
const ALIGN: usize = _

🔬This is a nightly-only experimental API. (sized_type_properties)
Source§

#[doc(hidden)]
const ALIGNMENT: Alignment = _

🔬This is a nightly-only experimental API. (ptr_alignment_type)
Source§

#[doc(hidden)]
const IS_ZST: bool = _

🔬This is a nightly-only experimental API. (sized_type_properties)
true if this type requires no storage. false if its size is greater than zero. Read more
Source§

#[doc(hidden)]
const LAYOUT: Layout = _

🔬This is a nightly-only experimental API. (sized_type_properties)
Source§

#[doc(hidden)]
const MAX_SLICE_LEN: usize = _

🔬This is a nightly-only experimental API. (sized_type_properties)
The largest safe length for a [Self]. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.

Layout§

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: 24 bytes