You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by ti...@apache.org on 2024/10/06 08:58:45 UTC

(opendal) branch main updated: refactor: more consistent C binding pattern (#5162)

This is an automated email from the ASF dual-hosted git repository.

tison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git


The following commit(s) were added to refs/heads/main by this push:
     new d74bf7c2c5 refactor: more consistent C binding pattern (#5162)
d74bf7c2c5 is described below

commit d74bf7c2c5a9a011029c62ba1f381ae684fc4f57
Author: tison <wa...@gmail.com>
AuthorDate: Sun Oct 6 16:58:39 2024 +0800

    refactor: more consistent C binding pattern (#5162)
    
    Signed-off-by: tison <wa...@gmail.com>
---
 bindings/c/include/opendal.h    |  88 +++++---------
 bindings/c/src/entry.rs         |   6 +-
 bindings/c/src/error.rs         |  19 +--
 bindings/c/src/lister.rs        |  10 +-
 bindings/c/src/metadata.rs      |   4 +-
 bindings/c/src/operator.rs      | 255 +++++++++++++++++-----------------------
 bindings/c/src/operator_info.rs |  12 +-
 bindings/c/src/reader.rs        |  17 ++-
 bindings/c/src/types.rs         |  25 ++--
 bindings/c/src/writer.rs        |  12 +-
 10 files changed, 192 insertions(+), 256 deletions(-)

diff --git a/bindings/c/include/opendal.h b/bindings/c/include/opendal.h
index 05854c93e1..2df3447d23 100644
--- a/bindings/c/include/opendal.h
+++ b/bindings/c/include/opendal.h
@@ -81,60 +81,6 @@ typedef enum opendal_code {
   OPENDAL_RANGE_NOT_SATISFIED,
 } opendal_code;
 
-/**
- * BlockingOperator is the entry for all public blocking APIs.
- *
- * Read [`concepts`][docs::concepts] for know more about [`Operator`].
- *
- * # Examples
- *
- * ## Init backends
- *
- * Read more backend init examples in [`services`]
- *
- * ```rust,no_run
- * # use anyhow::Result;
- * use opendal::services::Fs;
- * use opendal::BlockingOperator;
- * use opendal::Operator;
- *
- * fn main() -> Result<()> {
- *     // Create fs backend builder.
- *     let builder = Fs::default().root("/tmp");
- *
- *     // Build an `BlockingOperator` to start operating the storage.
- *     let _: BlockingOperator = Operator::new(builder)?.finish().blocking();
- *
- *     Ok(())
- * }
- * ```
- *
- * ## Init backends with blocking layer
- *
- * Some services like s3, gcs doesn't have native blocking supports, we can use [`layers::BlockingLayer`]
- * to wrap the async operator to make it blocking.
- * # use anyhow::Result;
- * use opendal::layers::BlockingLayer;
- * use opendal::services::S3;
- * use opendal::BlockingOperator;
- * use opendal::Operator;
- *
- * async fn test() -> Result<()> {
- *     // Create fs backend builder.
- *     let mut builder = S3::default().bucket("test").region("us-east-1");
- *
- *     // Build an `BlockingOperator` with blocking layer to start operating the storage.
- *     let _: BlockingOperator = Operator::new(builder)?
- *         .layer(BlockingLayer::create()?)
- *         .finish()
- *         .blocking();
- *
- *     Ok(())
- * }
- * ```
- */
-typedef struct BlockingOperator BlockingOperator;
-
 /**
  * \brief opendal_bytes carries raw-bytes with its length
  *
@@ -188,6 +134,10 @@ typedef struct opendal_error {
  * @see opendal_list_entry_name()
  */
 typedef struct opendal_entry {
+  /**
+   * The pointer to the opendal::Entry in the Rust code.
+   * Only touch this on judging whether it is NULL.
+   */
   void *inner;
 } opendal_entry;
 
@@ -219,6 +169,10 @@ typedef struct opendal_result_lister_next {
  * @see opendal_operator_list()
  */
 typedef struct opendal_lister {
+  /**
+   * The pointer to the opendal::BlockingLister in the Rust code.
+   * Only touch this on judging whether it is NULL.
+   */
   void *inner;
 } opendal_lister;
 
@@ -259,7 +213,7 @@ typedef struct opendal_operator {
    * The pointer to the opendal::BlockingOperator in the Rust code.
    * Only touch this on judging whether it is NULL.
    */
-  const struct BlockingOperator *ptr;
+  const void *inner;
 } opendal_operator;
 
 /**
@@ -297,7 +251,7 @@ typedef struct opendal_result_operator_new {
  */
 typedef struct opendal_operator_options {
   /**
-   * The pointer to the Rust HashMap<String, String>
+   * The pointer to the HashMap<String, String> in the Rust code.
    * Only touch this on judging whether it is NULL.
    */
   void *inner;
@@ -329,6 +283,10 @@ typedef struct opendal_result_read {
  * a opendal::BlockingReader, which is inside the Rust core code.
  */
 typedef struct opendal_reader {
+  /**
+   * The pointer to the opendal::StdReader in the Rust code.
+   * Only touch this on judging whether it is NULL.
+   */
   void *inner;
 } opendal_reader;
 
@@ -355,6 +313,10 @@ typedef struct opendal_result_operator_reader {
  * an opendal::BlockingWriter, which is inside the Rust core code.
  */
 typedef struct opendal_writer {
+  /**
+   * The pointer to the opendal::BlockingWriter in the Rust code.
+   * Only touch this on judging whether it is NULL.
+   */
   void *inner;
 } opendal_writer;
 
@@ -436,6 +398,10 @@ typedef struct opendal_result_list {
  * of operator.
  */
 typedef struct opendal_operator_info {
+  /**
+   * The pointer to the opendal::OperatorInfo in the Rust code.
+   * Only touch this on judging whether it is NULL.
+   */
   void *inner;
 } opendal_operator_info;
 
@@ -658,7 +624,7 @@ void opendal_error_free(struct opendal_error *ptr);
  * For examples, please see the comment section of opendal_operator_list()
  * @see opendal_operator_list()
  */
-struct opendal_result_lister_next opendal_lister_next(const struct opendal_lister *self);
+struct opendal_result_lister_next opendal_lister_next(struct opendal_lister *self);
 
 /**
  * \brief Free the heap-allocated metadata used by opendal_lister
@@ -752,7 +718,7 @@ int64_t opendal_metadata_last_modified_ms(const struct opendal_metadata *self);
  * opendal_operator_free(op);
  * ```
  */
-void opendal_operator_free(const struct opendal_operator *op);
+void opendal_operator_free(const struct opendal_operator *ptr);
 
 /**
  * \brief Construct an operator based on `scheme` and `options`
@@ -1343,7 +1309,7 @@ struct opendal_capability opendal_operator_info_get_native_capability(const stru
 /**
  * \brief Frees the heap memory used by the opendal_bytes
  */
-void opendal_bytes_free(struct opendal_bytes *bs);
+void opendal_bytes_free(struct opendal_bytes *ptr);
 
 /**
  * \brief Construct a heap-allocated opendal_operator_options
@@ -1411,7 +1377,7 @@ void opendal_entry_free(struct opendal_entry *ptr);
 /**
  * \brief Read data from the reader.
  */
-struct opendal_result_reader_read opendal_reader_read(const struct opendal_reader *self,
+struct opendal_result_reader_read opendal_reader_read(struct opendal_reader *self,
                                                       uint8_t *buf,
                                                       uintptr_t len);
 
@@ -1423,7 +1389,7 @@ void opendal_reader_free(struct opendal_reader *ptr);
 /**
  * \brief Write data to the writer.
  */
-struct opendal_result_writer_write opendal_writer_write(const struct opendal_writer *self,
+struct opendal_result_writer_write opendal_writer_write(struct opendal_writer *self,
                                                         struct opendal_bytes bytes);
 
 /**
diff --git a/bindings/c/src/entry.rs b/bindings/c/src/entry.rs
index f4c62792e0..f31fa77547 100644
--- a/bindings/c/src/entry.rs
+++ b/bindings/c/src/entry.rs
@@ -28,6 +28,8 @@ use ::opendal as core;
 /// @see opendal_list_entry_name()
 #[repr(C)]
 pub struct opendal_entry {
+    /// The pointer to the opendal::Entry in the Rust code.
+    /// Only touch this on judging whether it is NULL.
     inner: *mut c_void,
 }
 
@@ -77,8 +79,8 @@ impl opendal_entry {
     #[no_mangle]
     pub unsafe extern "C" fn opendal_entry_free(ptr: *mut opendal_entry) {
         if !ptr.is_null() {
-            let _ = Box::from_raw((*ptr).inner as *mut core::Entry);
-            let _ = Box::from_raw(ptr);
+            drop(Box::from_raw((*ptr).inner as *mut core::Entry));
+            drop(Box::from_raw(ptr));
         }
     }
 }
diff --git a/bindings/c/src/error.rs b/bindings/c/src/error.rs
index ac6cb6b552..d1c6155ee7 100644
--- a/bindings/c/src/error.rs
+++ b/bindings/c/src/error.rs
@@ -68,7 +68,9 @@ impl From<core::ErrorKind> for opendal_code {
             core::ErrorKind::RangeNotSatisfied => opendal_code::OPENDAL_RANGE_NOT_SATISFIED,
             // if this is triggered, check the [`core`] crate and add a
             // new error code accordingly
-            _ => panic!("The newly added ErrorKind in core crate is not handled in C bindings"),
+            _ => unimplemented!(
+                "The newly added ErrorKind in core crate is not handled in C bindings"
+            ),
         }
     }
 }
@@ -112,16 +114,19 @@ impl opendal_error {
     #[no_mangle]
     pub unsafe extern "C" fn opendal_error_free(ptr: *mut opendal_error) {
         if !ptr.is_null() {
-            let message_ptr = &(*ptr).message as *const opendal_bytes as *mut opendal_bytes;
+            let message_ptr = &(*ptr).message;
+            let message_ptr = message_ptr as *const opendal_bytes as *mut opendal_bytes;
             if !message_ptr.is_null() {
-                let data_mut = unsafe { (*message_ptr).data as *mut u8 };
-                let _ = unsafe {
-                    Vec::from_raw_parts(data_mut, (*message_ptr).len, (*message_ptr).len)
-                };
+                let data_mut = (*message_ptr).data as *mut u8;
+                drop(Vec::from_raw_parts(
+                    data_mut,
+                    (*message_ptr).len,
+                    (*message_ptr).len,
+                ));
             }
 
             // free the pointer
-            let _ = unsafe { Box::from_raw(ptr) };
+            drop(Box::from_raw(ptr))
         }
     }
 }
diff --git a/bindings/c/src/lister.rs b/bindings/c/src/lister.rs
index 3376a011dd..b6a2a0e778 100644
--- a/bindings/c/src/lister.rs
+++ b/bindings/c/src/lister.rs
@@ -29,11 +29,13 @@ use super::*;
 /// @see opendal_operator_list()
 #[repr(C)]
 pub struct opendal_lister {
+    /// The pointer to the opendal::BlockingLister in the Rust code.
+    /// Only touch this on judging whether it is NULL.
     inner: *mut c_void,
 }
 
 impl opendal_lister {
-    fn deref_mut(&self) -> &mut core::BlockingLister {
+    fn deref_mut(&mut self) -> &mut core::BlockingLister {
         // Safety: the inner should never be null once constructed
         // The use-after-free is undefined behavior
         unsafe { &mut *(self.inner as *mut core::BlockingLister) }
@@ -55,7 +57,7 @@ impl opendal_lister {
     /// For examples, please see the comment section of opendal_operator_list()
     /// @see opendal_operator_list()
     #[no_mangle]
-    pub unsafe extern "C" fn opendal_lister_next(&self) -> opendal_result_lister_next {
+    pub unsafe extern "C" fn opendal_lister_next(&mut self) -> opendal_result_lister_next {
         let e = self.deref_mut().next();
         if e.is_none() {
             return opendal_result_lister_next {
@@ -83,8 +85,8 @@ impl opendal_lister {
     #[no_mangle]
     pub unsafe extern "C" fn opendal_lister_free(ptr: *mut opendal_lister) {
         if !ptr.is_null() {
-            let _ = Box::from_raw((*ptr).inner as *mut core::BlockingLister);
-            let _ = Box::from_raw(ptr);
+            drop(Box::from_raw((*ptr).inner as *mut core::BlockingLister));
+            drop(Box::from_raw(ptr));
         }
     }
 }
diff --git a/bindings/c/src/metadata.rs b/bindings/c/src/metadata.rs
index 60a3c42a3f..394e337c0e 100644
--- a/bindings/c/src/metadata.rs
+++ b/bindings/c/src/metadata.rs
@@ -55,8 +55,8 @@ impl opendal_metadata {
     #[no_mangle]
     pub unsafe extern "C" fn opendal_metadata_free(ptr: *mut opendal_metadata) {
         if !ptr.is_null() {
-            let _ = Box::from_raw((*ptr).inner as *mut core::Metadata);
-            let _ = Box::from_raw(ptr);
+            drop(Box::from_raw((*ptr).inner as *mut core::Metadata));
+            drop(Box::from_raw(ptr));
         }
     }
 
diff --git a/bindings/c/src/operator.rs b/bindings/c/src/operator.rs
index b3e070af3e..04df68ec45 100644
--- a/bindings/c/src/operator.rs
+++ b/bindings/c/src/operator.rs
@@ -16,6 +16,7 @@
 // under the License.
 
 use std::collections::HashMap;
+use std::ffi::c_void;
 use std::os::raw::c_char;
 use std::str::FromStr;
 
@@ -46,7 +47,15 @@ static RUNTIME: Lazy<tokio::runtime::Runtime> = Lazy::new(|| {
 pub struct opendal_operator {
     /// The pointer to the opendal::BlockingOperator in the Rust code.
     /// Only touch this on judging whether it is NULL.
-    ptr: *const core::BlockingOperator,
+    inner: *const c_void,
+}
+
+impl opendal_operator {
+    pub(crate) fn deref(&self) -> &core::BlockingOperator {
+        // Safety: the inner should never be null once constructed
+        // The use-after-free is undefined behavior
+        unsafe { &*(self.inner as *mut core::BlockingOperator) }
+    }
 }
 
 impl opendal_operator {
@@ -66,35 +75,11 @@ impl opendal_operator {
     /// opendal_operator_free(op);
     /// ```
     #[no_mangle]
-    pub unsafe extern "C" fn opendal_operator_free(op: *const opendal_operator) {
-        let _ = unsafe { Box::from_raw((*op).ptr as *mut core::BlockingOperator) };
-        let _ = unsafe { Box::from_raw(op as *mut opendal_operator) };
-    }
-}
-
-/// Returns a reference to the underlying [`od::BlockingOperator`]
-///
-/// # Safety
-///
-/// The ptr is a raw pointer to the underlying [`od::BlockingOperator`].
-/// It will only free when opendal_operator_free has been called.
-impl AsRef<core::BlockingOperator> for opendal_operator {
-    fn as_ref(&self) -> &core::BlockingOperator {
-        unsafe { &*(self.ptr) }
-    }
-}
-
-#[allow(clippy::from_over_into)]
-impl From<*const core::BlockingOperator> for opendal_operator {
-    fn from(value: *const core::BlockingOperator) -> Self {
-        Self { ptr: value }
-    }
-}
-
-#[allow(clippy::from_over_into)]
-impl From<*mut core::BlockingOperator> for opendal_operator {
-    fn from(value: *mut core::BlockingOperator) -> Self {
-        Self { ptr: value }
+    pub unsafe extern "C" fn opendal_operator_free(ptr: *const opendal_operator) {
+        if !ptr.is_null() {
+            drop(Box::from_raw((*ptr).inner as *mut core::BlockingOperator));
+            drop(Box::from_raw(ptr as *mut opendal_operator));
+        }
     }
 }
 
@@ -158,12 +143,11 @@ pub unsafe extern "C" fn opendal_operator_new(
     scheme: *const c_char,
     options: *const opendal_operator_options,
 ) -> opendal_result_operator_new {
-    if scheme.is_null() {
-        panic!("The scheme given is pointing at NULL");
-    }
-
-    let scheme_str = unsafe { std::ffi::CStr::from_ptr(scheme).to_str().unwrap() };
-    let scheme = match core::Scheme::from_str(scheme_str) {
+    assert!(!scheme.is_null());
+    let scheme = std::ffi::CStr::from_ptr(scheme)
+        .to_str()
+        .expect("malformed scheme");
+    let scheme = match core::Scheme::from_str(scheme) {
         Ok(s) => s,
         Err(e) => {
             return opendal_result_operator_new {
@@ -181,13 +165,12 @@ pub unsafe extern "C" fn opendal_operator_new(
     }
 
     match build_operator(scheme, map) {
-        Ok(op) => {
-            let op = opendal_operator::from(Box::into_raw(Box::new(op.blocking())));
-            opendal_result_operator_new {
-                op: Box::into_raw(Box::new(op)),
-                error: std::ptr::null_mut(),
-            }
-        }
+        Ok(op) => opendal_result_operator_new {
+            op: Box::into_raw(Box::new(opendal_operator {
+                inner: Box::into_raw(Box::new(op.blocking())) as _,
+            })),
+            error: std::ptr::null_mut(),
+        },
         Err(e) => opendal_result_operator_new {
             op: std::ptr::null_mut(),
             error: opendal_error::new(e),
@@ -241,17 +224,15 @@ 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_write(
-    op: *const opendal_operator,
+    op: &opendal_operator,
     path: *const c_char,
     bytes: opendal_bytes,
 ) -> *mut opendal_error {
-    if path.is_null() {
-        panic!("The path given is pointing at NULL");
-    }
-
-    let op = (*op).as_ref();
-    let path = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() };
-    match op.write(path, bytes) {
+    assert!(!path.is_null());
+    let path = std::ffi::CStr::from_ptr(path)
+        .to_str()
+        .expect("malformed path");
+    match op.deref().write(path, bytes) {
         Ok(_) => std::ptr::null_mut(),
         Err(e) => opendal_error::new(e),
     }
@@ -297,17 +278,14 @@ pub unsafe extern "C" fn opendal_operator_write(
 /// * If the `path` points to NULL, this function panics, i.e. exits with information
 #[no_mangle]
 pub unsafe extern "C" fn opendal_operator_read(
-    op: *const opendal_operator,
+    op: &opendal_operator,
     path: *const c_char,
 ) -> opendal_result_read {
-    if path.is_null() {
-        panic!("The path given is pointing at NULL");
-    }
-
-    let op = (*op).as_ref();
-    let path = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() };
-    let data = op.read(path);
-    match data {
+    assert!(!path.is_null());
+    let path = std::ffi::CStr::from_ptr(path)
+        .to_str()
+        .expect("malformed path");
+    match op.deref().read(path) {
         Ok(d) => {
             let v = Box::new(opendal_bytes::new(d));
             opendal_result_read {
@@ -360,16 +338,14 @@ pub unsafe extern "C" fn opendal_operator_read(
 /// * If the `path` points to NULL, this function panics, i.e. exits with information
 #[no_mangle]
 pub unsafe extern "C" fn opendal_operator_reader(
-    op: *const opendal_operator,
+    op: &opendal_operator,
     path: *const c_char,
 ) -> opendal_result_operator_reader {
-    if path.is_null() {
-        panic!("The path given is pointing at NULL");
-    }
-    let op = (*op).as_ref();
-
-    let path = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() };
-    let reader = match op.reader(path) {
+    assert!(!path.is_null());
+    let path = std::ffi::CStr::from_ptr(path)
+        .to_str()
+        .expect("malformed path");
+    let reader = match op.deref().reader(path) {
         Ok(reader) => reader,
         Err(err) => {
             return opendal_result_operator_reader {
@@ -429,16 +405,14 @@ pub unsafe extern "C" fn opendal_operator_reader(
 /// * If the `path` points to NULL, this function panics, i.e. exits with information
 #[no_mangle]
 pub unsafe extern "C" fn opendal_operator_writer(
-    op: *const opendal_operator,
+    op: &opendal_operator,
     path: *const c_char,
 ) -> opendal_result_operator_writer {
-    if path.is_null() {
-        panic!("The path given is pointing at NULL");
-    }
-    let op = (*op).as_ref();
-
-    let path = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() };
-    let writer = match op.writer(path) {
+    assert!(!path.is_null());
+    let path = std::ffi::CStr::from_ptr(path)
+        .to_str()
+        .expect("malformed path");
+    let writer = match op.deref().writer(path) {
         Ok(writer) => writer,
         Err(err) => {
             return opendal_result_operator_writer {
@@ -496,16 +470,14 @@ pub unsafe extern "C" fn opendal_operator_writer(
 /// * If the `path` points to NULL, this function panics, i.e. exits with information
 #[no_mangle]
 pub unsafe extern "C" fn opendal_operator_delete(
-    op: *const opendal_operator,
+    op: &opendal_operator,
     path: *const c_char,
 ) -> *mut opendal_error {
-    if path.is_null() {
-        panic!("The path given is pointing at NULL");
-    }
-
-    let op = (*op).as_ref();
-    let path = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() };
-    match op.delete(path) {
+    assert!(!path.is_null());
+    let path = std::ffi::CStr::from_ptr(path)
+        .to_str()
+        .expect("malformed path");
+    match op.deref().delete(path) {
         Ok(_) => std::ptr::null_mut(),
         Err(e) => opendal_error::new(e),
     }
@@ -550,16 +522,14 @@ pub unsafe extern "C" fn opendal_operator_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(
-    op: *const opendal_operator,
+    op: &opendal_operator,
     path: *const c_char,
 ) -> opendal_result_is_exist {
-    if path.is_null() {
-        panic!("The path given is pointing at NULL");
-    }
-
-    let op = (*op).as_ref();
-    let path = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() };
-    match op.is_exist(path) {
+    assert!(!path.is_null());
+    let path = std::ffi::CStr::from_ptr(path)
+        .to_str()
+        .expect("malformed path");
+    match op.deref().is_exist(path) {
         Ok(e) => opendal_result_is_exist {
             is_exist: e,
             error: std::ptr::null_mut(),
@@ -609,16 +579,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(
-    op: *const opendal_operator,
+    op: &opendal_operator,
     path: *const c_char,
 ) -> opendal_result_stat {
-    if path.is_null() {
-        panic!("The path given is pointing at NULL");
-    }
-
-    let op = (*op).as_ref();
-    let path = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() };
-    match op.stat(path) {
+    assert!(!path.is_null());
+    let path = std::ffi::CStr::from_ptr(path)
+        .to_str()
+        .expect("malformed path");
+    match op.deref().stat(path) {
         Ok(m) => opendal_result_stat {
             meta: Box::into_raw(Box::new(opendal_metadata::new(m))),
             error: std::ptr::null_mut(),
@@ -680,16 +648,14 @@ pub unsafe extern "C" fn opendal_operator_stat(
 /// * If the `path` points to NULL, this function panics, i.e. exits with information
 #[no_mangle]
 pub unsafe extern "C" fn opendal_operator_list(
-    op: *const opendal_operator,
+    op: &opendal_operator,
     path: *const c_char,
 ) -> opendal_result_list {
-    if path.is_null() {
-        panic!("The path given is pointing at NULL");
-    }
-
-    let op = (*op).as_ref();
-    let path = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() };
-    match op.lister(path) {
+    assert!(!path.is_null());
+    let path = std::ffi::CStr::from_ptr(path)
+        .to_str()
+        .expect("malformed path");
+    match op.deref().lister(path) {
         Ok(lister) => opendal_result_list {
             lister: Box::into_raw(Box::new(opendal_lister::new(lister))),
             error: std::ptr::null_mut(),
@@ -736,18 +702,17 @@ pub unsafe extern "C" fn opendal_operator_list(
 /// * If the `path` points to NULL, this function panics, i.e. exits with information
 #[no_mangle]
 pub unsafe extern "C" fn opendal_operator_create_dir(
-    op: *const opendal_operator,
+    op: &opendal_operator,
     path: *const c_char,
 ) -> *mut opendal_error {
-    if path.is_null() {
-        panic!("The path given is pointing at NULL");
-    }
-
-    let op = (*op).as_ref();
-    let path = unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() };
-    match op.create_dir(path) {
-        Ok(_) => std::ptr::null_mut(),
-        Err(e) => opendal_error::new(e),
+    assert!(!path.is_null());
+    let path = std::ffi::CStr::from_ptr(path)
+        .to_str()
+        .expect("malformed path");
+    if let Err(err) = op.deref().create_dir(path) {
+        opendal_error::new(err)
+    } else {
+        std::ptr::null_mut()
     }
 }
 
@@ -794,23 +759,22 @@ pub unsafe extern "C" fn opendal_operator_create_dir(
 /// * If the `src` or `dest` points to NULL, this function panics, i.e. exits with information
 #[no_mangle]
 pub unsafe extern "C" fn opendal_operator_rename(
-    op: *const opendal_operator,
+    op: &opendal_operator,
     src: *const c_char,
     dest: *const c_char,
 ) -> *mut opendal_error {
-    if src.is_null() {
-        panic!("The source path given is pointing at NULL");
-    }
-    if dest.is_null() {
-        panic!("The destination path given is pointing at NULL");
-    }
-
-    let op = (*op).as_ref();
-    let src = unsafe { std::ffi::CStr::from_ptr(src).to_str().unwrap() };
-    let dest = unsafe { std::ffi::CStr::from_ptr(dest).to_str().unwrap() };
-    match op.rename(src, dest) {
-        Ok(_) => std::ptr::null_mut(),
-        Err(e) => opendal_error::new(e),
+    assert!(!src.is_null());
+    assert!(!dest.is_null());
+    let src = std::ffi::CStr::from_ptr(src)
+        .to_str()
+        .expect("malformed src");
+    let dest = std::ffi::CStr::from_ptr(dest)
+        .to_str()
+        .expect("malformed dest");
+    if let Err(err) = op.deref().rename(src, dest) {
+        opendal_error::new(err)
+    } else {
+        std::ptr::null_mut()
     }
 }
 
@@ -857,22 +821,21 @@ pub unsafe extern "C" fn opendal_operator_rename(
 /// * If the `src` or `dest` points to NULL, this function panics, i.e. exits with information
 #[no_mangle]
 pub unsafe extern "C" fn opendal_operator_copy(
-    op: *const opendal_operator,
+    op: &opendal_operator,
     src: *const c_char,
     dest: *const c_char,
 ) -> *mut opendal_error {
-    if src.is_null() {
-        panic!("The source path given is pointing at NULL");
-    }
-    if dest.is_null() {
-        panic!("The destination path given is pointing at NULL");
-    }
-
-    let op = (*op).as_ref();
-    let src = unsafe { std::ffi::CStr::from_ptr(src).to_str().unwrap() };
-    let dest = unsafe { std::ffi::CStr::from_ptr(dest).to_str().unwrap() };
-    match op.copy(src, dest) {
-        Ok(_) => std::ptr::null_mut(),
-        Err(e) => opendal_error::new(e),
+    assert!(!src.is_null());
+    assert!(!dest.is_null());
+    let src = std::ffi::CStr::from_ptr(src)
+        .to_str()
+        .expect("malformed src");
+    let dest = std::ffi::CStr::from_ptr(dest)
+        .to_str()
+        .expect("malformed dest");
+    if let Err(err) = op.deref().copy(src, dest) {
+        opendal_error::new(err)
+    } else {
+        std::ptr::null_mut()
     }
 }
diff --git a/bindings/c/src/operator_info.rs b/bindings/c/src/operator_info.rs
index 36efe0c8b4..4e42962a78 100644
--- a/bindings/c/src/operator_info.rs
+++ b/bindings/c/src/operator_info.rs
@@ -26,6 +26,8 @@ use crate::opendal_operator;
 /// of operator.
 #[repr(C)]
 pub struct opendal_operator_info {
+    /// The pointer to the opendal::OperatorInfo in the Rust code.
+    /// Only touch this on judging whether it is NULL.
     inner: *mut c_void,
 }
 
@@ -161,10 +163,8 @@ impl opendal_operator_info {
     /// opendal_operator_info_free(info);
     /// ```
     #[no_mangle]
-    pub unsafe extern "C" fn opendal_operator_info_new(op: *const opendal_operator) -> *mut Self {
-        let op = (*op).as_ref();
-        let info = op.info();
-
+    pub unsafe extern "C" fn opendal_operator_info_new(op: &opendal_operator) -> *mut Self {
+        let info = op.deref().info();
         Box::into_raw(Box::new(Self {
             inner: Box::into_raw(Box::new(info)) as _,
         }))
@@ -174,8 +174,8 @@ impl opendal_operator_info {
     #[no_mangle]
     pub unsafe extern "C" fn opendal_operator_info_free(ptr: *mut Self) {
         if !ptr.is_null() {
-            let _ = Box::from_raw((*ptr).inner as *mut core::OperatorInfo);
-            let _ = Box::from_raw(ptr);
+            drop(Box::from_raw((*ptr).inner as *mut core::OperatorInfo));
+            drop(Box::from_raw(ptr));
         }
     }
 
diff --git a/bindings/c/src/reader.rs b/bindings/c/src/reader.rs
index 5d15fcba0a..1c34658e1c 100644
--- a/bindings/c/src/reader.rs
+++ b/bindings/c/src/reader.rs
@@ -28,11 +28,13 @@ use super::*;
 /// a opendal::BlockingReader, which is inside the Rust core code.
 #[repr(C)]
 pub struct opendal_reader {
+    /// The pointer to the opendal::StdReader in the Rust code.
+    /// Only touch this on judging whether it is NULL.
     inner: *mut c_void,
 }
 
 impl opendal_reader {
-    fn deref_mut(&self) -> &mut core::StdReader {
+    fn deref_mut(&mut self) -> &mut core::StdReader {
         // Safety: the inner should never be null once constructed
         // The use-after-free is undefined behavior
         unsafe { &mut *(self.inner as *mut core::StdReader) }
@@ -49,15 +51,12 @@ impl opendal_reader {
     /// \brief Read data from the reader.
     #[no_mangle]
     pub unsafe extern "C" fn opendal_reader_read(
-        &self,
+        &mut self,
         buf: *mut u8,
         len: usize,
     ) -> opendal_result_reader_read {
-        if buf.is_null() {
-            panic!("buf is NULL");
-        }
-
-        let buf = unsafe { std::slice::from_raw_parts_mut(buf, len) };
+        assert!(!buf.is_null());
+        let buf = std::slice::from_raw_parts_mut(buf, len);
         match self.deref_mut().read(buf) {
             Ok(n) => opendal_result_reader_read {
                 size: n,
@@ -77,8 +76,8 @@ impl opendal_reader {
     #[no_mangle]
     pub unsafe extern "C" fn opendal_reader_free(ptr: *mut opendal_reader) {
         if !ptr.is_null() {
-            let _ = Box::from_raw((*ptr).inner as *mut core::StdReader);
-            let _ = Box::from_raw(ptr);
+            drop(Box::from_raw((*ptr).inner as *mut core::StdReader));
+            drop(Box::from_raw(ptr));
         }
     }
 }
diff --git a/bindings/c/src/types.rs b/bindings/c/src/types.rs
index 932f63b627..051724a671 100644
--- a/bindings/c/src/types.rs
+++ b/bindings/c/src/types.rs
@@ -48,21 +48,18 @@ impl opendal_bytes {
 
     /// \brief Frees the heap memory used by the opendal_bytes
     #[no_mangle]
-    pub unsafe extern "C" fn opendal_bytes_free(bs: *mut opendal_bytes) {
-        if !bs.is_null() {
-            let data_mut = unsafe { (*bs).data as *mut u8 };
-            // free the vector
-            let _ = unsafe { Vec::from_raw_parts(data_mut, (*bs).len, (*bs).len) };
-            // free the pointer
-            let _ = unsafe { Box::from_raw(bs) };
+    pub unsafe extern "C" fn opendal_bytes_free(ptr: *mut opendal_bytes) {
+        if !ptr.is_null() {
+            let data_mut = (*ptr).data as *mut u8;
+            drop(Vec::from_raw_parts(data_mut, (*ptr).len, (*ptr).len));
+            drop(Box::from_raw(ptr));
         }
     }
 }
 
-#[allow(clippy::from_over_into)]
-impl Into<Buffer> for opendal_bytes {
-    fn into(self) -> Buffer {
-        let slice = unsafe { std::slice::from_raw_parts(self.data, self.len) };
+impl From<opendal_bytes> for Buffer {
+    fn from(v: opendal_bytes) -> Self {
+        let slice = unsafe { std::slice::from_raw_parts(v.data, v.len) };
         Buffer::from(bytes::Bytes::copy_from_slice(slice))
     }
 }
@@ -77,7 +74,7 @@ impl Into<Buffer> for opendal_bytes {
 /// @see opendal_operator_options_set This function allow you to set the options
 #[repr(C)]
 pub struct opendal_operator_options {
-    /// The pointer to the Rust HashMap<String, String>
+    /// The pointer to the HashMap<String, String> in the Rust code.
     /// Only touch this on judging whether it is NULL.
     inner: *mut c_void,
 }
@@ -150,8 +147,8 @@ impl opendal_operator_options {
     #[no_mangle]
     pub unsafe extern "C" fn opendal_operator_options_free(ptr: *mut opendal_operator_options) {
         if !ptr.is_null() {
-            let _ = Box::from_raw((*ptr).inner as *mut HashMap<String, String>);
-            let _ = Box::from_raw(ptr);
+            drop(Box::from_raw((*ptr).inner as *mut HashMap<String, String>));
+            drop(Box::from_raw(ptr));
         }
     }
 }
diff --git a/bindings/c/src/writer.rs b/bindings/c/src/writer.rs
index 36cc578790..67ac7d53f4 100644
--- a/bindings/c/src/writer.rs
+++ b/bindings/c/src/writer.rs
@@ -25,11 +25,13 @@ use super::*;
 /// an opendal::BlockingWriter, which is inside the Rust core code.
 #[repr(C)]
 pub struct opendal_writer {
+    /// The pointer to the opendal::BlockingWriter in the Rust code.
+    /// Only touch this on judging whether it is NULL.
     inner: *mut c_void,
 }
 
 impl opendal_writer {
-    fn deref_mut(&self) -> &mut core::BlockingWriter {
+    fn deref_mut(&mut self) -> &mut core::BlockingWriter {
         // Safety: the inner should never be null once constructed
         // The use-after-free is undefined behavior
         unsafe { &mut *(self.inner as *mut core::BlockingWriter) }
@@ -46,7 +48,7 @@ impl opendal_writer {
     /// \brief Write data to the writer.
     #[no_mangle]
     pub unsafe extern "C" fn opendal_writer_write(
-        &self,
+        &mut self,
         bytes: opendal_bytes,
     ) -> opendal_result_writer_write {
         let size = bytes.len;
@@ -70,9 +72,9 @@ impl opendal_writer {
     #[no_mangle]
     pub unsafe extern "C" fn opendal_writer_free(ptr: *mut opendal_writer) {
         if !ptr.is_null() {
-            let _ = (&*ptr).deref_mut().close();
-            let _ = unsafe { Box::from_raw((*ptr).inner as *mut core::BlockingWriter) };
-            let _ = unsafe { Box::from_raw(ptr) };
+            let _ = (*ptr).deref_mut().close();
+            drop(Box::from_raw((*ptr).inner as *mut core::BlockingWriter));
+            drop(Box::from_raw(ptr));
         }
     }
 }