blob: e7b4c601dde571560b33c0f998fc6e862bb61c80 [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 std::ffi::{c_char, c_void};
use crate::metadata::{OpendalMetadata, metadata_release_fields};
use crate::utils::into_string_ptr;
#[repr(C)]
/// FFI representation of an OpenDAL entry.
///
/// The path string and metadata string fields are heap-allocated and owned by
/// Rust until released via `entry_list_free`. Metadata is stored inline so a
/// list is one contiguous array instead of a pointer per entry.
pub struct OpendalEntry {
pub path: *mut c_char,
pub metadata: OpendalMetadata,
}
#[repr(C)]
/// FFI representation of a list of entries.
///
/// `entries` points at a contiguous array of `len` entries stored by value.
pub struct OpendalEntryList {
pub entries: *mut OpendalEntry,
pub len: usize,
}
impl OpendalEntry {
pub fn from_entry(entry: opendal::Entry) -> Self {
let (path, metadata) = entry.into_parts();
Self {
path: into_string_ptr(path),
metadata: OpendalMetadata::from_metadata(metadata),
}
}
}
/// Convert OpenDAL entries into an owned FFI list pointer.
///
/// The returned pointer must be released by `entry_list_free`.
pub fn into_entry_list_ptr(entries: Vec<opendal::Entry>) -> *mut c_void {
// A boxed slice always allocates exactly `len` elements, so
// `entry_list_free` can rebuild it from the raw parts alone.
let entries: Box<[OpendalEntry]> = entries.into_iter().map(OpendalEntry::from_entry).collect();
let len = entries.len();
let entries_ptr = Box::into_raw(entries) as *mut OpendalEntry;
Box::into_raw(Box::new(OpendalEntryList {
entries: entries_ptr,
len,
})) as *mut c_void
}
/// # Safety
///
/// - `list` must be null or a pointer returned by Rust as `OpendalEntryList`.
/// - Must be called at most once for the same pointer.
pub(crate) unsafe fn entry_list_free(list: *mut OpendalEntryList) {
if list.is_null() {
return;
}
unsafe {
let list = Box::from_raw(list);
if list.entries.is_null() {
return;
}
let mut entries = Box::from_raw(std::ptr::slice_from_raw_parts_mut(list.entries, list.len));
for entry in entries.iter_mut() {
if !entry.path.is_null() {
drop(std::ffi::CString::from_raw(entry.path));
}
metadata_release_fields(&mut entry.metadata);
}
}
}