Skip to content

Commit 09d151b

Browse files
committed
Preserve type of row names in vec_ptype()
Extracted from #1020
1 parent 87f4bd8 commit 09d151b

File tree

3 files changed

+33
-6
lines changed

3 files changed

+33
-6
lines changed

src/type.c

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
#include "vctrs.h"
2-
#include "utils.h"
2+
#include "arg-counter.h"
33
#include "ptype-common.h"
44
#include "ptype2.h"
5-
#include "arg-counter.h"
5+
#include "type-data-frame.h"
6+
#include "utils.h"
67

78
// Initialised at load time
89
static SEXP syms_vec_ptype_finalise_dispatch = NULL;
@@ -11,6 +12,7 @@ static SEXP fns_vec_ptype_finalise_dispatch = NULL;
1112

1213
static inline SEXP vec_ptype_slice(SEXP x, SEXP empty);
1314
static SEXP s3_type(SEXP x, struct vctrs_arg* x_arg);
15+
static SEXP df_ptype(SEXP x, bool bare);
1416

1517
// [[ register() ]]
1618
SEXP vctrs_ptype(SEXP x, SEXP x_arg) {
@@ -32,7 +34,7 @@ SEXP vec_ptype(SEXP x, struct vctrs_arg* x_arg) {
3234
case vctrs_type_character: return vec_ptype_slice(x, vctrs_shared_empty_chr);
3335
case vctrs_type_raw: return vec_ptype_slice(x, vctrs_shared_empty_raw);
3436
case vctrs_type_list: return vec_ptype_slice(x, vctrs_shared_empty_list);
35-
case vctrs_type_dataframe: return bare_df_map(x, &col_ptype);
37+
case vctrs_type_dataframe: return df_ptype(x, true);
3638
case vctrs_type_s3: return s3_type(x, x_arg);
3739
case vctrs_type_scalar: stop_scalar_type(x, x_arg);
3840
}
@@ -54,10 +56,10 @@ static inline SEXP vec_ptype_slice(SEXP x, SEXP empty) {
5456
static SEXP s3_type(SEXP x, struct vctrs_arg* x_arg) {
5557
switch (class_type(x)) {
5658
case vctrs_class_bare_tibble:
57-
return bare_df_map(x, &col_ptype);
59+
return df_ptype(x, true);
5860

5961
case vctrs_class_data_frame:
60-
return df_map(x, &col_ptype);
62+
return df_ptype(x, false);
6163

6264
case vctrs_class_bare_data_frame:
6365
Rf_errorcall(R_NilValue, "Internal error: Bare data frames should be handled by `vec_ptype()`");
@@ -77,6 +79,24 @@ static SEXP s3_type(SEXP x, struct vctrs_arg* x_arg) {
7779
return vec_slice(x, R_NilValue);
7880
}
7981

82+
SEXP df_ptype(SEXP x, bool bare) {
83+
SEXP row_nms = PROTECT(df_rownames(x));
84+
85+
SEXP ptype = R_NilValue;
86+
if (bare) {
87+
ptype = PROTECT(bare_df_map(x, &col_ptype));
88+
} else {
89+
ptype = PROTECT(df_map(x, &col_ptype));
90+
}
91+
92+
if (TYPEOF(row_nms) == STRSXP) {
93+
Rf_setAttrib(ptype, R_RowNamesSymbol, vctrs_shared_empty_chr);
94+
}
95+
96+
UNPROTECT(2);
97+
return ptype;
98+
}
99+
80100
static SEXP vec_ptype_finalise_unspecified(SEXP x);
81101
static SEXP vec_ptype_finalise_dispatch(SEXP x);
82102

tests/testthat/test-type.R

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,11 @@ test_that("vec_ptype_finalise() requires vector types", {
221221
expect_error(vec_ptype_finalise(quote(name)), class = "vctrs_error_scalar_type")
222222
expect_error(vec_ptype_finalise(foobar()), class = "vctrs_error_scalar_type")
223223
})
224+
225+
# This might change in the future if we decide that prototypes don't
226+
# have names
227+
test_that("vec_ptype() preserves type of names and row names", {
228+
expect_identical(vec_ptype(c(foo = 1)), named(dbl()))
229+
expect_identical(vec_ptype(mtcars), mtcars[0, ])
230+
expect_identical(vec_ptype(foobar(mtcars)), foobar(mtcars[0, ]))
231+
})

tests/testthat/test-type2.R

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,6 @@ test_that("vec_ptype2() methods get prototypes", {
296296
expect_identical(x, foobar(int()))
297297
expect_identical(y, foobar(chr()))
298298

299-
skip("Figure out what to do with row names in `vec_ptype()`")
300299
vec_ptype2(foobar(mtcars), foobar(iris))
301300
expect_identical(x, foobar(mtcars[0, , drop = FALSE]))
302301
expect_identical(y, foobar(iris[0, , drop = FALSE]))

0 commit comments

Comments
 (0)