@@ -19,7 +19,6 @@ use libr::*;
19
19
use crate :: error:: Error ;
20
20
use crate :: exec:: RFunction ;
21
21
use crate :: exec:: RFunctionExt ;
22
- use crate :: protect:: RProtect ;
23
22
use crate :: r_inherits;
24
23
use crate :: r_symbol;
25
24
use crate :: size:: r_size;
@@ -31,7 +30,6 @@ use crate::utils::r_is_altrep;
31
30
use crate :: utils:: r_is_null;
32
31
use crate :: utils:: r_is_object;
33
32
use crate :: utils:: r_is_s4;
34
- use crate :: utils:: r_names;
35
33
use crate :: utils:: r_str_to_owned_utf8;
36
34
use crate :: utils:: r_typeof;
37
35
@@ -460,39 +458,64 @@ impl RObject {
460
458
/// Gets a vector containing names for the object's values (from the `names`
461
459
/// attribute). Returns `None` if the object's value(s) don't have names.
462
460
pub fn names ( & self ) -> Option < Vec < Option < String > > > {
463
- let names = r_names ( self . sexp ) ;
464
- let names = RObject :: from ( names) ;
465
- match names. kind ( ) {
466
- STRSXP => Vec :: < Option < String > > :: try_from ( names) . ok ( ) ,
467
- _ => None ,
461
+ match self . get_attribute_names ( ) {
462
+ Some ( names) => match names. kind ( ) {
463
+ STRSXP => Vec :: < Option < String > > :: try_from ( names) . ok ( ) ,
464
+ _ => None ,
465
+ } ,
466
+ None => None ,
468
467
}
469
468
}
470
469
471
- /// Gets a named attribute from the object. Returns `None` if the attribute
472
- /// doesn't exist.
473
- pub fn attr ( & self , name : & str ) -> Option < RObject > {
474
- let val = unsafe { Rf_getAttrib ( self . sexp , r_symbol ! ( name) ) } ;
475
- if r_is_null ( val) {
476
- None
477
- } else {
478
- Some ( RObject :: new ( val) )
479
- }
480
- }
481
-
482
- pub fn set_attr ( & self , name : & str , value : SEXP ) {
470
+ pub fn set_attribute ( & self , name : & str , value : SEXP ) {
483
471
unsafe {
484
472
Rf_protect ( value) ;
485
473
Rf_setAttrib ( self . sexp , r_symbol ! ( name) , value) ;
486
474
Rf_unprotect ( 1 ) ;
487
475
}
488
476
}
489
477
478
+ /// Gets a named attribute from the object. Returns `None` if the attribute
479
+ /// was `NULL`.
480
+ pub fn get_attribute ( & self , name : & str ) -> Option < RObject > {
481
+ self . get_attribute_from_symbol ( unsafe { r_symbol ! ( name) } )
482
+ }
483
+
484
+ /// Gets the [R_NamesSymbol] attribute from the object. Returns `None` if there are no
485
+ /// names.
486
+ pub fn get_attribute_names ( & self ) -> Option < RObject > {
487
+ self . get_attribute_from_symbol ( unsafe { R_NamesSymbol } )
488
+ }
489
+
490
+ /// Gets the [R_RowNamesSymbol] attribute from the object. Returns `None` if there are
491
+ /// no row names.
492
+ ///
493
+ /// # Notes
494
+ ///
495
+ /// Note that [Rf_getAttrib()] will turn compact row names of the form `c(NA, -5)`
496
+ /// into ALTREP compact intrange objects. If you really need to avoid this, use
497
+ /// `.row_names_info(x, 0L)` instead, which goes through `getAttrib0()`, but note that
498
+ /// R core frowns on this.
499
+ /// https://github.com/wch/r-source/blob/e11e04d1f9966551991569b43da2ba6ab2251f30/src/main/attrib.c#L177-L187
500
+ pub fn get_attribute_row_names ( & self ) -> Option < RObject > {
501
+ self . get_attribute_from_symbol ( unsafe { R_RowNamesSymbol } )
502
+ }
503
+
504
+ fn get_attribute_from_symbol ( & self , symbol : SEXP ) -> Option < RObject > {
505
+ let out = unsafe { Rf_getAttrib ( self . sexp , symbol) } ;
506
+ if r_is_null ( out) {
507
+ None
508
+ } else {
509
+ Some ( RObject :: new ( out) )
510
+ }
511
+ }
512
+
490
513
pub fn inherits ( & self , class : & str ) -> bool {
491
514
return r_inherits ( self . sexp , class) ;
492
515
}
493
516
494
517
pub fn class ( & self ) -> harp:: Result < Option < Vec < String > > > {
495
- let Some ( class) = self . attr ( "class" ) else {
518
+ let Some ( class) = self . get_attribute ( "class" ) else {
496
519
return Ok ( None ) ;
497
520
} ;
498
521
@@ -1050,28 +1073,26 @@ impl TryFrom<&Vec<i32>> for RObject {
1050
1073
impl TryFrom < RObject > for HashMap < String , String > {
1051
1074
type Error = crate :: error:: Error ;
1052
1075
fn try_from ( value : RObject ) -> Result < Self , Self :: Error > {
1053
- unsafe {
1054
- r_assert_type ( * value, & [ STRSXP , VECSXP ] ) ?;
1055
-
1056
- let mut protect = RProtect :: new ( ) ;
1057
- let names = protect. add ( r_names ( * value) ) ;
1058
- r_assert_type ( names, & [ STRSXP ] ) ?;
1076
+ r_assert_type ( value. sexp , & [ STRSXP , VECSXP ] ) ?;
1059
1077
1060
- let value = protect. add ( Rf_coerceVector ( * value, STRSXP ) ) ;
1078
+ let Some ( names) = value. get_attribute_names ( ) else {
1079
+ return Err ( Error :: UnexpectedType ( NILSXP , vec ! [ STRSXP ] ) ) ;
1080
+ } ;
1061
1081
1062
- let n = Rf_xlength ( names) ;
1063
- let mut map = HashMap :: < String , String > :: with_capacity ( n as usize ) ;
1082
+ let value = RObject :: new ( unsafe { Rf_coerceVector ( value. sexp , STRSXP ) } ) ;
1064
1083
1065
- for i in ( 0 ..Rf_xlength ( names) ) . rev ( ) {
1066
- // Translate the name and value into Rust strings.
1067
- let lhs = r_chr_get_owned_utf8 ( names, i) ?;
1068
- let rhs = r_chr_get_owned_utf8 ( value, i) ?;
1084
+ let n = names. length ( ) ;
1085
+ let mut map = HashMap :: < String , String > :: with_capacity ( n as usize ) ;
1069
1086
1070
- map. insert ( lhs, rhs) ;
1071
- }
1087
+ for i in ( 0 ..n) . rev ( ) {
1088
+ // Translate the name and value into Rust strings.
1089
+ let lhs = r_chr_get_owned_utf8 ( names. sexp , i) ?;
1090
+ let rhs = r_chr_get_owned_utf8 ( value. sexp , i) ?;
1072
1091
1073
- Ok ( map)
1092
+ map. insert ( lhs , rhs ) ;
1074
1093
}
1094
+
1095
+ Ok ( map)
1075
1096
}
1076
1097
}
1077
1098
@@ -1080,28 +1101,26 @@ impl TryFrom<RObject> for HashMap<String, String> {
1080
1101
impl TryFrom < RObject > for HashMap < String , i32 > {
1081
1102
type Error = crate :: error:: Error ;
1082
1103
fn try_from ( value : RObject ) -> Result < Self , Self :: Error > {
1083
- unsafe {
1084
- r_assert_type ( * value, & [ INTSXP , VECSXP ] ) ?;
1104
+ r_assert_type ( * value, & [ INTSXP , VECSXP ] ) ?;
1085
1105
1086
- let mut protect = RProtect :: new ( ) ;
1087
- let names = protect . add ( r_names ( * value ) ) ;
1088
- r_assert_type ( names , & [ STRSXP ] ) ? ;
1106
+ let Some ( names ) = value . get_attribute_names ( ) else {
1107
+ return Err ( Error :: UnexpectedType ( NILSXP , vec ! [ STRSXP ] ) ) ;
1108
+ } ;
1089
1109
1090
- let value = protect . add ( Rf_coerceVector ( * value, INTSXP ) ) ;
1110
+ let value = RObject :: new ( unsafe { Rf_coerceVector ( value. sexp , INTSXP ) } ) ;
1091
1111
1092
- let n = Rf_xlength ( names) ;
1093
- let mut map = HashMap :: < String , i32 > :: with_capacity ( n as usize ) ;
1112
+ let n = names. length ( ) ;
1113
+ let mut map = HashMap :: < String , i32 > :: with_capacity ( n as usize ) ;
1094
1114
1095
- for i in ( 0 ..Rf_xlength ( names ) ) . rev ( ) {
1096
- // Translate the name and value into Rust strings.
1097
- let name = r_chr_get_owned_utf8 ( names, i) ?;
1098
- let val = r_int_get ( value, i) ;
1115
+ for i in ( 0 ..n ) . rev ( ) {
1116
+ // Translate the name and value into Rust strings.
1117
+ let name = r_chr_get_owned_utf8 ( names. sexp , i) ?;
1118
+ let val = r_int_get ( value. sexp , i) ;
1099
1119
1100
- map. insert ( name, val) ;
1101
- }
1102
-
1103
- Ok ( map)
1120
+ map. insert ( name, val) ;
1104
1121
}
1122
+
1123
+ Ok ( map)
1105
1124
}
1106
1125
}
1107
1126
@@ -1110,23 +1129,23 @@ impl TryFrom<RObject> for HashMap<String, i32> {
1110
1129
impl TryFrom < RObject > for HashMap < String , RObject > {
1111
1130
type Error = crate :: error:: Error ;
1112
1131
fn try_from ( value : RObject ) -> Result < Self , Self :: Error > {
1113
- unsafe {
1114
- let mut protect = RProtect :: new ( ) ;
1115
- let names = protect. add ( r_names ( * value) ) ;
1116
- r_assert_type ( names, & [ STRSXP ] ) ?;
1117
-
1118
- let n = Rf_xlength ( names) ;
1119
- let mut map = HashMap :: < String , RObject > :: with_capacity ( n as usize ) ;
1120
-
1121
- // iterate in the reverse order to keep the first occurence of a name
1122
- for i in ( 0 ..n) . rev ( ) {
1123
- let name = r_chr_get_owned_utf8 ( names, i) ?;
1124
- let value: RObject = RObject :: new ( VECTOR_ELT ( * value, i) ) ;
1125
- map. insert ( name, value) ;
1126
- }
1132
+ r_assert_type ( * value, & [ VECSXP ] ) ?;
1127
1133
1128
- Ok ( map)
1134
+ let Some ( names) = value. get_attribute_names ( ) else {
1135
+ return Err ( Error :: UnexpectedType ( NILSXP , vec ! [ STRSXP ] ) ) ;
1136
+ } ;
1137
+
1138
+ let n = names. length ( ) ;
1139
+ let mut map = HashMap :: < String , RObject > :: with_capacity ( n as usize ) ;
1140
+
1141
+ // iterate in the reverse order to keep the first occurence of a name
1142
+ for i in ( 0 ..n) . rev ( ) {
1143
+ let name = r_chr_get_owned_utf8 ( names. sexp , i) ?;
1144
+ let value = RObject :: new ( list_get ( value. sexp , i) ) ;
1145
+ map. insert ( name, value) ;
1129
1146
}
1147
+
1148
+ Ok ( map)
1130
1149
}
1131
1150
}
1132
1151
0 commit comments