bindings/c/include/opendal.h (97 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.
*/
#ifndef _OPENDAL_H
#define _OPENDAL_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
/**
* \brief The error code for all opendal APIs in C binding.
* \todo The error handling is not complete, the error with error message will be
* added in the future.
*/
typedef enum opendal_code {
/**
* All is well
*/
OPENDAL_OK,
/**
* General error
*/
OPENDAL_ERROR,
/**
* returning it back. For example, s3 returns an internal service error.
*/
OPENDAL_UNEXPECTED,
/**
* Underlying service doesn't support this operation.
*/
OPENDAL_UNSUPPORTED,
/**
* The config for backend is invalid.
*/
OPENDAL_CONFIG_INVALID,
/**
* The given path is not found.
*/
OPENDAL_NOT_FOUND,
/**
* The given path doesn't have enough permission for this operation
*/
OPENDAL_PERMISSION_DENIED,
/**
* The given path is a directory.
*/
OPENDAL_IS_A_DIRECTORY,
/**
* The given path is not a directory.
*/
OPENDAL_NOT_A_DIRECTORY,
/**
* The given path already exists thus we failed to the specified operation on it.
*/
OPENDAL_ALREADY_EXISTS,
/**
* Requests that sent to this path is over the limit, please slow down.
*/
OPENDAL_RATE_LIMITED,
/**
* The given file paths are same.
*/
OPENDAL_IS_SAME_FILE,
} opendal_code;
/**
* BlockingLister is designed to list entries at given path in a blocking
* manner.
*
* Users can construct Lister by `blocking_lister`.
*/
typedef struct BlockingLister BlockingLister;
/**
* BlockingOperator is the entry for all public blocking APIs.
*
* Read [`concepts`][docs::concepts] for know more about [`Operator`].
*
* # Examples
*
* Read more backend init examples in [`services`]
*
* ```
* # use anyhow::Result;
* use opendal::services::Fs;
* use opendal::BlockingOperator;
* use opendal::Operator;
* #[tokio::main]
* async fn main() -> Result<()> {
* // Create fs backend builder.
* let mut builder = Fs::default();
* // Set the root for fs, all operations will happen under this root.
* //
* // NOTE: the root must be absolute path.
* builder.root("/tmp");
*
* // Build an `BlockingOperator` to start operating the storage.
* let _: BlockingOperator = Operator::new(builder)?.finish().blocking();
*
* Ok(())
* }
* ```
*/
typedef struct BlockingOperator BlockingOperator;
/**
* Entry returned by [`Lister`] or [`BlockingLister`] to represent a path and it's relative metadata.
*
* # Notes
*
* Entry returned by [`Lister`] or [`BlockingLister`] may carry some already known metadata.
* Lister by default only make sure that `Mode` is fetched. To make sure the entry contains
* metadata you want, please use `list_with` or `lister_with` and `metakey`.
*
* For example:
*
* ```no_run
* # use anyhow::Result;
* use opendal::EntryMode;
* use opendal::Metakey;
* use opendal::Operator;
* # #[tokio::main]
* # async fn test(op: Operator) -> Result<()> {
* let mut entries = op
* .list_with("dir/")
* .metakey(Metakey::ContentLength | Metakey::LastModified)
* .await?;
* for entry in entries {
* let meta = entry.metadata();
* match meta.mode() {
* EntryMode::FILE => {
* println!(
* "Handling file {} with size {}",
* entry.path(),
* meta.content_length()
* )
* }
* EntryMode::DIR => {
* println!("Handling dir {}", entry.path())
* }
* EntryMode::Unknown => continue,
* }
* }
* # Ok(())
* # }
* ```
*/
typedef struct Entry Entry;
typedef struct HashMap_String__String HashMap_String__String;
/**
* Metadata carries all metadata associated with a path.
*
* # Notes
*
* mode and content_length are required metadata that all services
* should provide during `stat` operation. But in `list` operation,
* a.k.a., `Entry`'s content length could be `None`.
*/
typedef struct Metadata Metadata;
/**
* \brief Used to access almost all OpenDAL APIs. It represents a
* operator that provides the unified interfaces provided by OpenDAL.
*
* @see opendal_operator_new This function construct the operator
* @see opendal_operator_free This function frees the heap memory of the operator
*
* \note The opendal_operator_ptr actually owns a pointer to
* a opendal::BlockingOperator, which is inside the Rust core code.
*
* \remark You may use the field `ptr` to check whether this is a NULL
* operator.
*/
typedef struct opendal_operator_ptr {
/**
* The pointer to the opendal::BlockingOperator in the Rust code.
* Only touch this on judging whether it is NULL.
*/
const struct BlockingOperator *ptr;
} opendal_operator_ptr;
/**
* \brief The configuration for the initialization of opendal_operator_ptr.
*
* \note This is also a heap-allocated struct, please free it after you use it
*
* @see opendal_operator_new has an example of using opendal_operator_options
* @see opendal_operator_options_new This function construct the operator
* @see opendal_operator_options_free This function frees the heap memory of the operator
* @see opendal_operator_options_set This function allow you to set the options
*/
typedef struct opendal_operator_options {
/**
* The pointer to the Rust HashMap<String, String>
* Only touch this on judging whether it is NULL.
*/
struct HashMap_String__String *inner;
} opendal_operator_options;
/**
* \brief opendal_bytes carries raw-bytes with its length
*
* The opendal_bytes type is a C-compatible substitute for Vec type
* in Rust, it has to be manually freed. You have to call opendal_bytes_free()
* to free the heap memory to avoid memory leak.
*
* @see opendal_bytes_free
*/
typedef struct opendal_bytes {
/**
* Pointing to the byte array on heap
*/
const uint8_t *data;
/**
* The length of the byte array
*/
uintptr_t len;
} opendal_bytes;
/**
* \brief The result type returned by opendal's read operation.
*
* The result type of read operation in opendal C binding, it contains
* the data that the read operation returns and a error code.
* If the read operation failed, the `data` fields should be a nullptr
* and the error code is **NOT** OPENDAL_OK.
*/
typedef struct opendal_result_read {
/**
* The byte array with length returned by read operations
*/
struct opendal_bytes *data;
/**
* The error code, should be OPENDAL_OK if succeeds
*/
enum opendal_code code;
} opendal_result_read;
/**
* \brief The result type returned by opendal_operator_is_exist().
*
* The result type for opendal_operator_is_exist(), the field `is_exist`
* contains whether the path exists, and the field `code` contains the
* corresponding error code.
*
* \note If the opendal_operator_is_exist() fails, the `is_exist` field
* will be set to false.
*/
typedef struct opendal_result_is_exist {
/**
* Whether the path exists
*/
bool is_exist;
/**
* The error code, should be OPENDAL_OK if succeeds
*/
enum opendal_code code;
} opendal_result_is_exist;
/**
* \brief Carries all metadata associated with a path.
*
* The metadata of the "thing" under a path. Please **only** use the opendal_metadata
* with our provided API, e.g. opendal_metadata_content_length().
*
* \note The metadata is also heap-allocated, please call opendal_metadata_free() on this
* to free the heap memory.
*
* @see opendal_metadata_free
*/
typedef struct opendal_metadata {
/**
* The pointer to the opendal::Metadata in the Rust code.
* Only touch this on judging whether it is NULL.
*/
struct Metadata *inner;
} opendal_metadata;
/**
* \brief The result type returned by opendal_operator_stat().
*
* The result type for opendal_operator_stat(), the field `meta` contains the metadata
* of the path, the field `code` represents whether the stat operation is successful.
*/
typedef struct opendal_result_stat {
/**
* The metadata output of the stat
*/
struct opendal_metadata *meta;
/**
* The error code, should be OPENDAL_OK if succeeds
*/
enum opendal_code code;
} opendal_result_stat;
/**
* \brief BlockingLister is designed to list entries at given path in a blocking
* manner.
*
* Users can construct Lister by `blocking_list` or `blocking_scan`(currently not supported in C binding)
*
* For examples, please see the comment section of opendal_operator_blocking_list()
* @see opendal_operator_blocking_list()
*/
typedef struct opendal_blocking_lister {
struct BlockingLister *inner;
} opendal_blocking_lister;
/**
* \brief The result type returned by opendal_operator_blocking_list().
*
* The result type for opendal_operator_blocking_list(), the field `lister` contains the lister
* of the path, which is an iterator of the objects under the path. the field `code` represents
* whether the stat operation is successful.
*/
typedef struct opendal_result_list {
struct opendal_blocking_lister *lister;
enum opendal_code code;
} opendal_result_list;
/**
* \brief opendal_list_entry is the entry under a path, which is listed from the opendal_blocking_lister
*
* For examples, please see the comment section of opendal_operator_blocking_list()
* @see opendal_operator_blocking_list()
* @see opendal_list_entry_path()
* @see opendal_list_entry_name()
*/
typedef struct opendal_list_entry {
struct Entry *inner;
} opendal_list_entry;
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/**
* \brief Construct an operator based on `scheme` and `options`
*
* Uses an array of key-value pairs to initialize the operator based on provided `scheme`
* and `options`. For each scheme, i.e. Backend, different options could be set, you may
* reference the [documentation](https://opendal.apache.org/docs/category/services/) for
* each service, especially for the **Configuration Part**.
*
* @param scheme the service scheme you want to specify, e.g. "fs", "s3", "supabase"
* @param options the pointer to the options for this operators, it could be NULL, which means no
* option is set
* @see opendal_operator_options
* @return A valid opendal_operator_ptr setup with the `scheme` and `options` is the construction
* succeeds. A null opendal_operator_ptr if any error happens.
*
* \remark You may use the `ptr` field of opendal_operator_ptr to check if it is NULL.
*
* # Example
*
* Following is an example.
* ```C
* // Allocate a new options
* opendal_operator_options *options = opendal_operator_options_new();
* // Set the options you need
* opendal_operator_options_set(options, "root", "/myroot");
*
* // Construct the operator based on the options and scheme
* const opendal_operator_ptr *ptr = opendal_operator_new("memory", options);
*
* // you could free the options right away since the options is not used afterwards
* opendal_operator_options_free(options);
*
* // ... your operations
* ```
*
* # Safety
*
* It is **safe** under two cases below
* * The memory pointed to by `scheme` contain a valid nul terminator at the end of
* the string.
* * The `scheme` points to NULL, this function simply returns you a null opendal_operator_ptr.
*/
const struct opendal_operator_ptr *opendal_operator_new(const char *scheme,
const struct opendal_operator_options *options);
/**
* \brief Blockingly write raw bytes to `path`.
*
* Write the `bytes` into the `path` blockingly by `op_ptr`, returns the opendal_code OPENDAL_OK
* if succeeds, others otherwise.
*
* @NOTE It is important to notice that the `bytes` that is passes in will be consumed by this
* function.
*
* @param ptr The opendal_operator_ptr created previously
* @param path The designated path you want to write your bytes in
* @param bytes The opendal_byte typed bytes to be written
* @see opendal_operator_ptr
* @see opendal_bytes
* @see opendal_code
* @return OPENDAL_OK if succeeds others otherwise
*
* # Example
*
* Following is an example
* ```C
* //...prepare your opendal_operator_ptr, named ptr for example
*
* // prepare your data
* char* data = "Hello, World!";
* opendal_bytes bytes = opendal_bytes { .data = (uint8_t*)data, .len = 13 };
*
* // now you can write!
* opendal_code code = opendal_operator_blocking_write(ptr, "/testpath", bytes);
*
* // Assert that this succeeds
* assert(code == OPENDAL_OK)
* ```
*
* # Safety
*
* It is **safe** under the cases below
* * The memory pointed to by `path` must contain a valid nul terminator at the end of
* the string.
* * The `bytes` provided has valid byte in the `data` field and the `len` field is set
* correctly.
*
* # Panic
*
* * If the `path` points to NULL, this function panics, i.e. exits with information
*/
enum opendal_code opendal_operator_blocking_write(const struct opendal_operator_ptr *ptr,
const char *path,
struct opendal_bytes bytes);
/**
* \brief Blockingly read the data from `path`.
*
* Read the data out from `path` blockingly by operator, returns
* an opendal_result_read with error code.
*
* @param ptr The opendal_operator_ptr created previously
* @param path The path you want to read the data out
* @see opendal_operator_ptr
* @see opendal_result_read
* @see opendal_code
* @return Returns opendal_result_read, the `data` field is a pointer to a newly allocated
* opendal_bytes, the `code` field contains the error code. If the `code` is not OPENDAL_OK,
* the `data` field points to NULL.
*
* \note If the read operation succeeds, the returned opendal_bytes is newly allocated on heap.
* After your usage of that, please call opendal_bytes_free() to free the space.
*
* # Example
*
* Following is an example
* ```C
* // ... you have write "Hello, World!" to path "/testpath"
*
* opendal_result_read r = opendal_operator_blocking_read(ptr, "testpath");
* assert(r.code == OPENDAL_OK);
*
* opendal_bytes *bytes = r.data;
* assert(bytes->len == 13);
* ```
*
* # Safety
*
* It is **safe** under the cases below
* * The memory pointed to by `path` must contain a valid nul terminator at the end of
* the string.
*
* # Panic
*
* * If the `path` points to NULL, this function panics, i.e. exits with information
*/
struct opendal_result_read opendal_operator_blocking_read(const struct opendal_operator_ptr *ptr,
const char *path);
/**
* \brief Blockingly delete the object in `path`.
*
* Delete the object in `path` blockingly by `op_ptr`, returns the opendal_code OPENDAL_OK
* if succeeds, others otherwise
*
* @param ptr The opendal_operator_ptr created previously
* @param path The designated path you want to delete
* @see opendal_operator_ptr
* @see opendal_code
* @return OPENDAL_OK if succeeds others otherwise
*
* # Example
*
* Following is an example
* ```C
* //...prepare your opendal_operator_ptr, named ptr for example
*
* // prepare your data
* char* data = "Hello, World!";
* opendal_bytes bytes = opendal_bytes { .data = (uint8_t*)data, .len = 13 };
* opendal_code code = opendal_operator_blocking_write(ptr, "/testpath", bytes);
*
* // now you can delete!
* opendal_code code = opendal_operator_blocking_delete(ptr, "/testpath");
*
* // Assert that this succeeds
* assert(code == OPENDAL_OK)
* ```
*
* # Safety
*
* It is **safe** under the cases below
* * The memory pointed to by `path` must contain a valid nul terminator at the end of
* the string.
*
* # Panic
*
* * If the `path` points to NULL, this function panics, i.e. exits with information
*/
enum opendal_code opendal_operator_blocking_delete(const struct opendal_operator_ptr *ptr,
const char *path);
/**
* \brief Check whether the path exists.
*
* If the operation succeeds, no matter the path exists or not,
* the error code should be opendal_code::OPENDAL_OK. Otherwise,
* the field `is_exist` is filled with false, and the error code
* is set correspondingly.
*
* @param ptr The opendal_operator_ptr created previously
* @param path The path you want to check existence
* @see opendal_operator_ptr
* @see opendal_result_is_exist
* @see opendal_code
* @return Returns opendal_result_is_exist, the `is_exist` field contains whether the path exists.
* However, it the operation fails, the `is_exist` will contains false and the error code will be
* stored in the `code` field.
*
* # Example
*
* ```C
* // .. you previously wrote some data to path "/mytest/obj"
* opendal_result_is_exist e = opendal_operator_is_exist(ptr, "/mytest/obj");
* assert(e.code == OPENDAL_OK);
* assert(e.is_exist);
*
* // but you previously did **not** write any data to path "/yourtest/obj"
* opendal_result_is_exist e = opendal_operator_is_exist(ptr, "yourtest/obj");
* assert(e.code == OPENDAL_OK);
* assert(!e.is_exist);
* ```
*
* # Safety
*
* It is **safe** under the cases below
* * The memory pointed to by `path` must contain a valid nul terminator at the end of
* the string.
*
* # Panic
*
* * If the `path` points to NULL, this function panics, i.e. exits with information
*/
struct opendal_result_is_exist opendal_operator_is_exist(const struct opendal_operator_ptr *ptr,
const char *path);
/**
* \brief Stat the path, return its metadata.
*
* If the operation succeeds, the error code should be
* OPENDAL_OK. Otherwise, the field `meta` is filled with
* a NULL pointer, and the error code is set correspondingly.
*
* @param ptr The opendal_operator_ptr created previously
* @param path The path you want to stat
* @see opendal_operator_ptr
* @see opendal_result_stat
* @see opendal_metadata
* @return Returns opendal_result_stat, containing a metadata and a opendal_code.
* If the operation succeeds, the `meta` field would holds a valid metadata and
* the `code` field should hold OPENDAL_OK. Otherwise the metadata will contain a
* NULL pointer, i.e. invalid, and the `code` will be set correspondingly.
*
* # Example
*
* ```C
* // ... previously you wrote "Hello, World!" to path "/testpath"
* opendal_result_stat s = opendal_operator_stat(ptr, "/testpath");
* assert(s.code == OPENDAL_OK);
*
* const opendal_metadata *meta = s.meta;
*
* // ... you could now use your metadata, notice that please only access metadata
* // using the APIs provided by OpenDAL
* ```
*
* # Safety
*
* It is **safe** under the cases below
* * The memory pointed to by `path` must contain a valid nul terminator at the end of
* the string.
*
* # Panic
*
* * If the `path` points to NULL, this function panics, i.e. exits with information
*/
struct opendal_result_stat opendal_operator_stat(const struct opendal_operator_ptr *ptr,
const char *path);
/**
* \brief Blockingly list the objects in `path`.
*
* List the object in `path` blockingly by `op_ptr`, return a result with a
* opendal_blocking_lister. Users should call opendal_lister_next() on the
* lister.
*
* @param ptr The opendal_operator_ptr created previously
* @param path The designated path you want to delete
* @see opendal_blocking_lister
* @return
*
* # Example
*
* Following is an example
* ```C
* // You have written some data into some files path "root/dir1"
* // Your opendal_operator_ptr was called ptr
* opendal_result_list l = opendal_operator_blocking_list(ptr, "root/dir1");
* assert(l.code == OPENDAL_OK);
*
* opendal_blocking_lister *lister = l.lister;
* opendal_list_entry *entry;
*
* while ((entry = opendal_lister_next(lister)) != NULL) {
* const char* de_path = opendal_list_entry_path(entry);
* const char* de_name = opendal_list_entry_name(entry);
* // ...... your operations
*
* // remember to free the entry after you are done using it
* opendal_list_entry_free(entry);
* }
*
* // and remember to free the lister
* opendal_lister_free(lister);
* ```
*
* # Safety
*
* It is **safe** under the cases below
* * The memory pointed to by `path` must contain a valid nul terminator at the end of
* the string.
*
* # Panic
*
* * If the `path` points to NULL, this function panics, i.e. exits with information
*/
struct opendal_result_list opendal_operator_blocking_list(const struct opendal_operator_ptr *ptr,
const char *path);
/**
* \brief Free the heap-allocated operator pointed by opendal_operator_ptr.
*
* Please only use this for a pointer pointing at a valid opendal_operator_ptr.
* Calling this function on NULL does nothing, but calling this function on pointers
* of other type will lead to segfault.
*
* # Example
*
* ```C
* opendal_operator_ptr *ptr = opendal_operator_new("fs", NULL);
* // ... use this ptr, maybe some reads and writes
*
* // free this operator
* opendal_operator_free(ptr);
* ```
*/
void opendal_operator_free(const struct opendal_operator_ptr *op);
/**
* \brief Frees the heap memory used by the opendal_bytes
*/
void opendal_bytes_free(struct opendal_bytes *ptr);
/**
* \brief Free the heap-allocated metadata used by opendal_metadata
*/
void opendal_metadata_free(struct opendal_metadata *ptr);
/**
* \brief Return the content_length of the metadata
*
* # Example
* ```C
* // ... previously you wrote "Hello, World!" to path "/testpath"
* opendal_result_stat s = opendal_operator_stat(ptr, "/testpath");
* assert(s.code == OPENDAL_OK);
*
* opendal_metadata *meta = s.meta;
* assert(opendal_metadata_content_length(meta) == 13);
* ```
*/
uint64_t opendal_metadata_content_length(const struct opendal_metadata *self);
/**
* \brief Return whether the path represents a file
*
* # Example
* ```C
* // ... previously you wrote "Hello, World!" to path "/testpath"
* opendal_result_stat s = opendal_operator_stat(ptr, "/testpath");
* assert(s.code == OPENDAL_OK);
*
* opendal_metadata *meta = s.meta;
* assert(opendal_metadata_is_file(meta));
* ```
*/
bool opendal_metadata_is_file(const struct opendal_metadata *self);
/**
* \brief Return whether the path represents a directory
*
* # Example
* ```C
* // ... previously you wrote "Hello, World!" to path "/testpath"
* opendal_result_stat s = opendal_operator_stat(ptr, "/testpath");
* assert(s.code == OPENDAL_OK);
*
* opendal_metadata *meta = s.meta;
*
* // this is not a directory
* assert(!opendal_metadata_is_dir(meta));
* ```
*
* \todo This is not a very clear example. A clearer example will be added
* after we support opendal_operator_mkdir()
*/
bool opendal_metadata_is_dir(const struct opendal_metadata *self);
/**
* \brief Construct a heap-allocated opendal_operator_options
*
* @return An empty opendal_operator_option, which could be set by
* opendal_operator_option_set().
*
* @see opendal_operator_option_set
*/
struct opendal_operator_options *opendal_operator_options_new(void);
/**
* \brief Set a Key-Value pair inside opendal_operator_options
*
* # Safety
*
* This function is unsafe because it dereferences and casts the raw pointers
* Make sure the pointer of `key` and `value` point to a valid string.
*
* # Example
*
* ```C
* opendal_operator_options *options = opendal_operator_options_new();
* opendal_operator_options_set(options, "root", "/myroot");
*
* // .. use your opendal_operator_options
*
* opendal_operator_options_free(options);
* ```
*/
void opendal_operator_options_set(struct opendal_operator_options *self,
const char *key,
const char *value);
/**
* \brief Free the allocated memory used by [`opendal_operator_options`]
*/
void opendal_operator_options_free(const struct opendal_operator_options *options);
/**
* \brief Return the next object to be listed
*
* Lister is an iterator of the objects under its path, this method is the same as
* calling next() on the iterator
*
* For examples, please see the comment section of opendal_operator_blocking_list()
* @see opendal_operator_blocking_list()
*/
struct opendal_list_entry *opendal_lister_next(const struct opendal_blocking_lister *self);
/**
* \brief Free the heap-allocated metadata used by opendal_blocking_lister
*/
void opendal_lister_free(const struct opendal_blocking_lister *p);
/**
* \brief Path of entry.
*
* Path is relative to operator's root. Only valid in current operator.
*
* @NOTE To free the string, you can directly call free()
*/
char *opendal_list_entry_path(const struct opendal_list_entry *self);
/**
* \brief Name of entry.
*
* Name is the last segment of path.
* If this entry is a dir, `Name` MUST endswith `/`
* Otherwise, `Name` MUST NOT endswith `/`.
*
* @NOTE To free the string, you can directly call free()
*/
char *opendal_list_entry_name(const struct opendal_list_entry *self);
/**
* \brief Frees the heap memory used by the opendal_list_entry
*/
void opendal_list_entry_free(struct opendal_list_entry *ptr);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif /* _OPENDAL_H */