blob: 1f4d7ecde65cb1c179395b5eaf14879abf35bc73 [file] [log] [blame]
# 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.
#' Danger zone: low-level pointer operations
#'
#' The [nanoarrow_schema][as_nanoarrow_schema],
#' [nanoarrow_array][as_nanoarrow_array],
#' and [nanoarrow_array_stream][as_nanoarrow_array_stream] classes are
#' represented in R as external pointers (`EXTPTRSXP`). When these objects
#' go out of scope (i.e., when they are garbage collected or shortly
#' thereafter), the underlying object's `release()` callback is called if
#' the underlying pointer is non-null and if the `release()` callback is
#' non-null.
#'
#' When interacting with other C Data Interface implementations, it is
#' important to keep in mind that the R object wrapping these pointers is
#' always passed by reference (because it is an external pointer) and may
#' be referred to by another R object (e.g., an element in a `list()` or as a
#' variable assigned in a user's environment). When importing a schema,
#' array, or array stream into nanoarrow this is not a problem: the R object
#' takes ownership of the lifecycle and memory is released when the R
#' object is garbage collected. In this case, one can use
#' [nanoarrow_pointer_move()] where `ptr_dst` was created using
#' `nanoarrow_allocate_*()`.
#'
#' The case of exporting is more complicated and as such has a dedicated
#' function, [nanoarrow_pointer_export()], that implements different logic
#' schemas, arrays, and array streams:
#'
#' - Schema objects are (deep) copied such that a fresh copy of the schema
#' is exported and made the responsibility of some other C data interface
#' implementation.
#' - Array objects are exported as a shell around the original array that
#' preserves a reference to the R object. This ensures that the buffers
#' and children pointed to by the array are not copied and that any references
#' to the original array are not invalidated.
#' - Array stream objects are moved: the responsibility for the object is
#' transferred to the other C data interface implementation and any
#' references to the original R object are invalidated. Because these
#' objects are mutable, this is typically what you want (i.e., you should
#' not be pulling arrays from a stream accidentally from two places).
#'
#' If you know the lifecycle of your object (i.e., you created the R object
#' yourself and never passed references to it elsewhere), you can slightly
#' more efficiently call [nanoarrow_pointer_move()] for all three pointer
#' types.
#'
#' @param ptr,ptr_src,ptr_dst An external pointer to a `struct ArrowSchema`,
#' `struct ArrowArray`, or `struct ArrowArrayStream`.
#' @param protected An object whose scope must outlive that of `ptr`. This is
#' useful for array streams since at least two specifications involving the
#' array stream specify that the stream is only valid for the lifecycle of
#' another object (e.g., an AdbcStatement or OGRDataset).
#' @return
#' - `nanoarrow_pointer_is_valid()` returns TRUE if the pointer is non-null
#' and has a non-null release callback.
#' - `nanoarrow_pointer_addr_dbl()` and `nanoarrow_pointer_addr_chr()` return
#' pointer representations that may be helpful to facilitate moving or
#' exporting nanoarrow objects to other libraries.
#' - `nanoarrow_pointer_addr_pretty()` gives a pointer representation suitable
#' for printing or error messages.
#' - `nanoarrow_pointer_release()` returns `ptr`, invisibly.
#' - `nanoarrow_pointer_move()` and `nanoarrow_pointer_export()` reeturn
#' `ptr_dst`, invisibly.
#' - `nanoarrow_allocate_array()`, `nanoarrow_allocate_schema()`, and
#' `nanoarrow_allocate_array_stream()` return an
#' [array][as_nanoarrow_array], a [schema][as_nanoarrow_schema], and an
#' [array stream][as_nanoarrow_array_stream], respectively.
#' @export
#'
nanoarrow_pointer_is_valid <- function(ptr) {
.Call(nanoarrow_c_pointer_is_valid, ptr)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_pointer_addr_dbl <- function(ptr) {
.Call(nanoarrow_c_pointer_addr_dbl, ptr)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_pointer_addr_chr <- function(ptr) {
.Call(nanoarrow_c_pointer_addr_chr, ptr)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_pointer_addr_pretty <- function(ptr) {
.Call(nanoarrow_c_pointer_addr_pretty, ptr)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_pointer_release <- function(ptr) {
invisible(.Call(nanoarrow_c_pointer_release, ptr))
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_pointer_move <- function(ptr_src, ptr_dst) {
invisible(.Call(nanoarrow_c_pointer_move, ptr_src, ptr_dst))
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_pointer_export <- function(ptr_src, ptr_dst) {
if (inherits(ptr_src, "nanoarrow_schema")) {
.Call(nanoarrow_c_export_schema, ptr_src, ptr_dst)
} else if (inherits(ptr_src, "nanoarrow_array")) {
.Call(nanoarrow_c_export_array, ptr_src, ptr_dst)
} else if (inherits(ptr_src, "nanoarrow_array_stream")) {
.Call(nanoarrow_c_export_array_stream, ptr_src, ptr_dst)
} else {
stop(
"`ptr_src` must inherit from 'nanoarrow_schema', 'nanoarrow_array', or 'nanoarrow_array_stream'"
)
}
invisible(ptr_dst)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_allocate_schema <- function() {
.Call(nanoarrow_c_allocate_schema)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_allocate_array <- function() {
.Call(nanoarrow_c_allocate_array)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_allocate_array_stream <- function() {
.Call(nanoarrow_c_allocate_array_stream)
}
#' @rdname nanoarrow_pointer_is_valid
#' @export
nanoarrow_pointer_set_protected <- function(ptr_src, protected) {
if (!inherits(ptr_src, c("nanoarrow_schema", "nanoarrow_array", "nanoarrow_array_stream"))) {
stop(
"`ptr_src` must inherit from 'nanoarrow_schema', 'nanoarrow_array', or 'nanoarrow_array_stream'"
)
}
.Call(nanoarrow_c_pointer_set_protected, ptr_src, protected)
invisible(ptr_src)
}