blob: af725a3a23cc18e8978ec8753b8d1095ca3733cd [file]
// 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.
use crate::{
byte_buffer::ByteBuffer,
entry::into_entry_list_ptr,
error::OpenDALError,
executor::executor_or_default,
metadata::OpendalMetadata,
operator_info::{OpendalOperatorInfo, into_operator_info},
options::{parse_list_options, parse_read_options, parse_stat_options, parse_write_options},
presign::into_presigned_request_ptr,
result::{
OpendalEntryListResult, OpendalMetadataResult, OpendalOperatorInfoResult,
OpendalOperatorResult, OpendalOptionsResult, OpendalPresignedRequestResult,
OpendalReadResult, OpendalResult,
},
utils::{collect_options, require_callback, require_cstr, require_data_ptr, require_operator},
validators::prelude::{
validate_concurrent_limit_options, validate_retry_options, validate_timeout_options,
},
};
use std::collections::HashMap;
use std::ffi::c_void;
use std::os::raw::c_char;
use std::time::Duration;
/// Callback signature for async write completion.
///
/// The callback is provided by the .NET side and must remain valid until
/// invoked by Rust.
type WriteCallback = extern "C" fn(context: i64, result: OpendalResult);
type ReadCallback = extern "C" fn(context: i64, result: OpendalReadResult);
type StatCallback = extern "C" fn(context: i64, result: OpendalMetadataResult);
type ListCallback = extern "C" fn(context: i64, result: OpendalEntryListResult);
type PresignCallback = extern "C" fn(context: i64, result: OpendalPresignedRequestResult);
/// Build constructor options from raw C string key/value arrays.
///
/// On success, the returned pointer must be released by
/// `constructor_option_free`.
/// # Safety
///
/// - When `len > 0`, `keys` and `values` must be non-null pointers to arrays
/// containing at least `len` C-string pointers.
/// - Each key/value entry must be a valid null-terminated UTF-8 string.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn constructor_option_build(
keys: *const *const c_char,
values: *const *const c_char,
len: usize,
) -> OpendalOptionsResult {
match unsafe { collect_options(keys, values, len) } {
Ok(options) => OpendalOptionsResult::ok(Box::into_raw(Box::new(options)) as *mut c_void),
Err(error) => OpendalOptionsResult::from_error(error),
}
}
/// # Safety
///
/// - `options` must be null or a pointer returned by
/// `constructor_option_build`.
/// - This function must be called at most once for the same pointer.
#[unsafe(no_mangle)]
pub extern "C" fn constructor_option_free(options: *mut HashMap<String, String>) {
if options.is_null() {
return;
}
unsafe {
drop(Box::from_raw(options));
}
}
/// Build read options from raw C string key/value arrays.
///
/// On success, the returned pointer must be released by `read_option_free`.
/// # Safety
///
/// - When `len > 0`, `keys` and `values` must be non-null pointers to arrays
/// containing at least `len` C-string pointers.
/// - Each key/value entry must be a valid null-terminated UTF-8 string.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn read_option_build(
keys: *const *const c_char,
values: *const *const c_char,
len: usize,
) -> OpendalOptionsResult {
match unsafe { collect_options(keys, values, len) }
.and_then(|values| parse_read_options(&values))
{
Ok(options) => OpendalOptionsResult::ok(Box::into_raw(Box::new(options)) as *mut c_void),
Err(error) => OpendalOptionsResult::from_error(error),
}
}
/// # Safety
///
/// - `options` must be null or a pointer returned by `read_option_build`.
/// - This function must be called at most once for the same pointer.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn read_option_free(options: *mut opendal::options::ReadOptions) {
if options.is_null() {
return;
}
unsafe {
drop(Box::from_raw(options));
}
}
/// Build write options from raw C string key/value arrays.
///
/// On success, the returned pointer must be released by `write_option_free`.
/// # Safety
///
/// - When `len > 0`, `keys` and `values` must be non-null pointers to arrays
/// containing at least `len` C-string pointers.
/// - Each key/value entry must be a valid null-terminated UTF-8 string.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn write_option_build(
keys: *const *const c_char,
values: *const *const c_char,
len: usize,
) -> OpendalOptionsResult {
match unsafe { collect_options(keys, values, len) }
.and_then(|values| parse_write_options(&values))
{
Ok(options) => OpendalOptionsResult::ok(Box::into_raw(Box::new(options)) as *mut c_void),
Err(error) => OpendalOptionsResult::from_error(error),
}
}
/// # Safety
///
/// - `options` must be null or a pointer returned by `write_option_build`.
/// - This function must be called at most once for the same pointer.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn write_option_free(options: *mut opendal::options::WriteOptions) {
if options.is_null() {
return;
}
unsafe {
drop(Box::from_raw(options));
}
}
/// Build stat options from raw C string key/value arrays.
///
/// On success, the returned pointer must be released by `stat_option_free`.
/// # Safety
///
/// - When `len > 0`, `keys` and `values` must be non-null pointers to arrays
/// containing at least `len` C-string pointers.
/// - Each key/value entry must be a valid null-terminated UTF-8 string.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn stat_option_build(
keys: *const *const c_char,
values: *const *const c_char,
len: usize,
) -> OpendalOptionsResult {
match unsafe { collect_options(keys, values, len) }
.and_then(|values| parse_stat_options(&values))
{
Ok(options) => OpendalOptionsResult::ok(Box::into_raw(Box::new(options)) as *mut c_void),
Err(error) => OpendalOptionsResult::from_error(error),
}
}
/// # Safety
///
/// - `options` must be null or a pointer returned by `stat_option_build`.
/// - This function must be called at most once for the same pointer.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn stat_option_free(options: *mut opendal::options::StatOptions) {
if options.is_null() {
return;
}
unsafe {
drop(Box::from_raw(options));
}
}
/// Build list options from raw C string key/value arrays.
///
/// On success, the returned pointer must be released by `list_option_free`.
/// # Safety
///
/// - When `len > 0`, `keys` and `values` must be non-null pointers to arrays
/// containing at least `len` C-string pointers.
/// - Each key/value entry must be a valid null-terminated UTF-8 string.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn list_option_build(
keys: *const *const c_char,
values: *const *const c_char,
len: usize,
) -> OpendalOptionsResult {
match unsafe { collect_options(keys, values, len) }
.and_then(|values| parse_list_options(&values))
{
Ok(options) => OpendalOptionsResult::ok(Box::into_raw(Box::new(options)) as *mut c_void),
Err(error) => OpendalOptionsResult::from_error(error),
}
}
/// # Safety
///
/// - `options` must be null or a pointer returned by `list_option_build`.
/// - This function must be called at most once for the same pointer.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn list_option_free(options: *mut opendal::options::ListOptions) {
if options.is_null() {
return;
}
unsafe {
drop(Box::from_raw(options));
}
}
/// Construct an OpenDAL operator instance from a scheme and key/value options.
///
/// Returns a pointer that must be released with `operator_free`.
/// # Safety
///
/// - `scheme` must be a valid null-terminated UTF-8 string.
/// - When `len > 0`, `keys` and `values` must be non-null and point to arrays
/// of at least `len` entries.
/// - Every key/value entry in those arrays must be a valid null-terminated
/// UTF-8 string.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn operator_construct(
scheme: *const c_char,
options: *const HashMap<String, String>,
) -> OpendalOperatorResult {
match operator_construct_inner(scheme, options) {
Ok(op) => OpendalOperatorResult::ok(op),
Err(error) => OpendalOperatorResult::from_error(error),
}
}
fn operator_construct_inner(
scheme: *const c_char,
options: *const HashMap<String, String>,
) -> Result<*mut c_void, OpenDALError> {
let scheme = require_cstr(scheme, "scheme")?;
let options = if options.is_null() {
HashMap::default()
} else {
unsafe { (&*options).clone() }
};
let op =
opendal::Operator::via_iter(scheme, options).map_err(OpenDALError::from_opendal_error)?;
Ok(Box::into_raw(Box::new(op)) as *mut c_void)
}
/// # Safety
///
/// - `op` must be either null or a pointer returned by `operator_construct`.
/// - The pointer must not be used after this call.
/// - This function must be called at most once for the same pointer.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn operator_free(op: *mut opendal::Operator) {
if op.is_null() {
return;
}
unsafe {
drop(Box::from_raw(op));
}
}
/// Get operator info payload.
///
/// On success, payload must be released by `opendal_operator_info_result_release`.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn operator_info_get(
op: *const opendal::Operator,
) -> OpendalOperatorInfoResult {
match operator_info_get_inner(op) {
Ok(value) => OpendalOperatorInfoResult::ok(value),
Err(error) => OpendalOperatorInfoResult::from_error(error),
}
}
fn operator_info_get_inner(op: *const opendal::Operator) -> Result<*mut c_void, OpenDALError> {
let op = require_operator(op)?;
let info = into_operator_info(op.info());
Ok(Box::into_raw(Box::new(info)) as *mut c_void)
}
/// # Safety
///
/// - `info` must be either null or a pointer returned by `operator_info_get`.
/// - The pointer must not be used after this call.
/// - This function must be called at most once for the same pointer.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn operator_info_free(info: *mut OpendalOperatorInfo) {
if info.is_null() {
return;
}
unsafe {
let info = Box::from_raw(info);
if !info.scheme.is_null() {
drop(std::ffi::CString::from_raw(info.scheme));
}
if !info.root.is_null() {
drop(std::ffi::CString::from_raw(info.root));
}
if !info.name.is_null() {
drop(std::ffi::CString::from_raw(info.name));
}
}
}
/// Create a new operator layered with retry behavior.
///
/// The current operator is not modified. Returned pointer must be released with
/// `operator_free`.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
#[unsafe(no_mangle)]
pub extern "C" fn operator_layer_retry(
op: *const opendal::Operator,
jitter: bool,
factor: f32,
min_delay_nanos: u64,
max_delay_nanos: u64,
max_times: usize,
) -> OpendalOperatorResult {
match operator_layer_retry_inner(
op,
jitter,
factor,
min_delay_nanos,
max_delay_nanos,
max_times,
) {
Ok(value) => OpendalOperatorResult::ok(value),
Err(error) => OpendalOperatorResult::from_error(error),
}
}
fn operator_layer_retry_inner(
op: *const opendal::Operator,
jitter: bool,
factor: f32,
min_delay_nanos: u64,
max_delay_nanos: u64,
max_times: usize,
) -> Result<*mut c_void, OpenDALError> {
let op = require_operator(op)?;
validate_retry_options(factor, min_delay_nanos, max_delay_nanos)?;
let mut retry = opendal::layers::RetryLayer::new();
retry = retry.with_factor(factor);
retry = retry.with_min_delay(Duration::from_nanos(min_delay_nanos));
retry = retry.with_max_delay(Duration::from_nanos(max_delay_nanos));
retry = retry.with_max_times(max_times);
if jitter {
retry = retry.with_jitter();
}
Ok(Box::into_raw(Box::new(op.clone().layer(retry))) as *mut c_void)
}
/// Create a new operator layered with concurrent-limit behavior.
///
/// The current operator is not modified. Returned pointer must be released with
/// `operator_free`.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
#[unsafe(no_mangle)]
pub extern "C" fn operator_layer_concurrent_limit(
op: *const opendal::Operator,
permits: usize,
) -> OpendalOperatorResult {
match operator_layer_concurrent_limit_inner(op, permits) {
Ok(value) => OpendalOperatorResult::ok(value),
Err(error) => OpendalOperatorResult::from_error(error),
}
}
fn operator_layer_concurrent_limit_inner(
op: *const opendal::Operator,
permits: usize,
) -> Result<*mut c_void, OpenDALError> {
let op = require_operator(op)?;
validate_concurrent_limit_options(permits)?;
let concurrent_limit = opendal::layers::ConcurrentLimitLayer::new(permits);
Ok(Box::into_raw(Box::new(op.clone().layer(concurrent_limit))) as *mut c_void)
}
/// Create a new operator layered with timeout behavior.
///
/// The current operator is not modified. Returned pointer must be released with
/// `operator_free`.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
#[unsafe(no_mangle)]
pub extern "C" fn operator_layer_timeout(
op: *const opendal::Operator,
timeout_nanos: u64,
io_timeout_nanos: u64,
) -> OpendalOperatorResult {
match operator_layer_timeout_inner(op, timeout_nanos, io_timeout_nanos) {
Ok(value) => OpendalOperatorResult::ok(value),
Err(error) => OpendalOperatorResult::from_error(error),
}
}
fn operator_layer_timeout_inner(
op: *const opendal::Operator,
timeout_nanos: u64,
io_timeout_nanos: u64,
) -> Result<*mut c_void, OpenDALError> {
let op = require_operator(op)?;
validate_timeout_options(timeout_nanos, io_timeout_nanos)?;
let timeout = opendal::layers::TimeoutLayer::new()
.with_timeout(Duration::from_nanos(timeout_nanos))
.with_io_timeout(Duration::from_nanos(io_timeout_nanos));
Ok(Box::into_raw(Box::new(op.clone().layer(timeout))) as *mut c_void)
}
/// Duplicate an operator instance.
///
/// Returned pointer must be released with `operator_free`.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
#[unsafe(no_mangle)]
pub extern "C" fn operator_duplicate(op: *const opendal::Operator) -> OpendalOperatorResult {
match operator_duplicate_inner(op) {
Ok(value) => OpendalOperatorResult::ok(value),
Err(error) => OpendalOperatorResult::from_error(error),
}
}
fn operator_duplicate_inner(op: *const opendal::Operator) -> Result<*mut c_void, OpenDALError> {
let op = require_operator(op)?;
Ok(Box::into_raw(Box::new(op.clone())) as *mut c_void)
}
/// Delete `path` synchronously.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
#[unsafe(no_mangle)]
pub extern "C" fn operator_delete(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
) -> OpendalResult {
match operator_delete_inner(op, executor, path) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_delete_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?;
executor
.block_on(op.delete(path))
.map_err(OpenDALError::from_opendal_error)
}
/// Delete `path` asynchronously.
///
/// The callback is invoked exactly once with the final result.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
/// - `callback` must be a valid function pointer and remain callable until invoked.
#[unsafe(no_mangle)]
pub extern "C" fn operator_delete_async(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
callback: Option<WriteCallback>,
context: i64,
) -> OpendalResult {
match operator_delete_async_inner(op, executor, path, callback, context) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_delete_async_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
callback: Option<WriteCallback>,
context: i64,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?.to_string();
let callback = require_callback(callback)?;
let op = op.clone();
executor.spawn(async move {
let result = op
.delete(&path)
.await
.map_err(OpenDALError::from_opendal_error);
callback(
context,
match result {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
},
);
});
Ok(())
}
/// Create directory at `path` synchronously.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
#[unsafe(no_mangle)]
pub extern "C" fn operator_create_dir(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
) -> OpendalResult {
match operator_create_dir_inner(op, executor, path) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_create_dir_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?;
executor
.block_on(op.create_dir(path))
.map_err(OpenDALError::from_opendal_error)
}
/// Create directory at `path` asynchronously.
///
/// The callback is invoked exactly once with the final result.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
/// - `callback` must be a valid function pointer and remain callable until invoked.
#[unsafe(no_mangle)]
pub extern "C" fn operator_create_dir_async(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
callback: Option<WriteCallback>,
context: i64,
) -> OpendalResult {
match operator_create_dir_async_inner(op, executor, path, callback, context) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_create_dir_async_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
callback: Option<WriteCallback>,
context: i64,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?.to_string();
let callback = require_callback(callback)?;
let op = op.clone();
executor.spawn(async move {
let result = op
.create_dir(&path)
.await
.map_err(OpenDALError::from_opendal_error);
callback(
context,
match result {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
},
);
});
Ok(())
}
/// Copy from `source_path` to `target_path` synchronously.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `source_path` and `target_path` must be valid null-terminated UTF-8 strings.
#[unsafe(no_mangle)]
pub extern "C" fn operator_copy(
op: *const opendal::Operator,
executor: *const c_void,
source_path: *const c_char,
target_path: *const c_char,
) -> OpendalResult {
match operator_copy_inner(op, executor, source_path, target_path) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_copy_inner(
op: *const opendal::Operator,
executor: *const c_void,
source_path: *const c_char,
target_path: *const c_char,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let source_path = require_cstr(source_path, "source_path")?;
let target_path = require_cstr(target_path, "target_path")?;
executor
.block_on(op.copy(source_path, target_path))
.map_err(OpenDALError::from_opendal_error)
}
/// Copy from `source_path` to `target_path` asynchronously.
///
/// The callback is invoked exactly once with the final result.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `source_path` and `target_path` must be valid null-terminated UTF-8 strings.
/// - `callback` must be a valid function pointer and remain callable until invoked.
#[unsafe(no_mangle)]
pub extern "C" fn operator_copy_async(
op: *const opendal::Operator,
executor: *const c_void,
source_path: *const c_char,
target_path: *const c_char,
callback: Option<WriteCallback>,
context: i64,
) -> OpendalResult {
match operator_copy_async_inner(op, executor, source_path, target_path, callback, context) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_copy_async_inner(
op: *const opendal::Operator,
executor: *const c_void,
source_path: *const c_char,
target_path: *const c_char,
callback: Option<WriteCallback>,
context: i64,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let source_path = require_cstr(source_path, "source_path")?.to_string();
let target_path = require_cstr(target_path, "target_path")?.to_string();
let callback = require_callback(callback)?;
let op = op.clone();
executor.spawn(async move {
let result = op
.copy(&source_path, &target_path)
.await
.map_err(OpenDALError::from_opendal_error);
callback(
context,
match result {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
},
);
});
Ok(())
}
/// Rename from `source_path` to `target_path` synchronously.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `source_path` and `target_path` must be valid null-terminated UTF-8 strings.
#[unsafe(no_mangle)]
pub extern "C" fn operator_rename(
op: *const opendal::Operator,
executor: *const c_void,
source_path: *const c_char,
target_path: *const c_char,
) -> OpendalResult {
match operator_rename_inner(op, executor, source_path, target_path) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_rename_inner(
op: *const opendal::Operator,
executor: *const c_void,
source_path: *const c_char,
target_path: *const c_char,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let source_path = require_cstr(source_path, "source_path")?;
let target_path = require_cstr(target_path, "target_path")?;
executor
.block_on(op.rename(source_path, target_path))
.map_err(OpenDALError::from_opendal_error)
}
/// Rename from `source_path` to `target_path` asynchronously.
///
/// The callback is invoked exactly once with the final result.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `source_path` and `target_path` must be valid null-terminated UTF-8 strings.
/// - `callback` must be a valid function pointer and remain callable until invoked.
#[unsafe(no_mangle)]
pub extern "C" fn operator_rename_async(
op: *const opendal::Operator,
executor: *const c_void,
source_path: *const c_char,
target_path: *const c_char,
callback: Option<WriteCallback>,
context: i64,
) -> OpendalResult {
match operator_rename_async_inner(op, executor, source_path, target_path, callback, context) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_rename_async_inner(
op: *const opendal::Operator,
executor: *const c_void,
source_path: *const c_char,
target_path: *const c_char,
callback: Option<WriteCallback>,
context: i64,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let source_path = require_cstr(source_path, "source_path")?.to_string();
let target_path = require_cstr(target_path, "target_path")?.to_string();
let callback = require_callback(callback)?;
let op = op.clone();
executor.spawn(async move {
let result = op
.rename(&source_path, &target_path)
.await
.map_err(OpenDALError::from_opendal_error);
callback(
context,
match result {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
},
);
});
Ok(())
}
/// Remove `path` recursively synchronously.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
#[unsafe(no_mangle)]
pub extern "C" fn operator_remove_all(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
) -> OpendalResult {
match operator_remove_all_inner(op, executor, path) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_remove_all_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?;
let options = opendal::options::DeleteOptions {
recursive: true,
..Default::default()
};
executor
.block_on(op.delete_options(path, options))
.map_err(OpenDALError::from_opendal_error)
}
/// Remove `path` recursively asynchronously.
///
/// The callback is invoked exactly once with the final result.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
/// - `callback` must be a valid function pointer and remain callable until invoked.
#[unsafe(no_mangle)]
pub extern "C" fn operator_remove_all_async(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
callback: Option<WriteCallback>,
context: i64,
) -> OpendalResult {
match operator_remove_all_async_inner(op, executor, path, callback, context) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_remove_all_async_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
callback: Option<WriteCallback>,
context: i64,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?.to_string();
let callback = require_callback(callback)?;
let options = opendal::options::DeleteOptions {
recursive: true,
..Default::default()
};
let op = op.clone();
executor.spawn(async move {
let result = op
.delete_options(&path, options)
.await
.map_err(OpenDALError::from_opendal_error);
callback(
context,
match result {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
},
);
});
Ok(())
}
/// Presign read asynchronously.
///
/// The callback is invoked exactly once with the final result.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
/// - `callback` must be a valid function pointer and remain callable until invoked.
#[unsafe(no_mangle)]
pub extern "C" fn operator_presign_read_async(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
expire_nanos: u64,
callback: Option<PresignCallback>,
context: i64,
) -> OpendalResult {
match operator_presign_read_async_inner(op, executor, path, expire_nanos, callback, context) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_presign_read_async_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
expire_nanos: u64,
callback: Option<PresignCallback>,
context: i64,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?.to_string();
let callback = require_callback(callback)?;
let expire = Duration::from_nanos(expire_nanos);
let op = op.clone();
executor.spawn(async move {
let result = op
.presign_read(&path, expire)
.await
.map_err(OpenDALError::from_opendal_error)
.and_then(into_presigned_request_ptr);
callback(
context,
match result {
Ok(value) => OpendalPresignedRequestResult::ok(value),
Err(error) => OpendalPresignedRequestResult::from_error(error),
},
);
});
Ok(())
}
/// Presign write asynchronously.
///
/// The callback is invoked exactly once with the final result.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
/// - `callback` must be a valid function pointer and remain callable until invoked.
#[unsafe(no_mangle)]
pub extern "C" fn operator_presign_write_async(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
expire_nanos: u64,
callback: Option<PresignCallback>,
context: i64,
) -> OpendalResult {
match operator_presign_write_async_inner(op, executor, path, expire_nanos, callback, context) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_presign_write_async_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
expire_nanos: u64,
callback: Option<PresignCallback>,
context: i64,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?.to_string();
let callback = require_callback(callback)?;
let expire = Duration::from_nanos(expire_nanos);
let op = op.clone();
executor.spawn(async move {
let result = op
.presign_write(&path, expire)
.await
.map_err(OpenDALError::from_opendal_error)
.and_then(into_presigned_request_ptr);
callback(
context,
match result {
Ok(value) => OpendalPresignedRequestResult::ok(value),
Err(error) => OpendalPresignedRequestResult::from_error(error),
},
);
});
Ok(())
}
/// Presign stat asynchronously.
///
/// The callback is invoked exactly once with the final result.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
/// - `callback` must be a valid function pointer and remain callable until invoked.
#[unsafe(no_mangle)]
pub extern "C" fn operator_presign_stat_async(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
expire_nanos: u64,
callback: Option<PresignCallback>,
context: i64,
) -> OpendalResult {
match operator_presign_stat_async_inner(op, executor, path, expire_nanos, callback, context) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_presign_stat_async_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
expire_nanos: u64,
callback: Option<PresignCallback>,
context: i64,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?.to_string();
let callback = require_callback(callback)?;
let expire = Duration::from_nanos(expire_nanos);
let op = op.clone();
executor.spawn(async move {
let result = op
.presign_stat(&path, expire)
.await
.map_err(OpenDALError::from_opendal_error)
.and_then(into_presigned_request_ptr);
callback(
context,
match result {
Ok(value) => OpendalPresignedRequestResult::ok(value),
Err(error) => OpendalPresignedRequestResult::from_error(error),
},
);
});
Ok(())
}
/// Presign delete asynchronously.
///
/// The callback is invoked exactly once with the final result.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
/// - `callback` must be a valid function pointer and remain callable until invoked.
#[unsafe(no_mangle)]
pub extern "C" fn operator_presign_delete_async(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
expire_nanos: u64,
callback: Option<PresignCallback>,
context: i64,
) -> OpendalResult {
match operator_presign_delete_async_inner(op, executor, path, expire_nanos, callback, context) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_presign_delete_async_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
expire_nanos: u64,
callback: Option<PresignCallback>,
context: i64,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?.to_string();
let callback = require_callback(callback)?;
let expire = Duration::from_nanos(expire_nanos);
let op = op.clone();
executor.spawn(async move {
let result = op
.presign_delete(&path, expire)
.await
.map_err(OpenDALError::from_opendal_error)
.and_then(into_presigned_request_ptr);
callback(
context,
match result {
Ok(value) => OpendalPresignedRequestResult::ok(value),
Err(error) => OpendalPresignedRequestResult::from_error(error),
},
);
});
Ok(())
}
/// Create an input stream for `path` with read options.
///
/// Returned pointer must be released by `operator_input_stream_free`.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
#[unsafe(no_mangle)]
pub extern "C" fn operator_input_stream_create(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::ReadOptions,
) -> OpendalOperatorResult {
match operator_input_stream_create_inner(op, executor, path, options) {
Ok(value) => OpendalOperatorResult::ok(value),
Err(error) => OpendalOperatorResult::from_error(error),
}
}
fn operator_input_stream_create_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::ReadOptions,
) -> Result<*mut c_void, OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?.to_string();
let options = if options.is_null() {
opendal::options::ReadOptions::default()
} else {
unsafe { (&*options).clone() }
};
let _guard = executor.enter();
let blocking_op =
opendal::blocking::Operator::new(op.clone()).map_err(OpenDALError::from_opendal_error)?;
let reader = blocking_op
.reader_options(&path, opendal::options::ReaderOptions::default())
.map_err(OpenDALError::from_opendal_error)?;
let stream = reader
.into_bytes_iterator(options.range.to_range())
.map_err(OpenDALError::from_opendal_error)?;
Ok(Box::into_raw(Box::new(stream)) as *mut c_void)
}
/// Read next bytes chunk from input stream.
///
/// Returns an empty buffer when EOF is reached.
/// # Safety
///
/// - `stream` must be a valid pointer returned by `operator_input_stream_create`.
#[unsafe(no_mangle)]
pub extern "C" fn operator_input_stream_read_next(
stream: *mut opendal::blocking::StdBytesIterator,
) -> OpendalReadResult {
match operator_input_stream_read_next_inner(stream) {
Ok(buffer) => OpendalReadResult::ok(buffer),
Err(error) => OpendalReadResult::from_error(error),
}
}
fn operator_input_stream_read_next_inner(
stream: *mut opendal::blocking::StdBytesIterator,
) -> Result<ByteBuffer, OpenDALError> {
if stream.is_null() {
return Err(crate::utils::config_invalid_error(
"input stream pointer is null",
));
}
let stream = unsafe { &mut *stream };
let value = stream
.next()
.transpose()
.map_err(|err| {
OpenDALError::from_opendal_error(opendal::Error::new(
opendal::ErrorKind::Unexpected,
err.to_string(),
))
})?
.map(|v| ByteBuffer::from_vec(v.to_vec()))
.unwrap_or_else(ByteBuffer::empty);
Ok(value)
}
/// # Safety
///
/// - `stream` must be null or a pointer returned by `operator_input_stream_create`.
/// - Must be called at most once for the same pointer.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn operator_input_stream_free(
stream: *mut opendal::blocking::StdBytesIterator,
) {
if stream.is_null() {
return;
}
unsafe {
drop(Box::from_raw(stream));
}
}
/// Create an output stream for `path` with write options.
///
/// Returned pointer must be released by `operator_output_stream_free`.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
#[unsafe(no_mangle)]
pub extern "C" fn operator_output_stream_create(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::WriteOptions,
) -> OpendalOperatorResult {
match operator_output_stream_create_inner(op, executor, path, options) {
Ok(value) => OpendalOperatorResult::ok(value),
Err(error) => OpendalOperatorResult::from_error(error),
}
}
fn operator_output_stream_create_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::WriteOptions,
) -> Result<*mut c_void, OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?.to_string();
let options = if options.is_null() {
opendal::options::WriteOptions::default()
} else {
unsafe { (&*options).clone() }
};
let _guard = executor.enter();
let blocking_op =
opendal::blocking::Operator::new(op.clone()).map_err(OpenDALError::from_opendal_error)?;
let stream = blocking_op
.writer_options(&path, options)
.map_err(OpenDALError::from_opendal_error)?;
Ok(Box::into_raw(Box::new(stream)) as *mut c_void)
}
/// Write bytes to output stream.
/// # Safety
///
/// - `stream` must be a valid pointer returned by `operator_output_stream_create`.
/// - When `len > 0`, `data` must be non-null and readable for `len` bytes.
#[unsafe(no_mangle)]
pub extern "C" fn operator_output_stream_write(
stream: *mut opendal::blocking::Writer,
data: *const u8,
len: usize,
) -> OpendalResult {
match operator_output_stream_write_inner(stream, data, len) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_output_stream_write_inner(
stream: *mut opendal::blocking::Writer,
data: *const u8,
len: usize,
) -> Result<(), OpenDALError> {
if stream.is_null() {
return Err(crate::utils::config_invalid_error(
"output stream pointer is null",
));
}
require_data_ptr(data, len)?;
let stream = unsafe { &mut *stream };
let payload = if len == 0 {
&[][..]
} else {
unsafe { std::slice::from_raw_parts(data, len) }
};
stream
.write(payload)
.map(|_| ())
.map_err(OpenDALError::from_opendal_error)
}
/// Flush output stream.
/// # Safety
///
/// - `stream` must be a valid pointer returned by `operator_output_stream_create`.
#[unsafe(no_mangle)]
pub extern "C" fn operator_output_stream_flush(
stream: *mut opendal::blocking::Writer,
) -> OpendalResult {
match operator_output_stream_flush_inner(stream) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_output_stream_flush_inner(
stream: *mut opendal::blocking::Writer,
) -> Result<(), OpenDALError> {
if stream.is_null() {
return Err(crate::utils::config_invalid_error(
"output stream pointer is null",
));
}
Ok(())
}
/// Close output stream.
/// # Safety
///
/// - `stream` must be a valid pointer returned by `operator_output_stream_create`.
#[unsafe(no_mangle)]
pub extern "C" fn operator_output_stream_close(
stream: *mut opendal::blocking::Writer,
) -> OpendalResult {
match operator_output_stream_close_inner(stream) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_output_stream_close_inner(
stream: *mut opendal::blocking::Writer,
) -> Result<(), OpenDALError> {
if stream.is_null() {
return Err(crate::utils::config_invalid_error(
"output stream pointer is null",
));
}
let stream = unsafe { &mut *stream };
stream
.close()
.map(|_| ())
.map_err(OpenDALError::from_opendal_error)
}
/// # Safety
///
/// - `stream` must be null or a pointer returned by `operator_output_stream_create`.
/// - Must be called at most once for the same pointer.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn operator_output_stream_free(stream: *mut opendal::blocking::Writer) {
if stream.is_null() {
return;
}
unsafe {
drop(Box::from_raw(stream));
}
}
/// Write bytes to `path` synchronously with options.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
/// - When `len > 0`, `data` must be non-null and readable for `len` bytes.
/// - When `option_len > 0`, `option_keys` and `option_values` must be valid arrays.
#[unsafe(no_mangle)]
pub extern "C" fn operator_write_with_options(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
data: *const u8,
len: usize,
options: *const opendal::options::WriteOptions,
) -> OpendalResult {
match operator_write_with_options_inner(op, executor, path, data, len, options) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_write_with_options_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
data: *const u8,
len: usize,
options: *const opendal::options::WriteOptions,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?;
require_data_ptr(data, len)?;
let options = if options.is_null() {
opendal::options::WriteOptions::default()
} else {
unsafe { (&*options).clone() }
};
let payload = if len == 0 {
&[][..]
} else {
unsafe { std::slice::from_raw_parts(data, len) }
};
executor
.block_on(op.write_options(path, payload, options))
.map(|_| ())
.map_err(OpenDALError::from_opendal_error)
}
/// Write bytes to `path` asynchronously with options.
///
/// The callback is invoked exactly once with the final result.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
/// - `data.data` must be non-null and readable for `data.len` bytes when `data.len > 0`.
/// - `callback` must be a valid function pointer and remain callable until invoked.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn operator_write_with_options_async(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
data: ByteBuffer,
options: *const opendal::options::WriteOptions,
callback: Option<WriteCallback>,
context: i64,
) -> OpendalResult {
match operator_write_with_options_async_inner(
op, executor, path, data, options, callback, context,
) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_write_with_options_async_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
data: ByteBuffer,
options: *const opendal::options::WriteOptions,
callback: Option<WriteCallback>,
context: i64,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?.to_string();
require_data_ptr(data.data.cast_const(), data.len)?;
let callback = require_callback(callback)?;
let options = if options.is_null() {
opendal::options::WriteOptions::default()
} else {
unsafe { (&*options).clone() }
};
let payload = if data.len == 0 {
Vec::new()
} else {
unsafe { std::slice::from_raw_parts(data.data.cast_const(), data.len) }.to_vec()
};
let op = op.clone();
executor.spawn(async move {
let result = op
.write_options(&path, payload, options)
.await
.map(|_| ())
.map_err(OpenDALError::from_opendal_error);
callback(
context,
match result {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
},
);
});
Ok(())
}
/// Read bytes from `path` synchronously with options.
///
/// On success, the returned buffer must be released with `opendal_read_result_release`.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
/// - When `option_len > 0`, `option_keys` and `option_values` must be valid arrays.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn operator_read_with_options(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::ReadOptions,
) -> OpendalReadResult {
match operator_read_with_options_inner(op, executor, path, options) {
Ok(value) => OpendalReadResult::ok(value),
Err(error) => OpendalReadResult::from_error(error),
}
}
fn operator_read_with_options_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::ReadOptions,
) -> Result<ByteBuffer, OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?;
let options = if options.is_null() {
opendal::options::ReadOptions::default()
} else {
unsafe { (&*options).clone() }
};
let value = executor
.block_on(op.read_options(path, options))
.map(|v| v.to_vec())
.map_err(OpenDALError::from_opendal_error)?;
Ok(ByteBuffer::from_vec(value))
}
/// Read bytes from `path` asynchronously with options.
///
/// The callback is invoked exactly once. On successful reads, the callback
/// result must be released with `opendal_read_result_release`.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
/// - When `option_len > 0`, `option_keys` and `option_values` must be valid arrays.
/// - `callback` must be a valid function pointer and remain callable until invoked.
#[unsafe(no_mangle)]
pub extern "C" fn operator_read_with_options_async(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::ReadOptions,
callback: Option<ReadCallback>,
context: i64,
) -> OpendalResult {
match operator_read_with_options_async_inner(op, executor, path, options, callback, context) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_read_with_options_async_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::ReadOptions,
callback: Option<ReadCallback>,
context: i64,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?.to_string();
let callback = require_callback(callback)?;
let options = if options.is_null() {
opendal::options::ReadOptions::default()
} else {
unsafe { (&*options).clone() }
};
let op = op.clone();
executor.spawn(async move {
let result = op
.read_options(&path, options)
.await
.map(|v| ByteBuffer::from_vec(v.to_vec()))
.map_err(OpenDALError::from_opendal_error);
callback(
context,
match result {
Ok(value) => OpendalReadResult::ok(value),
Err(error) => OpendalReadResult::from_error(error),
},
);
});
Ok(())
}
/// Stat `path` synchronously with options.
///
/// On success, returned payload must be released with `opendal_metadata_result_release`.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
/// - When `option_len > 0`, `option_keys` and `option_values` must be valid arrays.
#[unsafe(no_mangle)]
pub extern "C" fn operator_stat_with_options(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::StatOptions,
) -> OpendalMetadataResult {
match operator_stat_with_options_inner(op, executor, path, options) {
Ok(value) => OpendalMetadataResult::ok(value as *mut c_void),
Err(error) => OpendalMetadataResult::from_error(error),
}
}
fn operator_stat_with_options_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::StatOptions,
) -> Result<*mut OpendalMetadata, OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?;
let options = if options.is_null() {
opendal::options::StatOptions::default()
} else {
unsafe { (&*options).clone() }
};
let metadata = executor
.block_on(op.stat_options(path, options))
.map_err(OpenDALError::from_opendal_error)?;
Ok(Box::into_raw(Box::new(OpendalMetadata::from_metadata(
metadata,
))))
}
/// Stat `path` asynchronously with options.
///
/// The callback is invoked exactly once. On success, callback result must be
/// released with `opendal_metadata_result_release`.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
/// - When `option_len > 0`, `option_keys` and `option_values` must be valid arrays.
/// - `callback` must be a valid function pointer and remain callable until invoked.
#[unsafe(no_mangle)]
pub extern "C" fn operator_stat_with_options_async(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::StatOptions,
callback: Option<StatCallback>,
context: i64,
) -> OpendalResult {
match operator_stat_with_options_async_inner(op, executor, path, options, callback, context) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_stat_with_options_async_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::StatOptions,
callback: Option<StatCallback>,
context: i64,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?.to_string();
let callback = require_callback(callback)?;
let options = if options.is_null() {
opendal::options::StatOptions::default()
} else {
unsafe { (&*options).clone() }
};
let op = op.clone();
executor.spawn(async move {
let result = op
.stat_options(&path, options)
.await
.map(OpendalMetadata::from_metadata)
.map(|v| Box::into_raw(Box::new(v)))
.map_err(OpenDALError::from_opendal_error);
callback(
context,
match result {
Ok(value) => OpendalMetadataResult::ok(value as *mut c_void),
Err(error) => OpendalMetadataResult::from_error(error),
},
);
});
Ok(())
}
/// List entries from `path` synchronously with options.
///
/// On success, returned payload must be released with `opendal_entry_list_result_release`.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
/// - When `option_len > 0`, `option_keys` and `option_values` must be valid arrays.
#[unsafe(no_mangle)]
pub extern "C" fn operator_list_with_options(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::ListOptions,
) -> OpendalEntryListResult {
match operator_list_with_options_inner(op, executor, path, options) {
Ok(value) => OpendalEntryListResult::ok(value),
Err(error) => OpendalEntryListResult::from_error(error),
}
}
fn operator_list_with_options_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::ListOptions,
) -> Result<*mut c_void, OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?;
let options = if options.is_null() {
opendal::options::ListOptions::default()
} else {
unsafe { (&*options).clone() }
};
let entries = executor
.block_on(op.list_options(path, options))
.map_err(OpenDALError::from_opendal_error)?;
Ok(into_entry_list_ptr(entries))
}
/// List entries from `path` asynchronously with options.
///
/// The callback is invoked exactly once. On success, callback result must be
/// released with `opendal_entry_list_result_release`.
/// # Safety
///
/// - `op` must be a valid operator pointer from `operator_construct`.
/// - `path` must be a valid null-terminated UTF-8 string.
/// - When `option_len > 0`, `option_keys` and `option_values` must be valid arrays.
/// - `callback` must be a valid function pointer and remain callable until invoked.
#[unsafe(no_mangle)]
pub extern "C" fn operator_list_with_options_async(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::ListOptions,
callback: Option<ListCallback>,
context: i64,
) -> OpendalResult {
match operator_list_with_options_async_inner(op, executor, path, options, callback, context) {
Ok(()) => OpendalResult::ok(),
Err(error) => OpendalResult::from_error(error),
}
}
fn operator_list_with_options_async_inner(
op: *const opendal::Operator,
executor: *const c_void,
path: *const c_char,
options: *const opendal::options::ListOptions,
callback: Option<ListCallback>,
context: i64,
) -> Result<(), OpenDALError> {
let op = require_operator(op)?;
let executor = executor_or_default(executor)?;
let path = require_cstr(path, "path")?.to_string();
let callback = require_callback(callback)?;
let options = if options.is_null() {
opendal::options::ListOptions::default()
} else {
unsafe { (&*options).clone() }
};
let op = op.clone();
executor.spawn(async move {
let result = op
.list_options(&path, options)
.await
.map(into_entry_list_ptr)
.map_err(OpenDALError::from_opendal_error);
callback(
context,
match result {
Ok(value) => OpendalEntryListResult::ok(value),
Err(error) => OpendalEntryListResult::from_error(error),
},
);
});
Ok(())
}