11use libr:: SEXP ;
22
3+ // --- Closure accessors ---
4+
35pub fn fn_formals ( x : SEXP ) -> SEXP {
46 unsafe { libr:: FORMALS ( x) }
57}
@@ -24,6 +26,16 @@ pub fn fn_env(x: SEXP) -> SEXP {
2426 }
2527}
2628
29+ pub unsafe fn new_function ( formals : SEXP , body : SEXP , env : SEXP ) -> SEXP {
30+ if libr:: has:: R_mkClosure ( ) {
31+ libr:: R_mkClosure ( formals, body, env)
32+ } else {
33+ compat:: alloc_closure ( formals, body, env)
34+ }
35+ }
36+
37+ // --- Environment bindings ---
38+
2739pub fn env_binding_is_locked ( env : SEXP , sym : SEXP ) -> bool {
2840 unsafe { libr:: R_BindingIsLocked ( sym, env) != 0 }
2941}
@@ -54,15 +66,60 @@ pub fn env_bind_force(env: SEXP, sym: SEXP, value: SEXP) {
5466 }
5567}
5668
57- /// Creates a closure.
58- pub unsafe fn new_function ( formals : SEXP , body : SEXP , env : SEXP ) -> SEXP {
59- if libr:: has:: R_mkClosure ( ) {
60- libr:: R_mkClosure ( formals, body, env)
61- } else {
62- compat:: alloc_closure ( formals, body, env)
69+ // --- Attributes ---
70+
71+ /// Gets an attribute from `x`.
72+ pub fn attrib_get ( x : SEXP , tag : SEXP ) -> SEXP {
73+ unsafe { libr:: Rf_getAttrib ( x, tag) }
74+ }
75+
76+ pub fn attrib_poke ( x : SEXP , tag : SEXP , value : SEXP ) {
77+ unsafe {
78+ libr:: Rf_setAttrib ( x, tag, value) ;
6379 }
6480}
6581
82+ /// Returns `true` if `x` has any attributes.
83+ pub fn attrib_has_any ( x : SEXP ) -> bool {
84+ unsafe {
85+ if libr:: has:: ANY_ATTRIB ( ) {
86+ libr:: ANY_ATTRIB ( x) != 0
87+ } else {
88+ libr:: ATTRIB ( x) != libr:: R_NilValue
89+ }
90+ }
91+ }
92+
93+ /// Iterates over the attributes of `x`, calling `f(tag, value)` for each.
94+ pub fn attrib_for_each < F : FnMut ( SEXP , SEXP ) > ( x : SEXP , mut f : F ) {
95+ unsafe {
96+ if libr:: has:: R_mapAttrib ( ) {
97+ unsafe extern "C-unwind" fn trampoline < F : FnMut ( SEXP , SEXP ) > (
98+ tag : SEXP ,
99+ val : SEXP ,
100+ data : * mut std:: ffi:: c_void ,
101+ ) -> SEXP {
102+ let f = & mut * ( data as * mut F ) ;
103+ f ( tag, val) ;
104+ std:: ptr:: null_mut ( )
105+ }
106+ let data = & mut f as * mut F as * mut std:: ffi:: c_void ;
107+ libr:: R_mapAttrib ( x, Some ( trampoline :: < F > ) , data) ;
108+ } else {
109+ compat:: map_attrib ( x, & mut f) ;
110+ }
111+ }
112+ }
113+
114+ /// Copies all attributes from `src` to `dst`.
115+ pub fn attrib_poke_from ( dst : SEXP , src : SEXP ) {
116+ attrib_for_each ( src, |tag, val| unsafe {
117+ libr:: Rf_setAttrib ( dst, tag, val) ;
118+ } ) ;
119+ }
120+
121+ // --- Compat polyfills for older R ---
122+
66123mod compat {
67124 use libr:: SEXP ;
68125
@@ -73,4 +130,12 @@ mod compat {
73130 libr:: SET_CLOENV ( out, env) ;
74131 out
75132 }
133+
134+ pub unsafe fn map_attrib < F : FnMut ( SEXP , SEXP ) > ( x : SEXP , f : & mut F ) {
135+ let mut node = libr:: ATTRIB ( x) ;
136+ while node != libr:: R_NilValue {
137+ f ( libr:: TAG ( node) , libr:: CAR ( node) ) ;
138+ node = libr:: CDR ( node) ;
139+ }
140+ }
76141}
0 commit comments