Skip to main content

miniextendr_api/
sexp_ext.rs

1//! `SexpExt` — the ergonomic extension trait on `SEXP` — and `PairListExt`,
2//! its pairlist (call) counterpart.
3//!
4//! Provides safe(r) accessors and type checks. This is the actual user-facing
5//! API surface most callers reach for; both are re-exported from
6//! [`crate::prelude`].
7
8use std::marker::PhantomData;
9
10use crate::from_r::charsxp_to_str;
11use crate::gc_protect::ProtectScope;
12use crate::sexp_types::{R_xlen_t, RNativeType, Rboolean, Rcomplex, SEXPTYPE};
13use crate::{IsNA, SEXP};
14// Pull in everything raw from sys. Type re-exports (SEXP, SEXPTYPE, etc.)
15// that `sys` itself promotes are identical items, so glob import is safe;
16// we still bring SEXP/SEXPTYPE in via crate root above so the file reads
17// naturally.
18use crate::sys::{
19    ALTREP, CAR, CAR_unchecked, CDR, CDR_unchecked, COMPLEX_ELT, DATAPTR_RO, DATAPTR_RO_unchecked,
20    IDENT_USE_CLOENV, INTEGER_ELT, LOGICAL_ELT, PRINTNAME, R_BaseEnv, R_CHAR, R_CHAR_unchecked,
21    R_ClassSymbol, R_DimNamesSymbol, R_DimSymbol, R_LevelsSymbol, R_NaString, R_NamesSymbol,
22    R_RowNamesSymbol, R_compute_identical, RAW_ELT, REAL_ELT, Rf_asChar, Rf_asInteger,
23    Rf_asLogical, Rf_asReal, Rf_classgets, Rf_coerceVector, Rf_cons, Rf_cons_unchecked,
24    Rf_copyMostAttrib, Rf_copyMostAttrib_unchecked, Rf_dimgets, Rf_dimnamesgets, Rf_duplicate,
25    Rf_eval, Rf_getAttrib, Rf_getAttrib_unchecked, Rf_inherits, Rf_install, Rf_isArray,
26    Rf_isFactor, Rf_isFunction, Rf_isList, Rf_isMatrix, Rf_isObject, Rf_isS4, Rf_lang2, Rf_lcons,
27    Rf_namesgets, Rf_setAttrib, Rf_setAttrib_unchecked, Rf_shallow_duplicate, Rf_xlength,
28    Rf_xlength_unchecked, Rf_xlengthgets, SET_COMPLEX_ELT, SET_INTEGER_ELT, SET_LOGICAL_ELT,
29    SET_RAW_ELT, SET_REAL_ELT, SET_STRING_ELT, SET_STRING_ELT_unchecked, SET_TAG,
30    SET_TAG_unchecked, SET_VECTOR_ELT, SET_VECTOR_ELT_unchecked, SETCAR, SETCAR_unchecked, SETCDR,
31    SETCDR_unchecked, STRING_ELT, STRING_ELT_unchecked, TAG, TYPEOF, VECTOR_ELT,
32    VECTOR_ELT_unchecked,
33};
34
35/// Extension trait for SEXP providing safe(r) accessors and type checking.
36///
37/// This trait provides idiomatic Rust methods for working with SEXPs,
38/// equivalent to R's inline macros and type checking functions.
39pub trait SexpExt {
40    /// Get the type of this SEXP.
41    ///
42    /// Equivalent to `TYPEOF(x)` macro.
43    ///
44    /// # Safety
45    ///
46    /// The SEXP must be valid (not null and not freed).
47    #[must_use]
48    fn type_of(&self) -> SEXPTYPE;
49
50    /// Get the length of this SEXP as `usize`.
51    ///
52    /// # Safety
53    ///
54    /// The SEXP must be valid.
55    #[must_use]
56    fn len(&self) -> usize;
57
58    /// Get the length as `R_xlen_t`.
59    ///
60    /// # Safety
61    ///
62    /// The SEXP must be valid.
63    #[must_use]
64    fn xlength(&self) -> R_xlen_t;
65
66    /// Get the length as `R_xlen_t` without thread checks.
67    ///
68    /// # Safety
69    ///
70    /// Must be called from R's main thread. No debug assertions.
71    #[must_use]
72    unsafe fn xlength_unchecked(&self) -> R_xlen_t;
73
74    /// Get the length without thread checks.
75    ///
76    /// # Safety
77    ///
78    /// Must be called from R's main thread. No debug assertions.
79    #[must_use]
80    unsafe fn len_unchecked(&self) -> usize;
81
82    /// Get a slice view of this SEXP's data.
83    ///
84    /// # Safety
85    ///
86    /// - The SEXP must be valid and of the correct type for `T`
87    /// - The SEXP must be protected from R's garbage collector for the entire
88    ///   duration the returned slice is used. This typically means the SEXP must
89    ///   be either:
90    ///   - An argument to a `.Call` function (protected by R's calling convention)
91    ///   - Explicitly protected via `PROTECT`/`UNPROTECT` or `R_PreserveObject`
92    ///   - Part of a protected container (e.g., element of a protected list)
93    /// - The returned slice has `'static` lifetime for API convenience, but this
94    ///   is a lie - the actual lifetime is tied to the SEXP's protection status.
95    ///   Holding the slice after the SEXP is unprotected is undefined behavior.
96    unsafe fn as_slice<T: RNativeType>(&self) -> &'static [T];
97
98    /// Get a slice view without thread checks.
99    ///
100    /// # Safety
101    ///
102    /// - All safety requirements of [`as_slice`](Self::as_slice) apply
103    /// - Additionally, must be called from R's main thread (no debug assertions)
104    unsafe fn as_slice_unchecked<T: RNativeType>(&self) -> &'static [T];
105
106    /// Get a mutable slice view of this SEXP's data.
107    ///
108    /// # Safety
109    ///
110    /// - All safety requirements of [`as_slice`](Self::as_slice) apply.
111    /// - The caller must ensure **exclusive access**: no other `&[T]` or `&mut [T]`
112    ///   slices derived from this SEXP may exist simultaneously. Multiple calls to
113    ///   `as_mut_slice` on the same SEXP without dropping the previous slice is UB.
114    /// - The SEXP must not be shared (ALTREP or NAMED > 0 objects may alias).
115    unsafe fn as_mut_slice<T: RNativeType>(&self) -> &'static mut [T];
116
117    // Type checking methods (equivalent to R's type check macros)
118
119    /// Check if this SEXP is an integer vector (INTSXP).
120    #[must_use]
121    fn is_integer(&self) -> bool;
122
123    /// Check if this SEXP is a real/numeric vector (REALSXP).
124    #[must_use]
125    fn is_real(&self) -> bool;
126
127    /// Check if this SEXP is a logical vector (LGLSXP).
128    #[must_use]
129    fn is_logical(&self) -> bool;
130
131    /// Check if this SEXP is a character/string vector (STRSXP).
132    #[must_use]
133    fn is_character(&self) -> bool;
134
135    /// Check if this SEXP is a raw vector (RAWSXP).
136    #[must_use]
137    fn is_raw(&self) -> bool;
138
139    /// Check if this SEXP is a complex vector (CPLXSXP).
140    #[must_use]
141    fn is_complex(&self) -> bool;
142
143    /// Check if this SEXP is a list/generic vector (VECSXP).
144    #[must_use]
145    fn is_list(&self) -> bool;
146
147    /// Check if this SEXP is an external pointer (EXTPTRSXP).
148    #[must_use]
149    fn is_external_ptr(&self) -> bool;
150
151    /// Check if this SEXP is an environment (ENVSXP).
152    #[must_use]
153    fn is_environment(&self) -> bool;
154
155    /// Check if this SEXP is a symbol (SYMSXP).
156    #[must_use]
157    fn is_symbol(&self) -> bool;
158
159    /// Check if this SEXP is a language object (LANGSXP).
160    #[must_use]
161    fn is_language(&self) -> bool;
162
163    /// Check if this SEXP is an ALTREP object.
164    ///
165    /// Equivalent to R's `ALTREP(x)` macro.
166    #[must_use]
167    fn is_altrep(&self) -> bool;
168
169    /// Check if this `SEXP` contains any elements.
170    #[must_use]
171    fn is_empty(&self) -> bool;
172
173    /// Check if this SEXP is a factor.
174    ///
175    /// Equivalent to R's `Rf_isFactor(x)`.
176    #[must_use]
177    fn is_factor(&self) -> bool;
178
179    /// Check if this SEXP is a pairlist (LISTSXP or NILSXP).
180    ///
181    /// Equivalent to R's `Rf_isList(x)`.
182    #[must_use]
183    fn is_pair_list(&self) -> bool;
184
185    /// Check if this SEXP is a matrix.
186    ///
187    /// Equivalent to R's `Rf_isMatrix(x)`.
188    #[must_use]
189    fn is_matrix(&self) -> bool;
190
191    /// Check if this SEXP is an array.
192    ///
193    /// Equivalent to R's `Rf_isArray(x)`.
194    #[must_use]
195    fn is_array(&self) -> bool;
196
197    /// Check if this SEXP is a function (closure, builtin, or special).
198    ///
199    /// Equivalent to R's `Rf_isFunction(x)`.
200    #[must_use]
201    fn is_function(&self) -> bool;
202
203    /// Check if this SEXP is an S4 object.
204    ///
205    /// Equivalent to R's `Rf_isS4(x)`.
206    #[must_use]
207    fn is_s4(&self) -> bool;
208
209    /// Check if this SEXP is a data.frame.
210    ///
211    /// Equivalent to R's `Rf_isDataFrame(x)`.
212    #[must_use]
213    fn is_data_frame(&self) -> bool;
214
215    /// Check if this SEXP is a numeric type (integer, logical, or real, excluding factors).
216    ///
217    /// Equivalent to R's `Rf_isNumeric(x)`.
218    #[must_use]
219    fn is_numeric(&self) -> bool;
220
221    /// Check if this SEXP is a number type (numeric or complex).
222    ///
223    /// Equivalent to R's `Rf_isNumber(x)`.
224    #[must_use]
225    fn is_number(&self) -> bool;
226
227    /// Check if this SEXP is an atomic vector.
228    ///
229    /// Returns true for logical, integer, real, complex, character, and raw vectors.
230    #[must_use]
231    fn is_vector_atomic(&self) -> bool;
232
233    /// Check if this SEXP is a vector list (VECSXP or EXPRSXP).
234    #[must_use]
235    fn is_vector_list(&self) -> bool;
236
237    /// Check if this SEXP is a vector (atomic vector or list).
238    #[must_use]
239    fn is_vector(&self) -> bool;
240
241    /// Check if this SEXP is an R "object" (has a class attribute).
242    #[must_use]
243    fn is_object(&self) -> bool;
244
245    // region: Coercion and scalar extraction
246
247    /// Coerce this SEXP to the given type, returning a new SEXP.
248    ///
249    /// The result is guaranteed to have the requested SEXPTYPE.
250    /// Equivalent to R's `Rf_coerceVector(x, target)`.
251    #[must_use]
252    fn coerce(&self, target: SEXPTYPE) -> SEXP;
253
254    /// Extract a scalar logical value.
255    ///
256    /// Returns `None` for `NA`. Coerces non-logical inputs.
257    /// Equivalent to R's `Rf_asLogical(x)`.
258    #[must_use]
259    fn as_logical(&self) -> Option<bool>;
260
261    /// Extract a scalar integer value.
262    ///
263    /// Returns `None` for `NA_integer_`. Coerces non-integer inputs.
264    /// Equivalent to R's `Rf_asInteger(x)`.
265    #[must_use]
266    fn as_integer(&self) -> Option<i32>;
267
268    /// Extract a scalar real value.
269    ///
270    /// Returns `None` for `NA_real_` (NaN). Coerces non-real inputs.
271    /// Equivalent to R's `Rf_asReal(x)`.
272    #[must_use]
273    fn as_real(&self) -> Option<f64>;
274
275    /// Extract a scalar CHARSXP from this SEXP.
276    ///
277    /// The result is guaranteed to be a CHARSXP.
278    /// Equivalent to R's `Rf_asChar(x)`.
279    #[must_use]
280    fn as_char(&self) -> SEXP;
281
282    // endregion
283
284    // region: Attribute access
285
286    /// Get an attribute by symbol.
287    #[must_use]
288    fn get_attr(&self, name: SEXP) -> SEXP;
289
290    /// Get an attribute by symbol, returning `None` for `R_NilValue`.
291    #[must_use]
292    fn get_attr_opt(&self, name: SEXP) -> Option<SEXP> {
293        let attr = self.get_attr(name);
294        if attr.is_nil() { None } else { Some(attr) }
295    }
296
297    /// Set an attribute by symbol.
298    fn set_attr(&self, name: SEXP, val: SEXP);
299
300    /// Get the `names` attribute.
301    #[must_use]
302    fn get_names(&self) -> SEXP;
303
304    /// Set the `names` attribute.
305    fn set_names(&self, names: SEXP);
306
307    /// Get the `class` attribute.
308    #[must_use]
309    fn get_class(&self) -> SEXP;
310
311    /// Set the `class` attribute.
312    fn set_class(&self, class: SEXP);
313
314    /// Get the `dim` attribute.
315    #[must_use]
316    fn get_dim(&self) -> SEXP;
317
318    /// Set the `dim` attribute.
319    fn set_dim(&self, dim: SEXP);
320
321    /// Get the `dimnames` attribute.
322    #[must_use]
323    fn get_dimnames(&self) -> SEXP;
324
325    /// Set the `dimnames` attribute.
326    fn set_dimnames(&self, dimnames: SEXP);
327
328    /// Get the `levels` attribute (factors).
329    #[must_use]
330    fn get_levels(&self) -> SEXP;
331
332    /// Set the `levels` attribute (factors).
333    fn set_levels(&self, levels: SEXP);
334
335    /// Get the `row.names` attribute.
336    #[must_use]
337    fn get_row_names(&self) -> SEXP;
338
339    /// Set the `row.names` attribute.
340    fn set_row_names(&self, row_names: SEXP);
341
342    /// Copy every attribute of `from` except `names`, `dim` and `dimnames` onto
343    /// this object, as R's `Rf_copyMostAttrib(from, self)` does.
344    ///
345    /// The rule is R's, used where a result built from a vector should keep
346    /// its class but not its shape (subsetting, `rbind` of typed parts):
347    ///
348    /// - `class`, `levels`, `tzone`, `units` and every other attribute are
349    ///   copied. A copied attribute replaces one of the same name on `self`;
350    ///   the rest of `self`'s attributes, its `names` included, stay.
351    /// - The values are shared, not duplicated: `self` and `from` point at the
352    ///   same attribute objects.
353    /// - When `from` is an object (it has a `class` attribute), `self` is
354    ///   marked as one. An object bit `self` already has stays set.
355    /// - `self`'s S4 bit is set to `from`'s.
356    ///
357    /// The attributes are not checked against `self`'s type: copying
358    /// `factor`'s class and levels onto a double vector gives an object R
359    /// considers malformed. R raises its error when `self` is `NULL`.
360    fn copy_most_attrib(&self, from: SEXP);
361
362    /// Check if this SEXP inherits from a class.
363    ///
364    /// Equivalent to R's `inherits(x, "class_name")`.
365    #[must_use]
366    fn inherits_class(&self, class: &std::ffi::CStr) -> bool;
367
368    /// Check whether this SEXP carries any attributes.
369    ///
370    /// Same answer as `!is.null(attributes(x))` in R. For a pairlist
371    /// (`LISTSXP`), tag names count, because `attributes()` reports them as a
372    /// `names` attribute: `pairlist(a = 1)` has attributes, `pairlist(1)`
373    /// does not. A `CHARSXP` (an element of a character vector) has none:
374    /// R uses its attribute slot for the global string cache, and
375    /// `identical()` skips it too.
376    ///
377    /// The check evaluates `attributes(quote(x))` in the base environment, so
378    /// it allocates a call and, when attributes exist, the list
379    /// `attributes()` returns. R's constant-time test `ANY_ATTRIB` only
380    /// exists from R 4.5.0 and miniextendr supports R 4.4. `ATTRIB` is not
381    /// part of R's API, and `R CMD check` (R >= 4.6) reports packages that
382    /// call it.
383    ///
384    /// To reproduce R's `identical(x, y)`, which compares attributes as well
385    /// as values, use [`is_identical`](Self::is_identical).
386    ///
387    /// ```ignore
388    /// // attributes(c(a = 1)) is list(names = "a")
389    /// assert!(named_vector.has_attributes());
390    /// assert!(!SEXP::scalar_logical(false).has_attributes());
391    /// ```
392    #[must_use]
393    fn has_attributes(&self) -> bool;
394
395    // endregion
396
397    // region: String element access
398
399    /// Get the i-th CHARSXP element from a STRSXP.
400    ///
401    /// Equivalent to R's `STRING_ELT(x, i)`.
402    #[must_use]
403    fn string_elt(&self, i: isize) -> SEXP;
404
405    /// Get the i-th string element as `Option<&str>`.
406    ///
407    /// Returns `None` for `NA_character_`. The returned `&str` borrows from R's
408    /// internal string cache (CHARSXP global pool) and is valid as long as the
409    /// parent STRSXP is protected from GC. The lifetime is tied to `&self` by
410    /// the borrow checker, but the true validity depends on GC protection —
411    /// do not hold the `&str` across allocation boundaries without ensuring
412    /// the SEXP remains protected.
413    #[must_use]
414    fn string_elt_str(&self, i: isize) -> Option<&str>;
415
416    /// Set the i-th CHARSXP element of a STRSXP.
417    ///
418    /// Equivalent to R's `SET_STRING_ELT(x, i, v)`.
419    fn set_string_elt(&self, i: isize, charsxp: SEXP);
420
421    /// Check if this CHARSXP is `NA_character_`.
422    #[must_use]
423    fn is_na_string(&self) -> bool;
424
425    // endregion
426
427    // region: List element access
428
429    /// Get the i-th element of a VECSXP (generic vector / list).
430    ///
431    /// Equivalent to R's `VECTOR_ELT(x, i)`.
432    #[must_use]
433    fn vector_elt(&self, i: isize) -> SEXP;
434
435    /// Set the i-th element of a VECSXP.
436    ///
437    /// Equivalent to R's `SET_VECTOR_ELT(x, i, v)`.
438    fn set_vector_elt(&self, i: isize, val: SEXP);
439
440    // endregion
441
442    // region: Typed single-element access
443
444    /// Get the i-th integer element.
445    #[must_use]
446    fn integer_elt(&self, i: isize) -> i32;
447    /// Get the i-th real element.
448    #[must_use]
449    fn real_elt(&self, i: isize) -> f64;
450    /// Get the i-th logical element (raw i32: 0/1/NA_LOGICAL).
451    #[must_use]
452    fn logical_elt(&self, i: isize) -> i32;
453    /// Get the i-th complex element.
454    #[must_use]
455    fn complex_elt(&self, i: isize) -> Rcomplex;
456    /// Get the i-th raw element.
457    #[must_use]
458    fn raw_elt(&self, i: isize) -> u8;
459
460    /// Set the i-th integer element.
461    fn set_integer_elt(&self, i: isize, v: i32);
462    /// Set the i-th real element.
463    fn set_real_elt(&self, i: isize, v: f64);
464    /// Set the i-th logical element (raw i32: 0/1/NA_LOGICAL).
465    fn set_logical_elt(&self, i: isize, v: i32);
466    /// Set the i-th complex element.
467    fn set_complex_elt(&self, i: isize, v: Rcomplex);
468    /// Set the i-th raw element.
469    fn set_raw_elt(&self, i: isize, v: u8);
470
471    // endregion
472
473    // region: Symbol and CHARSXP access
474
475    /// Get the print name (CHARSXP) of a symbol (SYMSXP).
476    ///
477    /// # Safety
478    ///
479    /// The SEXP must be a valid SYMSXP.
480    #[must_use]
481    fn printname(&self) -> SEXP;
482
483    /// Get the C string pointer from a CHARSXP.
484    ///
485    /// The returned pointer is valid as long as the CHARSXP is protected.
486    ///
487    /// # Safety
488    ///
489    /// The SEXP must be a valid CHARSXP.
490    #[must_use]
491    fn r_char(&self) -> *const ::std::os::raw::c_char;
492
493    /// Get a `&str` from a CHARSXP. Returns `None` for `NA_character_`.
494    #[must_use]
495    fn r_char_str(&self) -> Option<&str>;
496
497    // endregion
498
499    // region: Vector resizing
500
501    /// Resize a vector to a new length, returning a (possibly new) SEXP.
502    ///
503    /// If the new length is shorter, elements are truncated.
504    /// If longer, new elements are filled with NA/NULL.
505    /// Equivalent to R's `Rf_xlengthgets(x, newlen)`.
506    #[must_use]
507    fn resize(&self, newlen: R_xlen_t) -> SEXP;
508
509    // endregion
510
511    // region: Duplication
512
513    /// Deep-copy this SEXP. Equivalent to R's `Rf_duplicate(x)`.
514    #[must_use]
515    fn duplicate(&self) -> SEXP;
516
517    /// Shallow-copy this SEXP. Equivalent to R's `Rf_shallow_duplicate(x)`.
518    #[must_use]
519    fn shallow_duplicate(&self) -> SEXP;
520
521    // endregion
522
523    // region: Comparison
524
525    /// Check whether this SEXP is identical to `other` under the defaults of
526    /// R's `identical(x, y)`.
527    ///
528    /// Calls `R_compute_identical(x, y, IDENT_USE_CLOENV)`. Flag 16 is what
529    /// `identical()` passes with its default arguments: `num.eq`,
530    /// `single.NA`, `attrib.as.set`, `ignore.bytecode` and `ignore.srcref`
531    /// are `TRUE`, and `ignore.environment` and `extptr.as.ref` are `FALSE`.
532    /// Attributes take part in the comparison, so `structure(FALSE, foo = 1)`
533    /// is not identical to `FALSE`.
534    ///
535    /// The `==` operator on `SEXP` compares pointers, not values.
536    ///
537    /// ```ignore
538    /// // R's identical(x, FALSE)
539    /// let is_false = x.is_identical(SEXP::scalar_logical(false));
540    /// ```
541    #[must_use]
542    fn is_identical(&self, other: SEXP) -> bool;
543
544    // endregion
545
546    // region: Unchecked variants (bypass thread-check, for perf-critical paths)
547
548    /// Get the i-th CHARSXP from a STRSXP. No thread check.
549    ///
550    /// # Safety
551    /// Must be called from R's main thread.
552    #[must_use]
553    unsafe fn string_elt_unchecked(&self, i: isize) -> SEXP;
554    /// Set the i-th CHARSXP of a STRSXP. No thread check.
555    ///
556    /// # Safety
557    /// Must be called from R's main thread.
558    unsafe fn set_string_elt_unchecked(&self, i: isize, charsxp: SEXP);
559    /// Get the i-th element of a VECSXP. No thread check.
560    ///
561    /// # Safety
562    /// Must be called from R's main thread.
563    #[must_use]
564    unsafe fn vector_elt_unchecked(&self, i: isize) -> SEXP;
565    /// Set the i-th element of a VECSXP. No thread check.
566    ///
567    /// # Safety
568    /// Must be called from R's main thread.
569    unsafe fn set_vector_elt_unchecked(&self, i: isize, val: SEXP);
570    /// Get an attribute by symbol. No thread check.
571    ///
572    /// # Safety
573    /// Must be called from R's main thread.
574    #[must_use]
575    unsafe fn get_attr_unchecked(&self, name: SEXP) -> SEXP;
576    /// Set an attribute by symbol. No thread check.
577    ///
578    /// # Safety
579    /// Must be called from R's main thread.
580    unsafe fn set_attr_unchecked(&self, name: SEXP, val: SEXP);
581    /// Copy every attribute of `from` except `names`, `dim` and `dimnames`
582    /// onto this object, as [`copy_most_attrib`](Self::copy_most_attrib). No
583    /// thread check.
584    ///
585    /// # Safety
586    /// Must be called from R's main thread.
587    unsafe fn copy_most_attrib_unchecked(&self, from: SEXP);
588
589    /// Get C string pointer from a CHARSXP. No thread check.
590    ///
591    /// # Safety
592    /// Must be called from R's main thread. The SEXP must be a valid CHARSXP.
593    #[must_use]
594    unsafe fn r_char_unchecked(&self) -> *const ::std::os::raw::c_char;
595
596    // endregion
597}
598
599impl SexpExt for SEXP {
600    #[inline]
601    fn type_of(&self) -> SEXPTYPE {
602        unsafe { TYPEOF(*self) }
603    }
604
605    #[inline]
606    fn len(&self) -> usize {
607        unsafe { Rf_xlength(*self) as usize }
608    }
609
610    #[inline]
611    fn xlength(&self) -> R_xlen_t {
612        unsafe { Rf_xlength(*self) }
613    }
614
615    #[inline]
616    unsafe fn xlength_unchecked(&self) -> R_xlen_t {
617        unsafe { Rf_xlength_unchecked(*self) }
618    }
619
620    #[inline]
621    unsafe fn len_unchecked(&self) -> usize {
622        unsafe { Rf_xlength_unchecked(*self) as usize }
623    }
624
625    #[inline]
626    unsafe fn as_slice<T: RNativeType>(&self) -> &'static [T] {
627        if true {
    if !(self.type_of() == T::SEXP_TYPE) {
        {
            ::core::panicking::panic_fmt(format_args!("SEXP type mismatch: expected {0:?}, got {1:?}",
                    T::SEXP_TYPE, self.type_of()));
        }
    };
};debug_assert!(
628            self.type_of() == T::SEXP_TYPE,
629            "SEXP type mismatch: expected {:?}, got {:?}",
630            T::SEXP_TYPE,
631            self.type_of()
632        );
633        unsafe { crate::from_r::r_slice(DATAPTR_RO(*self).cast(), self.len()) }
634    }
635
636    #[inline]
637    unsafe fn as_mut_slice<T: RNativeType>(&self) -> &'static mut [T] {
638        if true {
    if !(self.type_of() == T::SEXP_TYPE) {
        {
            ::core::panicking::panic_fmt(format_args!("SEXP type mismatch: expected {0:?}, got {1:?}",
                    T::SEXP_TYPE, self.type_of()));
        }
    };
};debug_assert!(
639            self.type_of() == T::SEXP_TYPE,
640            "SEXP type mismatch: expected {:?}, got {:?}",
641            T::SEXP_TYPE,
642            self.type_of()
643        );
644        unsafe { crate::from_r::r_slice_mut(T::dataptr_mut(*self), self.len()) }
645    }
646
647    #[inline]
648    unsafe fn as_slice_unchecked<T: RNativeType>(&self) -> &'static [T] {
649        if true {
    if !(self.type_of() == T::SEXP_TYPE) {
        {
            ::core::panicking::panic_fmt(format_args!("SEXP type mismatch: expected {0:?}, got {1:?}",
                    T::SEXP_TYPE, self.type_of()));
        }
    };
};debug_assert!(
650            self.type_of() == T::SEXP_TYPE,
651            "SEXP type mismatch: expected {:?}, got {:?}",
652            T::SEXP_TYPE,
653            self.type_of()
654        );
655        unsafe { crate::from_r::r_slice(DATAPTR_RO_unchecked(*self).cast(), self.len_unchecked()) }
656    }
657
658    // Type checking methods
659
660    #[inline]
661    fn is_integer(&self) -> bool {
662        self.type_of() == SEXPTYPE::INTSXP
663    }
664
665    #[inline]
666    fn is_real(&self) -> bool {
667        self.type_of() == SEXPTYPE::REALSXP
668    }
669
670    #[inline]
671    fn is_logical(&self) -> bool {
672        self.type_of() == SEXPTYPE::LGLSXP
673    }
674
675    #[inline]
676    fn is_character(&self) -> bool {
677        self.type_of() == SEXPTYPE::STRSXP
678    }
679
680    #[inline]
681    fn is_raw(&self) -> bool {
682        self.type_of() == SEXPTYPE::RAWSXP
683    }
684
685    #[inline]
686    fn is_complex(&self) -> bool {
687        self.type_of() == SEXPTYPE::CPLXSXP
688    }
689
690    #[inline]
691    fn is_list(&self) -> bool {
692        self.type_of() == SEXPTYPE::VECSXP
693    }
694
695    #[inline]
696    fn is_external_ptr(&self) -> bool {
697        self.type_of() == SEXPTYPE::EXTPTRSXP
698    }
699
700    #[inline]
701    fn is_environment(&self) -> bool {
702        self.type_of() == SEXPTYPE::ENVSXP
703    }
704
705    #[inline]
706    fn is_symbol(&self) -> bool {
707        self.type_of() == SEXPTYPE::SYMSXP
708    }
709
710    #[inline]
711    fn is_language(&self) -> bool {
712        self.type_of() == SEXPTYPE::LANGSXP
713    }
714
715    #[inline]
716    fn is_altrep(&self) -> bool {
717        unsafe { ALTREP(*self) != 0 }
718    }
719
720    #[inline]
721    fn is_empty(&self) -> bool {
722        self.len() == 0
723    }
724
725    #[inline]
726    fn is_factor(&self) -> bool {
727        unsafe { Rf_isFactor(*self) != Rboolean::FALSE }
728    }
729
730    #[inline]
731    fn is_pair_list(&self) -> bool {
732        unsafe { Rf_isList(*self) != Rboolean::FALSE }
733    }
734
735    #[inline]
736    fn is_matrix(&self) -> bool {
737        unsafe { Rf_isMatrix(*self) != Rboolean::FALSE }
738    }
739
740    #[inline]
741    fn is_array(&self) -> bool {
742        unsafe { Rf_isArray(*self) != Rboolean::FALSE }
743    }
744
745    #[inline]
746    fn is_function(&self) -> bool {
747        unsafe { Rf_isFunction(*self) != Rboolean::FALSE }
748    }
749
750    #[inline]
751    fn is_s4(&self) -> bool {
752        unsafe { Rf_isS4(*self) != Rboolean::FALSE }
753    }
754
755    #[inline]
756    fn is_data_frame(&self) -> bool {
757        self.inherits_class(c"data.frame")
758    }
759
760    #[inline]
761    fn is_numeric(&self) -> bool {
762        let typ = self.type_of();
763        (typ == SEXPTYPE::INTSXP || typ == SEXPTYPE::LGLSXP || typ == SEXPTYPE::REALSXP)
764            && !self.is_factor()
765    }
766
767    #[inline]
768    fn is_number(&self) -> bool {
769        self.is_numeric() || self.is_complex()
770    }
771
772    #[inline]
773    fn is_vector_atomic(&self) -> bool {
774        #[allow(non_exhaustive_omitted_patterns)] match self.type_of() {
    SEXPTYPE::LGLSXP | SEXPTYPE::INTSXP | SEXPTYPE::REALSXP |
        SEXPTYPE::CPLXSXP | SEXPTYPE::STRSXP | SEXPTYPE::RAWSXP => true,
    _ => false,
}matches!(
775            self.type_of(),
776            SEXPTYPE::LGLSXP
777                | SEXPTYPE::INTSXP
778                | SEXPTYPE::REALSXP
779                | SEXPTYPE::CPLXSXP
780                | SEXPTYPE::STRSXP
781                | SEXPTYPE::RAWSXP
782        )
783    }
784
785    #[inline]
786    fn is_vector_list(&self) -> bool {
787        let typ = self.type_of();
788        typ == SEXPTYPE::VECSXP || typ == SEXPTYPE::EXPRSXP
789    }
790
791    #[inline]
792    fn is_vector(&self) -> bool {
793        self.is_vector_atomic() || self.is_vector_list()
794    }
795
796    #[inline]
797    fn is_object(&self) -> bool {
798        unsafe { Rf_isObject(*self) != Rboolean::FALSE }
799    }
800
801    // region: Coercion and scalar extraction
802
803    #[inline]
804    fn coerce(&self, target: SEXPTYPE) -> SEXP {
805        unsafe { Rf_coerceVector(*self, target) }
806    }
807
808    #[inline]
809    fn as_logical(&self) -> Option<bool> {
810        let v = unsafe { Rf_asLogical(*self) };
811        if v.is_na() { None } else { Some(v != 0) }
812    }
813
814    #[inline]
815    fn as_integer(&self) -> Option<i32> {
816        let v = unsafe { Rf_asInteger(*self) };
817        if v.is_na() { None } else { Some(v) }
818    }
819
820    #[inline]
821    fn as_real(&self) -> Option<f64> {
822        let v = unsafe { Rf_asReal(*self) };
823        // `R_IsNA`: a computed NA is `None` too; any other NaN is a value.
824        if v.is_na() { None } else { Some(v) }
825    }
826
827    #[inline]
828    fn as_char(&self) -> SEXP {
829        unsafe { Rf_asChar(*self) }
830    }
831
832    // endregion
833
834    // region: Attribute access
835
836    #[inline]
837    fn get_attr(&self, name: SEXP) -> SEXP {
838        unsafe { Rf_getAttrib(*self, name) }
839    }
840
841    #[inline]
842    fn set_attr(&self, name: SEXP, val: SEXP) {
843        unsafe {
844            Rf_setAttrib(*self, name, val);
845        }
846    }
847
848    #[inline]
849    fn get_names(&self) -> SEXP {
850        unsafe { Rf_getAttrib(*self, R_NamesSymbol) }
851    }
852
853    #[inline]
854    fn set_names(&self, names: SEXP) {
855        unsafe {
856            Rf_namesgets(*self, names);
857        }
858    }
859
860    #[inline]
861    fn get_class(&self) -> SEXP {
862        unsafe { Rf_getAttrib(*self, R_ClassSymbol) }
863    }
864
865    #[inline]
866    fn set_class(&self, class: SEXP) {
867        unsafe {
868            Rf_classgets(*self, class);
869        }
870    }
871
872    #[inline]
873    fn get_dim(&self) -> SEXP {
874        unsafe { Rf_getAttrib(*self, R_DimSymbol) }
875    }
876
877    #[inline]
878    fn set_dim(&self, dim: SEXP) {
879        unsafe {
880            Rf_dimgets(*self, dim);
881        }
882    }
883
884    #[inline]
885    fn get_dimnames(&self) -> SEXP {
886        unsafe { Rf_getAttrib(*self, R_DimNamesSymbol) }
887    }
888
889    #[inline]
890    fn set_dimnames(&self, dimnames: SEXP) {
891        unsafe {
892            Rf_dimnamesgets(*self, dimnames);
893        }
894    }
895
896    #[inline]
897    fn get_levels(&self) -> SEXP {
898        unsafe { Rf_getAttrib(*self, R_LevelsSymbol) }
899    }
900
901    #[inline]
902    fn set_levels(&self, levels: SEXP) {
903        unsafe {
904            Rf_setAttrib(*self, R_LevelsSymbol, levels);
905        }
906    }
907
908    #[inline]
909    fn get_row_names(&self) -> SEXP {
910        unsafe { Rf_getAttrib(*self, R_RowNamesSymbol) }
911    }
912
913    #[inline]
914    fn set_row_names(&self, row_names: SEXP) {
915        unsafe {
916            Rf_setAttrib(*self, R_RowNamesSymbol, row_names);
917        }
918    }
919
920    #[inline]
921    fn copy_most_attrib(&self, from: SEXP) {
922        unsafe { Rf_copyMostAttrib(from, *self) }
923    }
924
925    #[inline]
926    fn inherits_class(&self, class: &std::ffi::CStr) -> bool {
927        unsafe { Rf_inherits(*self, class.as_ptr()) != Rboolean::FALSE }
928    }
929
930    fn has_attributes(&self) -> bool {
931        // A CHARSXP's ATTRIB slot links the string-cache hash chain;
932        // `attributes()` would walk those CHARSXPs as if they were pairlist
933        // nodes.
934        if self.type_of() == SEXPTYPE::CHARSXP {
935            return false;
936        }
937        // `attributes` is a builtin, so its argument is evaluated: wrap the
938        // value in `quote()` so a symbol, call or promise is passed as is.
939        unsafe {
940            let scope = ProtectScope::new();
941            let quoted = scope.protect_raw(Rf_lang2(Rf_install(c"quote".as_ptr()), *self));
942            let call = scope.protect_raw(Rf_lang2(Rf_install(c"attributes".as_ptr()), quoted));
943            !Rf_eval(call, R_BaseEnv).is_nil()
944        }
945    }
946
947    // endregion
948
949    // region: String element access
950
951    #[inline]
952    fn string_elt(&self, i: isize) -> SEXP {
953        unsafe { STRING_ELT(*self, i) }
954    }
955
956    #[inline]
957    fn string_elt_str(&self, i: isize) -> Option<&str> {
958        unsafe {
959            let charsxp = STRING_ELT(*self, i);
960            if std::ptr::addr_eq(charsxp.0, R_NaString.0) {
961                return None;
962            }
963            let p = R_CHAR(charsxp);
964            Some(std::ffi::CStr::from_ptr(p).to_str().unwrap_or(""))
965        }
966    }
967
968    #[inline]
969    fn set_string_elt(&self, i: isize, charsxp: SEXP) {
970        unsafe { SET_STRING_ELT(*self, i, charsxp) }
971    }
972
973    #[inline]
974    fn is_na_string(&self) -> bool {
975        unsafe { std::ptr::addr_eq(self.0, R_NaString.0) }
976    }
977
978    // endregion
979
980    // region: List element access
981
982    #[inline]
983    fn vector_elt(&self, i: isize) -> SEXP {
984        unsafe { VECTOR_ELT(*self, i) }
985    }
986
987    #[inline]
988    fn set_vector_elt(&self, i: isize, val: SEXP) {
989        unsafe {
990            SET_VECTOR_ELT(*self, i, val);
991        }
992    }
993
994    // endregion
995
996    // region: Typed single-element access
997
998    #[inline]
999    fn integer_elt(&self, i: isize) -> i32 {
1000        unsafe { INTEGER_ELT(*self, i) }
1001    }
1002    #[inline]
1003    fn real_elt(&self, i: isize) -> f64 {
1004        unsafe { REAL_ELT(*self, i) }
1005    }
1006    #[inline]
1007    fn logical_elt(&self, i: isize) -> i32 {
1008        unsafe { LOGICAL_ELT(*self, i) }
1009    }
1010    #[inline]
1011    fn complex_elt(&self, i: isize) -> Rcomplex {
1012        unsafe { COMPLEX_ELT(*self, i) }
1013    }
1014    #[inline]
1015    fn raw_elt(&self, i: isize) -> u8 {
1016        unsafe { RAW_ELT(*self, i) }
1017    }
1018    #[inline]
1019    fn set_integer_elt(&self, i: isize, v: i32) {
1020        unsafe { SET_INTEGER_ELT(*self, i, v) }
1021    }
1022    #[inline]
1023    fn set_real_elt(&self, i: isize, v: f64) {
1024        unsafe { SET_REAL_ELT(*self, i, v) }
1025    }
1026    #[inline]
1027    fn set_logical_elt(&self, i: isize, v: i32) {
1028        unsafe { SET_LOGICAL_ELT(*self, i, v) }
1029    }
1030    #[inline]
1031    fn set_complex_elt(&self, i: isize, v: Rcomplex) {
1032        unsafe { SET_COMPLEX_ELT(*self, i, v) }
1033    }
1034    #[inline]
1035    fn set_raw_elt(&self, i: isize, v: u8) {
1036        unsafe { SET_RAW_ELT(*self, i, v) }
1037    }
1038
1039    // endregion
1040
1041    // region: Symbol and CHARSXP access
1042
1043    #[inline]
1044    fn printname(&self) -> SEXP {
1045        unsafe { PRINTNAME(*self) }
1046    }
1047
1048    #[inline]
1049    fn r_char(&self) -> *const ::std::os::raw::c_char {
1050        unsafe { R_CHAR(*self) }
1051    }
1052
1053    #[inline]
1054    fn r_char_str(&self) -> Option<&str> {
1055        if self.is_na_string() {
1056            return None;
1057        }
1058        let p = unsafe { R_CHAR(*self) };
1059        Some(
1060            unsafe { std::ffi::CStr::from_ptr(p) }
1061                .to_str()
1062                .unwrap_or(""),
1063        )
1064    }
1065
1066    // endregion
1067
1068    // region: Vector resizing
1069
1070    #[inline]
1071    fn resize(&self, newlen: R_xlen_t) -> SEXP {
1072        unsafe { Rf_xlengthgets(*self, newlen) }
1073    }
1074
1075    // endregion
1076
1077    // region: Duplication
1078
1079    #[inline]
1080    fn duplicate(&self) -> SEXP {
1081        unsafe { Rf_duplicate(*self) }
1082    }
1083
1084    #[inline]
1085    fn shallow_duplicate(&self) -> SEXP {
1086        unsafe { Rf_shallow_duplicate(*self) }
1087    }
1088
1089    // endregion
1090
1091    // region: Comparison
1092
1093    #[inline]
1094    fn is_identical(&self, other: SEXP) -> bool {
1095        unsafe { R_compute_identical(*self, other, IDENT_USE_CLOENV) != Rboolean::FALSE }
1096    }
1097
1098    // endregion
1099
1100    // region: Unchecked variants
1101
1102    #[inline]
1103    unsafe fn string_elt_unchecked(&self, i: isize) -> SEXP {
1104        unsafe { STRING_ELT_unchecked(*self, i) }
1105    }
1106
1107    #[inline]
1108    unsafe fn set_string_elt_unchecked(&self, i: isize, charsxp: SEXP) {
1109        unsafe { SET_STRING_ELT_unchecked(*self, i, charsxp) }
1110    }
1111
1112    #[inline]
1113    unsafe fn vector_elt_unchecked(&self, i: isize) -> SEXP {
1114        unsafe { VECTOR_ELT_unchecked(*self, i) }
1115    }
1116
1117    #[inline]
1118    unsafe fn set_vector_elt_unchecked(&self, i: isize, val: SEXP) {
1119        unsafe {
1120            SET_VECTOR_ELT_unchecked(*self, i, val);
1121        }
1122    }
1123
1124    #[inline]
1125    unsafe fn get_attr_unchecked(&self, name: SEXP) -> SEXP {
1126        unsafe { Rf_getAttrib_unchecked(*self, name) }
1127    }
1128
1129    #[inline]
1130    unsafe fn set_attr_unchecked(&self, name: SEXP, val: SEXP) {
1131        unsafe {
1132            Rf_setAttrib_unchecked(*self, name, val);
1133        }
1134    }
1135
1136    #[inline]
1137    unsafe fn copy_most_attrib_unchecked(&self, from: SEXP) {
1138        unsafe { Rf_copyMostAttrib_unchecked(from, *self) }
1139    }
1140
1141    #[inline]
1142    unsafe fn r_char_unchecked(&self) -> *const ::std::os::raw::c_char {
1143        unsafe { R_CHAR_unchecked(*self) }
1144    }
1145
1146    // endregion
1147}
1148
1149/// Pairlist (cons cell) operations on a `SEXP`: R's calls (`LANGSXP`) and
1150/// pairlists (`LISTSXP`, such as `formals(f)` or `pairlist(...)`).
1151///
1152/// Each node has three slots: CAR (the value), CDR (the next node, `NULL`
1153/// after the last) and TAG (the name, a symbol, or `NULL` when unnamed). A
1154/// call's first node holds the function, the following nodes its arguments:
1155///
1156/// ```ignore
1157/// use miniextendr_api::{PairListExt, SEXP};
1158///
1159/// // `call` is `c(time = TAD, dose = NA)`, rooted by the caller.
1160/// fn roles(call: SEXP) -> Vec<(Option<String>, SEXP)> {
1161///     call.args().map(|(name, value)| (name.map(str::to_owned), value)).collect()
1162/// }
1163/// ```
1164///
1165/// The values read from a node are reachable from the pairlist, so they stay
1166/// rooted while it does. A pairlist R handed you (a `.Call()` argument, a
1167/// quosure's expression) is shared: change only a node you own, such as one
1168/// of a `shallow_duplicate()` of the call.
1169pub trait PairListExt {
1170    /// A new pairlist node, `CONS(self, cdr)`: this SEXP as its value, `cdr`
1171    /// as the rest. The node is unprotected.
1172    fn cons(self, cdr: SEXP) -> SEXP;
1173
1174    /// A new call node, `LCONS(self, cdr)`: this SEXP (the function) as its
1175    /// value, `cdr` (the arguments) as the rest. The node is unprotected.
1176    fn lcons(self, cdr: SEXP) -> SEXP;
1177
1178    /// The value of this node (`CAR`). On a call, the function.
1179    fn car(&self) -> SEXP;
1180
1181    /// The rest of the pairlist after this node (`CDR`): the next node, or
1182    /// `NULL` after the last. On a call, its arguments.
1183    fn cdr(&self) -> SEXP;
1184
1185    /// The name of this node (`TAG`): a symbol, or `NULL` when it has none.
1186    fn tag(&self) -> SEXP;
1187
1188    /// The arguments of a call, or the elements of a pairlist, as
1189    /// `(name, value)`. The name is `None` for an unnamed one; a repeated
1190    /// name is kept.
1191    ///
1192    /// | `self` | yields |
1193    /// |---|---|
1194    /// | a call, `f(a, b = 2)` | its arguments, `(None, a)` then `(Some("b"), 2)`; the function is not one of them |
1195    /// | a pairlist, `pairlist(a = 1, 2)` | every element, `(Some("a"), 1)` then `(None, 2)` |
1196    /// | `NULL` (the empty pairlist) | nothing |
1197    ///
1198    /// An empty argument, the slot of `f(a = )`, is the missing argument
1199    /// ([`SEXP::missing_arg()`]); a `NULL` argument does not end the walk.
1200    /// The names are the print names of the tags; the borrow of `self` stands
1201    /// for the root that keeps the pairlist alive.
1202    ///
1203    /// # Panics
1204    ///
1205    /// When `self` is not a call, a pairlist or `NULL`.
1206    fn args(&self) -> PairListArgs<'_>;
1207
1208    /// Set the name of this node (`SET_TAG`): a symbol, or `NULL`.
1209    ///
1210    /// Only on a node you own, such as one of a `shallow_duplicate()` of the
1211    /// call, never on a call or pairlist R handed you: R shares them.
1212    fn set_tag(&self, tag: SEXP);
1213
1214    /// Set the value of this node (`SETCAR`); returns `value`.
1215    ///
1216    /// Only on a node you own, such as one of a `shallow_duplicate()` of the
1217    /// call, never on a call or pairlist R handed you: R shares them.
1218    fn set_car(&self, value: SEXP) -> SEXP;
1219
1220    /// Set the rest of the pairlist after this node (`SETCDR`); returns
1221    /// `tail`.
1222    ///
1223    /// Only on a node you own, such as one of a `shallow_duplicate()` of the
1224    /// call, never on a call or pairlist R handed you: R shares them.
1225    fn set_cdr(&self, tail: SEXP) -> SEXP;
1226
1227    /// Create a cons cell (no thread check).
1228    /// # Safety
1229    /// Must be called from R's main thread.
1230    unsafe fn cons_unchecked(self, cdr: SEXP) -> SEXP;
1231
1232    /// Get the CAR (no thread check).
1233    /// # Safety
1234    /// Must be called from R's main thread.
1235    unsafe fn car_unchecked(&self) -> SEXP;
1236
1237    /// Get the CDR (no thread check).
1238    /// # Safety
1239    /// Must be called from R's main thread.
1240    unsafe fn cdr_unchecked(&self) -> SEXP;
1241
1242    /// Set the TAG (no thread check).
1243    /// # Safety
1244    /// Must be called from R's main thread.
1245    unsafe fn set_tag_unchecked(&self, tag: SEXP);
1246
1247    /// Set the CAR (no thread check).
1248    /// # Safety
1249    /// Must be called from R's main thread.
1250    unsafe fn set_car_unchecked(&self, value: SEXP) -> SEXP;
1251
1252    /// Set the CDR (no thread check).
1253    /// # Safety
1254    /// Must be called from R's main thread.
1255    unsafe fn set_cdr_unchecked(&self, tail: SEXP) -> SEXP;
1256}
1257
1258impl PairListExt for SEXP {
1259    #[inline]
1260    fn cons(self, cdr: SEXP) -> SEXP {
1261        unsafe { Rf_cons(self, cdr) }
1262    }
1263
1264    #[inline]
1265    fn lcons(self, cdr: SEXP) -> SEXP {
1266        unsafe { Rf_lcons(self, cdr) }
1267    }
1268
1269    #[inline]
1270    fn car(&self) -> SEXP {
1271        unsafe { CAR(*self) }
1272    }
1273
1274    #[inline]
1275    fn cdr(&self) -> SEXP {
1276        unsafe { CDR(*self) }
1277    }
1278
1279    #[inline]
1280    fn tag(&self) -> SEXP {
1281        unsafe { TAG(*self) }
1282    }
1283
1284    fn args(&self) -> PairListArgs<'_> {
1285        let first = match self.type_of() {
1286            SEXPTYPE::LANGSXP => self.cdr(),
1287            SEXPTYPE::LISTSXP | SEXPTYPE::NILSXP => *self,
1288            other => {
    ::core::panicking::panic_fmt(format_args!("`args()` reads a call, a pairlist or NULL, not {0}",
            other.type_name()));
}panic!(
1289                "`args()` reads a call, a pairlist or NULL, not {}",
1290                other.type_name()
1291            ),
1292        };
1293        PairListArgs {
1294            node: first,
1295            _list: PhantomData,
1296        }
1297    }
1298
1299    #[inline]
1300    fn set_tag(&self, tag: SEXP) {
1301        unsafe { SET_TAG(*self, tag) }
1302    }
1303
1304    #[inline]
1305    fn set_car(&self, value: SEXP) -> SEXP {
1306        unsafe { SETCAR(*self, value) }
1307    }
1308
1309    #[inline]
1310    fn set_cdr(&self, tail: SEXP) -> SEXP {
1311        unsafe { SETCDR(*self, tail) }
1312    }
1313
1314    #[inline]
1315    unsafe fn cons_unchecked(self, cdr: SEXP) -> SEXP {
1316        unsafe { Rf_cons_unchecked(self, cdr) }
1317    }
1318
1319    #[inline]
1320    unsafe fn car_unchecked(&self) -> SEXP {
1321        unsafe { CAR_unchecked(*self) }
1322    }
1323
1324    #[inline]
1325    unsafe fn cdr_unchecked(&self) -> SEXP {
1326        unsafe { CDR_unchecked(*self) }
1327    }
1328
1329    #[inline]
1330    unsafe fn set_tag_unchecked(&self, tag: SEXP) {
1331        unsafe { SET_TAG_unchecked(*self, tag) }
1332    }
1333
1334    #[inline]
1335    unsafe fn set_car_unchecked(&self, value: SEXP) -> SEXP {
1336        unsafe { SETCAR_unchecked(*self, value) }
1337    }
1338
1339    #[inline]
1340    unsafe fn set_cdr_unchecked(&self, tail: SEXP) -> SEXP {
1341        unsafe { SETCDR_unchecked(*self, tail) }
1342    }
1343}
1344
1345/// The arguments of a call, or the elements of a pairlist, as
1346/// `(name, value)`: see [`PairListExt::args`].
1347///
1348/// The `'a` borrow stands for the root that keeps the pairlist alive; the
1349/// names borrow it too.
1350pub struct PairListArgs<'a> {
1351    /// The next node to read, `NULL` once every node has been read.
1352    node: SEXP,
1353    /// Borrows the root of the pairlist.
1354    _list: PhantomData<&'a SEXP>,
1355}
1356
1357impl<'a> Iterator for PairListArgs<'a> {
1358    type Item = (Option<&'a str>, SEXP);
1359
1360    fn next(&mut self) -> Option<Self::Item> {
1361        let node = self.node;
1362        if node.is_nil() {
1363            return None;
1364        }
1365        self.node = node.cdr();
1366        let tag = node.tag();
1367        // A tag is a symbol; its print name lives for the session.
1368        let name = if tag.is_symbol() {
1369            let name = unsafe { charsxp_to_str(tag.printname()) };
1370            (!name.is_empty()).then_some(name)
1371        } else {
1372            None
1373        };
1374        Some((name, node.car()))
1375    }
1376}
1377
1378impl std::iter::FusedIterator for PairListArgs<'_> {}