r/adbcdrivermanager/src/radbc.h (115 lines of code) (raw):

// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. #pragma once #include <R.h> #include <Rinternals.h> template <typename T> static inline const char* adbc_xptr_class(); template <> inline const char* adbc_xptr_class<AdbcError>() { return "adbc_error"; } template <> inline const char* adbc_xptr_class<AdbcDriver>() { return "adbc_driver"; } template <> inline const char* adbc_xptr_class<AdbcDatabase>() { return "adbc_database"; } template <> inline const char* adbc_xptr_class<AdbcConnection>() { return "adbc_connection"; } template <> inline const char* adbc_xptr_class<AdbcStatement>() { return "adbc_statement"; } template <> inline const char* adbc_xptr_class<ArrowArrayStream>() { return "nanoarrow_array_stream"; } template <> inline const char* adbc_xptr_class<ArrowArray>() { return "nanoarrow_array"; } template <> inline const char* adbc_xptr_class<ArrowSchema>() { return "nanoarrow_schema"; } template <typename T> static inline T* adbc_from_xptr(SEXP xptr) { if (!Rf_inherits(xptr, adbc_xptr_class<T>())) { Rf_error("Expected external pointer with class '%s'", adbc_xptr_class<T>()); } T* ptr = reinterpret_cast<T*>(R_ExternalPtrAddr(xptr)); if (ptr == nullptr) { Rf_error("Can't convert external pointer to NULL to T*"); } return ptr; } template <typename T> static inline SEXP adbc_allocate_xptr(SEXP shelter_sexp = R_NilValue) { void* ptr = malloc(sizeof(T)); if (ptr == nullptr) { Rf_error("Failed to allocate T"); } memset(ptr, 0, sizeof(T)); SEXP xptr = PROTECT(R_MakeExternalPtr(ptr, R_NilValue, shelter_sexp)); SEXP xptr_class = PROTECT(Rf_allocVector(STRSXP, 2)); SET_STRING_ELT(xptr_class, 0, Rf_mkChar(adbc_xptr_class<T>())); SET_STRING_ELT(xptr_class, 1, Rf_mkChar("adbc_xptr")); Rf_setAttrib(xptr, R_ClassSymbol, xptr_class); UNPROTECT(1); SEXP new_env_sym = PROTECT(Rf_install("new_env")); SEXP new_env_call = PROTECT(Rf_lang1(new_env_sym)); SEXP pkg_chr = PROTECT(Rf_mkString("adbcdrivermanager")); SEXP pkg_ns = PROTECT(R_FindNamespace(pkg_chr)); SEXP new_env = PROTECT(Rf_eval(new_env_call, pkg_ns)); R_SetExternalPtrTag(xptr, new_env); UNPROTECT(5); UNPROTECT(1); return xptr; } template <typename T> static inline void adbc_xptr_default_finalize(SEXP xptr) { T* ptr = reinterpret_cast<T*>(R_ExternalPtrAddr(xptr)); if (ptr != nullptr) { free(ptr); } } static inline void adbc_xptr_move_attrs(SEXP xptr_old, SEXP xptr_new) { SEXP cls_old = PROTECT(Rf_getAttrib(xptr_old, R_ClassSymbol)); SEXP tag_old = PROTECT(R_ExternalPtrTag(xptr_old)); SEXP prot_old = PROTECT(R_ExternalPtrProtected(xptr_old)); SEXP tag_new = PROTECT(R_ExternalPtrTag(xptr_new)); SEXP prot_new = PROTECT(R_ExternalPtrProtected(xptr_new)); Rf_setAttrib(xptr_new, R_ClassSymbol, cls_old); R_SetExternalPtrTag(xptr_new, tag_old); R_SetExternalPtrProtected(xptr_new, prot_old); // Don't change the class of the original object...not necessary for // lifecycle management and potentially very confusing R_SetExternalPtrTag(xptr_old, tag_new); R_SetExternalPtrProtected(xptr_old, prot_new); UNPROTECT(5); } static inline const char* adbc_as_const_char(SEXP sexp) { if (TYPEOF(sexp) != STRSXP || Rf_length(sexp) != 1) { Rf_error("Expected character(1) for conversion to const char*"); } SEXP item = STRING_ELT(sexp, 0); if (item == NA_STRING) { Rf_error("Can't convert NA_character_ to const char*"); } return Rf_translateCharUTF8(item); } static inline int adbc_as_int(SEXP sexp) { if (Rf_length(sexp) == 1) { switch (TYPEOF(sexp)) { case REALSXP: return REAL(sexp)[0]; case INTSXP: return INTEGER(sexp)[0]; } } Rf_error("Expected integer(1) or double(1) for conversion to int"); } static inline SEXP adbc_wrap_status(AdbcStatusCode code) { return Rf_ScalarInteger(code); }