diff --git a/bindings/c/include/opendal.h b/bindings/c/include/opendal.h index d535e6dcf768..ca028278b9ce 100644 --- a/bindings/c/include/opendal.h +++ b/bindings/c/include/opendal.h @@ -254,7 +254,7 @@ typedef struct opendal_result_stat { /** * The metadata output of the stat */ - struct opendal_metadata meta; + const struct opendal_metadata *meta; /** * The error code, should be OPENDAL_OK if succeeds */ @@ -287,15 +287,15 @@ extern "C" { * Following is an example. * ```C * // Allocate a new options - * opendal_operator_options options = opendal_operator_options_new(); + * opendal_operator_options *options = opendal_operator_options_new(); * // Set the options you need - * opendal_operator_options_set(&options, "root", "/myroot"); + * opendal_operator_options_set(options, "root", "/myroot"); * * // Construct the operator based on the options and scheme - * opendal_operator_ptr ptr = opendal_operator_new("memory", &options); + * 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); + * opendal_operator_options_free(options); * * // ... your operations * ``` @@ -307,8 +307,8 @@ extern "C" { * the string. * * The `scheme` points to NULL, this function simply returns you a null opendal_operator_ptr. */ -struct opendal_operator_ptr opendal_operator_new(const char *scheme, - const struct opendal_operator_options *options); +const struct opendal_operator_ptr *opendal_operator_new(const char *scheme, + const struct opendal_operator_options *options); /** * \brief Blockingly write raw bytes to `path`. @@ -353,7 +353,7 @@ struct opendal_operator_ptr opendal_operator_new(const char *scheme, * * * If the `path` points to NULL, this function panics, i.e. exits with information */ -enum opendal_code opendal_operator_blocking_write(struct opendal_operator_ptr ptr, +enum opendal_code opendal_operator_blocking_write(const struct opendal_operator_ptr *ptr, const char *path, struct opendal_bytes bytes); @@ -398,7 +398,7 @@ enum opendal_code opendal_operator_blocking_write(struct opendal_operator_ptr pt * * * If the `path` points to NULL, this function panics, i.e. exits with information */ -struct opendal_result_read opendal_operator_blocking_read(struct opendal_operator_ptr ptr, +struct opendal_result_read opendal_operator_blocking_read(const struct opendal_operator_ptr *ptr, const char *path); /** @@ -441,7 +441,7 @@ struct opendal_result_read opendal_operator_blocking_read(struct opendal_operato * * * If the `path` points to NULL, this function panics, i.e. exits with information */ -enum opendal_code opendal_operator_blocking_delete(struct opendal_operator_ptr ptr, +enum opendal_code opendal_operator_blocking_delete(const struct opendal_operator_ptr *ptr, const char *path); /** @@ -485,7 +485,7 @@ enum opendal_code opendal_operator_blocking_delete(struct opendal_operator_ptr p * * * If the `path` points to NULL, this function panics, i.e. exits with information */ -struct opendal_result_is_exist opendal_operator_is_exist(struct opendal_operator_ptr ptr, +struct opendal_result_is_exist opendal_operator_is_exist(const struct opendal_operator_ptr *ptr, const char *path); /** @@ -512,7 +512,7 @@ struct opendal_result_is_exist opendal_operator_is_exist(struct opendal_operator * opendal_result_stat s = opendal_operator_stat(ptr, "/testpath"); * assert(s.code == OPENDAL_OK); * - * opendal_metadata meta = s.meta; + * const opendal_metadata *meta = s.meta; * * // ... you could now use your metadata, notice that please only access metadata * // using the APIs provided by OpenDAL @@ -528,7 +528,8 @@ struct opendal_result_is_exist opendal_operator_is_exist(struct opendal_operator * * * If the `path` points to NULL, this function panics, i.e. exits with information */ -struct opendal_result_stat opendal_operator_stat(struct opendal_operator_ptr ptr, const char *path); +struct opendal_result_stat opendal_operator_stat(const struct opendal_operator_ptr *ptr, + const char *path); /** * \brief Free the heap-allocated operator pointed by opendal_operator_ptr. @@ -540,14 +541,14 @@ struct opendal_result_stat opendal_operator_stat(struct opendal_operator_ptr ptr * # Example * * ```C - * opendal_operator_ptr ptr = opendal_operator_new("fs", NULL); + * opendal_operator_ptr *ptr = opendal_operator_new("fs", NULL); * // ... use this ptr, maybe some reads and writes * * // free this operator - * opendal_operator_free(&ptr); + * opendal_operator_free(ptr); * ``` */ -void opendal_operator_free(const struct opendal_operator_ptr *self); +void opendal_operator_free(const struct opendal_operator_ptr *op); /** * \brief Frees the heap memory used by the opendal_bytes @@ -568,8 +569,8 @@ void opendal_metadata_free(const struct opendal_metadata *self); * 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); + * opendal_metadata *meta = s.meta; + * assert(opendal_metadata_content_length(meta) == 13); * ``` */ uint64_t opendal_metadata_content_length(const struct opendal_metadata *self); @@ -583,8 +584,8 @@ uint64_t opendal_metadata_content_length(const struct opendal_metadata *self); * 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)); + * opendal_metadata *meta = s.meta; + * assert(opendal_metadata_is_file(meta)); * ``` */ bool opendal_metadata_is_file(const struct opendal_metadata *self); @@ -598,10 +599,10 @@ bool opendal_metadata_is_file(const struct opendal_metadata *self); * opendal_result_stat s = opendal_operator_stat(ptr, "/testpath"); * assert(s.code == OPENDAL_OK); * - * opendal_metadata meta = s.meta; + * opendal_metadata *meta = s.meta; * * // this is not a directory - * assert(!opendal_metadata_is_dir(&meta)); + * assert(!opendal_metadata_is_dir(meta)); * ``` * * \todo This is not a very clear example. A clearer example will be added @@ -617,7 +618,7 @@ bool opendal_metadata_is_dir(const struct opendal_metadata *self); * * @see opendal_operator_option_set */ -struct opendal_operator_options opendal_operator_options_new(void); +struct opendal_operator_options *opendal_operator_options_new(void); /** * \brief Set a Key-Value pair inside opendal_operator_options @@ -630,8 +631,8 @@ struct opendal_operator_options opendal_operator_options_new(void); * # Example * * ```C - * opendal_operator_options options = opendal_operator_options_new(); - * opendal_operator_options_set(&options, "root", "/myroot"); + * opendal_operator_options *options = opendal_operator_options_new(); + * opendal_operator_options_set(options, "root", "/myroot"); * * // .. use your opendal_operator_options * @@ -645,7 +646,7 @@ void opendal_operator_options_set(struct opendal_operator_options *self, /** * \brief Free the allocated memory used by [`opendal_operator_options`] */ -void opendal_operator_options_free(const struct opendal_operator_options *self); +void opendal_operator_options_free(const struct opendal_operator_options *options); #ifdef __cplusplus } // extern "C" diff --git a/bindings/c/src/lib.rs b/bindings/c/src/lib.rs index 4089f96a8944..047b0b38858b 100644 --- a/bindings/c/src/lib.rs +++ b/bindings/c/src/lib.rs @@ -54,15 +54,15 @@ use crate::types::{ /// Following is an example. /// ```C /// // Allocate a new options -/// opendal_operator_options options = opendal_operator_options_new(); +/// opendal_operator_options *options = opendal_operator_options_new(); /// // Set the options you need -/// opendal_operator_options_set(&options, "root", "/myroot"); +/// opendal_operator_options_set(options, "root", "/myroot"); /// /// // Construct the operator based on the options and scheme -/// opendal_operator_ptr ptr = opendal_operator_new("memory", &options); +/// 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); +/// opendal_operator_options_free(options); /// /// // ... your operations /// ``` @@ -77,16 +77,16 @@ use crate::types::{ pub unsafe extern "C" fn opendal_operator_new( scheme: *const c_char, options: *const opendal_operator_options, -) -> opendal_operator_ptr { +) -> *const opendal_operator_ptr { if scheme.is_null() { - return opendal_operator_ptr::null(); + return std::ptr::null(); } let scheme_str = unsafe { std::ffi::CStr::from_ptr(scheme).to_str().unwrap() }; let scheme = match od::Scheme::from_str(scheme_str) { Ok(s) => s, Err(_) => { - return opendal_operator_ptr::null(); + return std::ptr::null(); } }; @@ -100,14 +100,14 @@ pub unsafe extern "C" fn opendal_operator_new( let op = match od::Operator::via_map(scheme, map) { Ok(o) => o.blocking(), Err(_) => { - return opendal_operator_ptr::null(); + return std::ptr::null(); } }; // this prevents the operator memory from being dropped by the Box - let op = Box::leak(Box::new(op)); + let op = opendal_operator_ptr::from(Box::leak(Box::new(op))); - opendal_operator_ptr::from(op) + Box::leak(Box::new(op)) } /// \brief Blockingly write raw bytes to `path`. @@ -153,7 +153,7 @@ pub unsafe extern "C" fn opendal_operator_new( /// * If the `path` points to NULL, this function panics, i.e. exits with information #[no_mangle] pub unsafe extern "C" fn opendal_operator_blocking_write( - ptr: opendal_operator_ptr, + ptr: *const opendal_operator_ptr, path: *const c_char, bytes: opendal_bytes, ) -> opendal_code { @@ -161,7 +161,7 @@ pub unsafe extern "C" fn opendal_operator_blocking_write( panic!("The path given is pointing at NULL"); } - let op = ptr.as_ref(); + let op = (*ptr).as_ref(); let path = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }; match op.write(path, bytes) { Ok(_) => opendal_code::OPENDAL_OK, @@ -210,14 +210,14 @@ pub unsafe extern "C" fn opendal_operator_blocking_write( /// * If the `path` points to NULL, this function panics, i.e. exits with information #[no_mangle] pub unsafe extern "C" fn opendal_operator_blocking_read( - ptr: opendal_operator_ptr, + ptr: *const opendal_operator_ptr, path: *const c_char, ) -> opendal_result_read { if path.is_null() { panic!("The path given is pointing at NULL"); } - let op = ptr.as_ref(); + let op = (*ptr).as_ref(); let path = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }; let data = op.read(path); match data { @@ -275,14 +275,14 @@ pub unsafe extern "C" fn opendal_operator_blocking_read( /// * If the `path` points to NULL, this function panics, i.e. exits with information #[no_mangle] pub unsafe extern "C" fn opendal_operator_blocking_delete( - ptr: opendal_operator_ptr, + ptr: *const opendal_operator_ptr, path: *const c_char, ) -> opendal_code { if path.is_null() { panic!("The path given is pointing at NULL"); } - let op = ptr.as_ref(); + let op = (*ptr).as_ref(); let path = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }; match op.delete(path) { Ok(_) => opendal_code::OPENDAL_OK, @@ -331,14 +331,14 @@ pub unsafe extern "C" fn opendal_operator_blocking_delete( /// * If the `path` points to NULL, this function panics, i.e. exits with information #[no_mangle] pub unsafe extern "C" fn opendal_operator_is_exist( - ptr: opendal_operator_ptr, + ptr: *const opendal_operator_ptr, path: *const c_char, ) -> opendal_result_is_exist { if path.is_null() { panic!("The path given is pointing at NULL"); } - let op = ptr.as_ref(); + let op = (*ptr).as_ref(); let path = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }; match op.is_exist(path) { Ok(e) => opendal_result_is_exist { @@ -375,7 +375,7 @@ pub unsafe extern "C" fn opendal_operator_is_exist( /// opendal_result_stat s = opendal_operator_stat(ptr, "/testpath"); /// assert(s.code == OPENDAL_OK); /// -/// opendal_metadata meta = s.meta; +/// const opendal_metadata *meta = s.meta; /// /// // ... you could now use your metadata, notice that please only access metadata /// // using the APIs provided by OpenDAL @@ -392,14 +392,14 @@ pub unsafe extern "C" fn opendal_operator_is_exist( /// * If the `path` points to NULL, this function panics, i.e. exits with information #[no_mangle] pub unsafe extern "C" fn opendal_operator_stat( - ptr: opendal_operator_ptr, + ptr: *const opendal_operator_ptr, path: *const c_char, ) -> opendal_result_stat { if path.is_null() { panic!("The path given is pointing at NULL"); } - let op = ptr.as_ref(); + let op = (*ptr).as_ref(); let path = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }; match op.stat(path) { Ok(m) => opendal_result_stat { @@ -407,7 +407,7 @@ pub unsafe extern "C" fn opendal_operator_stat( code: opendal_code::OPENDAL_OK, }, Err(err) => opendal_result_stat { - meta: opendal_metadata::null(), + meta: std::ptr::null(), code: opendal_code::from_opendal_error(err), }, } diff --git a/bindings/c/src/result.rs b/bindings/c/src/result.rs index 345d3d3539f6..fef1c5d971c2 100644 --- a/bindings/c/src/result.rs +++ b/bindings/c/src/result.rs @@ -61,7 +61,7 @@ pub struct opendal_result_is_exist { #[repr(C)] pub struct opendal_result_stat { /// The metadata output of the stat - pub meta: opendal_metadata, + pub meta: *const opendal_metadata, /// The error code, should be OPENDAL_OK if succeeds pub code: opendal_code, } diff --git a/bindings/c/src/types.rs b/bindings/c/src/types.rs index 37aa372186ff..454248a4d0e2 100644 --- a/bindings/c/src/types.rs +++ b/bindings/c/src/types.rs @@ -48,35 +48,23 @@ impl opendal_operator_ptr { /// # Example /// /// ```C - /// opendal_operator_ptr ptr = opendal_operator_new("fs", NULL); + /// opendal_operator_ptr *ptr = opendal_operator_new("fs", NULL); /// // ... use this ptr, maybe some reads and writes /// /// // free this operator - /// opendal_operator_free(&ptr); + /// opendal_operator_free(ptr); /// ``` #[no_mangle] - pub extern "C" fn opendal_operator_free(&self) { - if self.is_null() { + pub unsafe extern "C" fn opendal_operator_free(op: *const opendal_operator_ptr) { + if op.is_null() || unsafe { (*op).ptr.is_null() } { return; } - let _ = unsafe { Box::from_raw(self.ptr as *mut od::BlockingOperator) }; + let _ = unsafe { Box::from_raw((*op).ptr as *mut od::BlockingOperator) }; + let _ = unsafe { Box::from_raw(op as *mut opendal_operator_ptr) }; } } impl opendal_operator_ptr { - /// Creates an OperatorPtr will nullptr, indicating this [`opendal_operator_ptr`] - /// is invalid. - pub(crate) fn null() -> Self { - Self { - ptr: std::ptr::null(), - } - } - - /// Returns whether this points to NULL - pub(crate) fn is_null(&self) -> bool { - self.ptr.is_null() - } - /// Returns a reference to the underlying [`od::BlockingOperator`] pub(crate) fn as_ref(&self) -> &od::BlockingOperator { unsafe { &*(self.ptr) } @@ -176,8 +164,8 @@ impl opendal_metadata { /// 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); + /// opendal_metadata *meta = s.meta; + /// assert(opendal_metadata_content_length(meta) == 13); /// ``` #[no_mangle] pub extern "C" fn opendal_metadata_content_length(&self) -> u64 { @@ -194,8 +182,8 @@ impl opendal_metadata { /// 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)); + /// opendal_metadata *meta = s.meta; + /// assert(opendal_metadata_is_file(meta)); /// ``` #[no_mangle] pub extern "C" fn opendal_metadata_is_file(&self) -> bool { @@ -212,10 +200,10 @@ impl opendal_metadata { /// opendal_result_stat s = opendal_operator_stat(ptr, "/testpath"); /// assert(s.code == OPENDAL_OK); /// - /// opendal_metadata meta = s.meta; + /// opendal_metadata *meta = s.meta; /// /// // this is not a directory - /// assert(!opendal_metadata_is_dir(&meta)); + /// assert(!opendal_metadata_is_dir(meta)); /// ``` /// /// \todo This is not a very clear example. A clearer example will be added @@ -229,17 +217,10 @@ impl opendal_metadata { } impl opendal_metadata { - /// Return a null metadata - pub(crate) fn null() -> Self { - Self { - inner: std::ptr::null(), - } - } - /// Convert a Rust core [`od::Metadata`] into a heap allocated C-compatible /// [`opendal_metadata`] - pub(crate) fn from_metadata(m: od::Metadata) -> Self { - Self { + pub(crate) fn from_metadata(m: od::Metadata) -> *const Self { + &Self { inner: Box::leak(Box::new(m)), } } @@ -268,11 +249,13 @@ impl opendal_operator_options { /// /// @see opendal_operator_option_set #[no_mangle] - pub extern "C" fn opendal_operator_options_new() -> Self { + pub extern "C" fn opendal_operator_options_new() -> *mut Self { let map: HashMap = HashMap::default(); - Self { + let options = Self { inner: Box::leak(Box::new(map)), - } + }; + + Box::leak(Box::new(options)) } /// \brief Set a Key-Value pair inside opendal_operator_options @@ -285,8 +268,8 @@ impl opendal_operator_options { /// # Example /// /// ```C - /// opendal_operator_options options = opendal_operator_options_new(); - /// opendal_operator_options_set(&options, "root", "/myroot"); + /// opendal_operator_options *options = opendal_operator_options_new(); + /// opendal_operator_options_set(options, "root", "/myroot"); /// /// // .. use your opendal_operator_options /// @@ -316,10 +299,13 @@ impl opendal_operator_options { /// \brief Free the allocated memory used by [`opendal_operator_options`] #[no_mangle] - pub extern "C" fn opendal_operator_options_free(&self) { - if self.inner.is_null() { + pub unsafe extern "C" fn opendal_operator_options_free( + options: *const opendal_operator_options, + ) { + if options.is_null() || unsafe { (*options).inner.is_null() } { return; } - let _ = unsafe { Box::from_raw(self.inner as *mut HashMap) }; + let _ = unsafe { Box::from_raw((*options).inner as *mut HashMap) }; + let _ = unsafe { Box::from_raw(options as *mut opendal_operator_options) }; } } diff --git a/bindings/c/tests/bdd.cpp b/bindings/c/tests/bdd.cpp index 4904259581c5..17414b83bece 100644 --- a/bindings/c/tests/bdd.cpp +++ b/bindings/c/tests/bdd.cpp @@ -25,7 +25,8 @@ extern "C" { class OpendalBddTest : public ::testing::Test { protected: - opendal_operator_ptr p; + const opendal_operator_ptr *p; + std::string scheme; std::string path; std::string content; @@ -36,17 +37,17 @@ class OpendalBddTest : public ::testing::Test { this->path = std::string("test"); this->content = std::string("Hello, World!"); - opendal_operator_options options = opendal_operator_options_new(); - opendal_operator_options_set(&options, "root", "/myroot"); + opendal_operator_options *options = opendal_operator_options_new(); + opendal_operator_options_set(options, "root", "/myroot"); // Given A new OpenDAL Blocking Operator - this->p = opendal_operator_new(scheme.c_str(), &options); - EXPECT_TRUE(this->p.ptr); + this->p = opendal_operator_new(scheme.c_str(), options); + EXPECT_TRUE(this->p->ptr); - opendal_operator_options_free(&options); + opendal_operator_options_free(options); } - void TearDown() override { opendal_operator_free(&this->p); } + void TearDown() override { opendal_operator_free(this->p); } }; // Scenario: OpenDAL Blocking Operations @@ -68,12 +69,12 @@ TEST_F(OpendalBddTest, FeatureTest) // The blocking file "test" entry mode must be file opendal_result_stat s = opendal_operator_stat(this->p, this->path.c_str()); EXPECT_EQ(s.code, OPENDAL_OK); - opendal_metadata meta = s.meta; - EXPECT_TRUE(opendal_metadata_is_file(&meta)); + const opendal_metadata *meta = s.meta; + EXPECT_TRUE(opendal_metadata_is_file(meta)); // The blocking file "test" content length must be 13 - EXPECT_EQ(opendal_metadata_content_length(&meta), 13); - opendal_metadata_free(&meta); + EXPECT_EQ(opendal_metadata_content_length(meta), 13); + opendal_metadata_free(meta); // The blocking file "test" must have content "Hello, World!" struct opendal_result_read r = opendal_operator_blocking_read(this->p, this->path.c_str());