Skip to main content

RNativeType

Derive Macro RNativeType 

Source
#[derive(RNativeType)]
Expand description

Derive macro for implementing RNativeType on a newtype wrapper.

This gives newtypes native buffer access, borrowed &[T] conversions, and participation in the Coerce<R> traits. Add #[derive(IntoR)] to return owned values: T, Vec<T>, Box<[T]>, and their supported nested containers. RNativeType describes storage; IntoR selects the output representation. Keeping them separate also permits an ExternalPtr representation. The inner type must implement RNativeType. Add #[derive(IsNA)] to forward missing-value detection when the inner type supports NA.

§Supported Struct Forms

Both tuple structs and single-field named structs are supported:

ⓘ
use miniextendr_api::RNativeType;

// Tuple struct (most common)
#[repr(transparent)]
#[derive(Clone, Copy, RNativeType)]
struct UserId(i32);

// Named single-field struct
#[repr(transparent)]
#[derive(Clone, Copy, RNativeType)]
struct Temperature { celsius: f64 }

§Generated Code

For struct UserId(i32), this generates:

ⓘ
impl RNativeType for UserId {
    const SEXP_TYPE: SEXPTYPE = <i32 as RNativeType>::SEXP_TYPE;
    const R_NA: Self = UserId(<i32 as RNativeType>::R_NA);

    unsafe fn dataptr_mut(sexp: SEXP) -> *mut Self {
        <i32 as RNativeType>::dataptr_mut(sexp).cast()
    }
}

§Using the Newtype with Coerce

Once RNativeType is derived, you can implement Coerce to/from the newtype:

ⓘ
impl Coerce<UserId> for i32 {
    fn coerce(self) -> UserId { UserId(self) }
}

let id: UserId = 42.coerce();

§Requirements

  • Must be a newtype struct (exactly one field, tuple or named)
  • Must use #[repr(transparent)] so native R buffers have the same layout
  • The inner type must implement RNativeType (i32, f64, RLogical, u8, Rcomplex)
  • Must also be Copy (RNativeType: Copy): derive Clone, Copy with it