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

xuanwo 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 2a332f3f15 refactor: resolve c pointers const (#5171)
2a332f3f15 is described below

commit 2a332f3f154d6b3d24f289d8a31b990c8bca2082
Author: tison <[email protected]>
AuthorDate: Mon Oct 14 03:15:26 2024 -0600

    refactor: resolve c pointers const (#5171)
    
    * refactor: resolve c pointers const
    
    Signed-off-by: tison <[email protected]>
    
    * fix zig cases
    
    Signed-off-by: tison <[email protected]>
    
    * fix swift cases
    
    Signed-off-by: tison <[email protected]>
    
    * fix go cases
    
    Signed-off-by: tison <[email protected]>
    
    * pass pointer to opendal_bytes_free
    
    Signed-off-by: tison <[email protected]>
    
    * try fix go case
    
    Signed-off-by: tison <[email protected]>
    
    * fix(bindings/go): make opendal_bytes pointer
    
    Signed-off-by: Hanchin Hsieh <[email protected]>
    
    ---------
    
    Signed-off-by: tison <[email protected]>
    Signed-off-by: Hanchin Hsieh <[email protected]>
    Co-authored-by: Hanchin Hsieh <[email protected]>
---
 bindings/c/README.md                               |  8 ++--
 bindings/c/examples/basic.c                        |  8 ++--
 bindings/c/include/opendal.h                       | 17 +++----
 bindings/c/src/error.rs                            | 16 +------
 bindings/c/src/operator.rs                         | 22 +++++----
 bindings/c/src/result.rs                           |  2 +-
 bindings/c/src/types.rs                            | 52 +++++++++++++---------
 bindings/c/src/writer.rs                           |  2 +-
 bindings/c/tests/bdd.cpp                           | 12 ++---
 bindings/c/tests/error_msg.cpp                     |  2 +-
 bindings/c/tests/list.cpp                          |  2 +-
 bindings/go/error.go                               |  2 +-
 bindings/go/reader.go                              |  9 ++--
 bindings/go/stat.go                                |  1 -
 bindings/go/types.go                               | 14 +++---
 bindings/go/write.go                               |  4 +-
 .../swift/OpenDAL/Sources/OpenDAL/Operator.swift   | 14 +++---
 .../OpenDAL/Tests/OpenDALTests/OpenDALTests.swift  |  4 +-
 bindings/zig/test/bdd.zig                          | 22 ++++-----
 19 files changed, 107 insertions(+), 106 deletions(-)

diff --git a/bindings/c/README.md b/bindings/c/README.md
index bd225ceb14..398f1a1f19 100644
--- a/bindings/c/README.md
+++ b/bindings/c/README.md
@@ -32,18 +32,18 @@ int main()
 
     /* We can read it out, make sure the data is the same */
     opendal_result_read r = opendal_operator_read(op, "/testpath");
-    opendal_bytes* read_bytes = r.data;
+    opendal_bytes read_bytes = r.data;
     assert(r.error == NULL);
-    assert(read_bytes->len == 24);
+    assert(read_bytes.len == 24);
 
     /* Lets print it out */
     for (int i = 0; i < 24; ++i) {
-        printf("%c", read_bytes->data[i]);
+        printf("%c", read_bytes.data[i]);
     }
     printf("\n");
 
     /* the opendal_bytes read is heap allocated, please free it */
-    opendal_bytes_free(read_bytes);
+    opendal_bytes_free(&read_bytes);
 
     /* the operator_ptr is also heap allocated */
     opendal_operator_free(&op);
diff --git a/bindings/c/examples/basic.c b/bindings/c/examples/basic.c
index 5e4e7925ba..af55faeea0 100644
--- a/bindings/c/examples/basic.c
+++ b/bindings/c/examples/basic.c
@@ -42,18 +42,18 @@ int main()
 
     /* We can read it out, make sure the data is the same */
     opendal_result_read r = opendal_operator_read(op, "/testpath");
-    opendal_bytes* read_bytes = r.data;
+    opendal_bytes read_bytes = r.data;
     assert(r.error == NULL);
-    assert(read_bytes->len == 24);
+    assert(read_bytes.len == 24);
 
     /* Lets print it out */
     for (int i = 0; i < 24; ++i) {
-        printf("%c", read_bytes->data[i]);
+        printf("%c", read_bytes.data[i]);
     }
     printf("\n");
 
     /* the opendal_bytes read is heap allocated, please free it */
-    opendal_bytes_free(read_bytes);
+    opendal_bytes_free(&read_bytes);
 
     /* the operator_ptr is also heap allocated */
     opendal_operator_free(op);
diff --git a/bindings/c/include/opendal.h b/bindings/c/include/opendal.h
index 4fba909163..8eeacf7c51 100644
--- a/bindings/c/include/opendal.h
+++ b/bindings/c/include/opendal.h
@@ -94,7 +94,7 @@ typedef struct opendal_bytes {
   /**
    * Pointing to the byte array on heap
    */
-  const uint8_t *data;
+  uint8_t *data;
   /**
    * The length of the byte array
    */
@@ -113,7 +113,7 @@ typedef struct opendal_bytes {
  * represents no error has taken placed**. If any error has taken place, the 
caller should check
  * the error code and print the error message.
  *
- * The error code is represented in opendal_code, which is a enum on different 
type of errors.
+ * The error code is represented in opendal_code, which is an enum on 
different type of errors.
  * The error messages is represented in opendal_bytes, which is a non-null 
terminated byte array.
  *
  * \note 1. The error message is on heap, so the error needs to be freed by 
the caller, by calling
@@ -217,7 +217,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 void *inner;
+  void *inner;
 } opendal_operator;
 
 /**
@@ -273,7 +273,7 @@ typedef struct opendal_result_read {
   /**
    * The byte array with length returned by read operations
    */
-  struct opendal_bytes *data;
+  struct opendal_bytes data;
   /**
    * The error, if ok, it is null
    */
@@ -814,7 +814,7 @@ struct opendal_result_operator_new 
opendal_operator_new(const char *scheme,
  */
 struct opendal_error *opendal_operator_write(const struct opendal_operator *op,
                                              const char *path,
-                                             struct opendal_bytes bytes);
+                                             const struct opendal_bytes 
*bytes);
 
 /**
  * \brief Blocking read the data from `path`.
@@ -842,8 +842,9 @@ struct opendal_error *opendal_operator_write(const struct 
opendal_operator *op,
  * opendal_result_read r = opendal_operator_read(op, "testpath");
  * assert(r.error == NULL);
  *
- * opendal_bytes *bytes = r.data;
- * assert(bytes->len == 13);
+ * opendal_bytes bytes = r.data;
+ * assert(bytes.len == 13);
+ * opendal_bytes_free(&bytes);
  * ```
  *
  * # Safety
@@ -1394,7 +1395,7 @@ void opendal_reader_free(struct opendal_reader *ptr);
  * \brief Write data to the writer.
  */
 struct opendal_result_writer_write opendal_writer_write(struct opendal_writer 
*self,
-                                                        struct opendal_bytes 
bytes);
+                                                        const struct 
opendal_bytes *bytes);
 
 /**
  * \brief Frees the heap memory used by the opendal_writer.
diff --git a/bindings/c/src/error.rs b/bindings/c/src/error.rs
index d1c6155ee7..97388ddfe2 100644
--- a/bindings/c/src/error.rs
+++ b/bindings/c/src/error.rs
@@ -82,7 +82,7 @@ impl From<core::ErrorKind> for opendal_code {
 /// represents no error has taken placed**. If any error has taken place, the 
caller should check
 /// the error code and print the error message.
 ///
-/// The error code is represented in opendal_code, which is a enum on 
different type of errors.
+/// The error code is represented in opendal_code, which is an enum on 
different type of errors.
 /// The error messages is represented in opendal_bytes, which is a non-null 
terminated byte array.
 ///
 /// \note 1. The error message is on heap, so the error needs to be freed by 
the caller, by calling
@@ -114,19 +114,7 @@ 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;
-            let message_ptr = message_ptr as *const opendal_bytes as *mut 
opendal_bytes;
-            if !message_ptr.is_null() {
-                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
-            drop(Box::from_raw(ptr))
+            drop(Box::from_raw(ptr));
         }
     }
 }
diff --git a/bindings/c/src/operator.rs b/bindings/c/src/operator.rs
index 04df68ec45..ba03f9c2ae 100644
--- a/bindings/c/src/operator.rs
+++ b/bindings/c/src/operator.rs
@@ -47,7 +47,7 @@ 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.
-    inner: *const c_void,
+    inner: *mut c_void,
 }
 
 impl opendal_operator {
@@ -226,7 +226,7 @@ pub unsafe extern "C" fn opendal_operator_new(
 pub unsafe extern "C" fn opendal_operator_write(
     op: &opendal_operator,
     path: *const c_char,
-    bytes: opendal_bytes,
+    bytes: &opendal_bytes,
 ) -> *mut opendal_error {
     assert!(!path.is_null());
     let path = std::ffi::CStr::from_ptr(path)
@@ -263,8 +263,9 @@ pub unsafe extern "C" fn opendal_operator_write(
 /// opendal_result_read r = opendal_operator_read(op, "testpath");
 /// assert(r.error == NULL);
 ///
-/// opendal_bytes *bytes = r.data;
-/// assert(bytes->len == 13);
+/// opendal_bytes bytes = r.data;
+/// assert(bytes.len == 13);
+/// opendal_bytes_free(&bytes);
 /// ```
 ///
 /// # Safety
@@ -286,15 +287,12 @@ pub unsafe extern "C" fn opendal_operator_read(
         .to_str()
         .expect("malformed path");
     match op.deref().read(path) {
-        Ok(d) => {
-            let v = Box::new(opendal_bytes::new(d));
-            opendal_result_read {
-                data: Box::into_raw(v),
-                error: std::ptr::null_mut(),
-            }
-        }
+        Ok(b) => opendal_result_read {
+            data: opendal_bytes::new(b),
+            error: std::ptr::null_mut(),
+        },
         Err(e) => opendal_result_read {
-            data: std::ptr::null_mut(),
+            data: opendal_bytes::empty(),
             error: opendal_error::new(e),
         },
     }
diff --git a/bindings/c/src/result.rs b/bindings/c/src/result.rs
index ba7e1c64a0..e9aede5d47 100644
--- a/bindings/c/src/result.rs
+++ b/bindings/c/src/result.rs
@@ -49,7 +49,7 @@ pub struct opendal_result_operator_new {
 #[repr(C)]
 pub struct opendal_result_read {
     /// The byte array with length returned by read operations
-    pub data: *mut opendal_bytes,
+    pub data: opendal_bytes,
     /// The error, if ok, it is null
     pub error: *mut opendal_error,
 }
diff --git a/bindings/c/src/types.rs b/bindings/c/src/types.rs
index 795c7a73b5..cba8f25400 100644
--- a/bindings/c/src/types.rs
+++ b/bindings/c/src/types.rs
@@ -31,7 +31,7 @@ use opendal::Buffer;
 #[repr(C)]
 pub struct opendal_bytes {
     /// Pointing to the byte array on heap
-    pub data: *const u8,
+    pub data: *mut u8,
     /// The length of the byte array
     pub len: usize,
     /// The capacity of the byte array
@@ -39,17 +39,21 @@ pub struct opendal_bytes {
 }
 
 impl opendal_bytes {
+    pub(crate) fn empty() -> Self {
+        Self {
+            data: std::ptr::null_mut(),
+            len: 0,
+            capacity: 0,
+        }
+    }
+
     /// Construct a [`opendal_bytes`] from the Rust [`Vec`] of bytes
-    pub(crate) fn new(buf: Buffer) -> Self {
-        let vec = buf.to_vec();
-        let mut buf = std::mem::ManuallyDrop::new(vec);
-        let data = buf.as_mut_ptr();
-        let len = buf.len();
-        let capacity = buf.capacity();
+    pub(crate) fn new(b: Buffer) -> Self {
+        let mut b = std::mem::ManuallyDrop::new(b.to_vec());
         Self {
-            data,
-            len,
-            capacity,
+            data: b.as_mut_ptr(),
+            len: b.len(),
+            capacity: b.capacity(),
         }
     }
 
@@ -57,20 +61,28 @@ impl opendal_bytes {
     #[no_mangle]
     pub unsafe extern "C" fn opendal_bytes_free(ptr: *mut opendal_bytes) {
         if !ptr.is_null() {
-            // transmuting `*const u8` to `*mut u8` is undefined behavior in 
any cases
-            // however, fields type of `opendal_bytes` is already related to 
the zig binding
-            // it should be fixed later
-            let _ = Vec::from_raw_parts((*ptr).data as *mut u8, (*ptr).len, 
(*ptr).capacity);
-            // it is too weird that call `Box::new` outside 
`opendal_bytes::new` but dealloc it here
-            // also, boxing `opendal_bytes` might not be necessary
-            // `data` points to heap, so `opendal_bytes` could be passed as a 
stack value
-            let _ = Box::from_raw(ptr);
+            let bs = &mut *ptr;
+            if !bs.data.is_null() {
+                drop(Vec::from_raw_parts(bs.data, bs.len, bs.capacity));
+                bs.data = std::ptr::null_mut();
+                bs.len = 0;
+                bs.capacity = 0;
+            }
+        }
+    }
+}
+
+impl Drop for opendal_bytes {
+    fn drop(&mut self) {
+        unsafe {
+            // Safety: the pointer is always valid
+            Self::opendal_bytes_free(self);
         }
     }
 }
 
-impl From<opendal_bytes> for Buffer {
-    fn from(v: opendal_bytes) -> Self {
+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))
     }
diff --git a/bindings/c/src/writer.rs b/bindings/c/src/writer.rs
index 67ac7d53f4..a72dbbbb69 100644
--- a/bindings/c/src/writer.rs
+++ b/bindings/c/src/writer.rs
@@ -49,7 +49,7 @@ impl opendal_writer {
     #[no_mangle]
     pub unsafe extern "C" fn opendal_writer_write(
         &mut self,
-        bytes: opendal_bytes,
+        bytes: &opendal_bytes,
     ) -> opendal_result_writer_write {
         let size = bytes.len;
         match self.deref_mut().write(bytes) {
diff --git a/bindings/c/tests/bdd.cpp b/bindings/c/tests/bdd.cpp
index 39856e81e5..65e97f52bf 100644
--- a/bindings/c/tests/bdd.cpp
+++ b/bindings/c/tests/bdd.cpp
@@ -61,7 +61,7 @@ TEST_F(OpendalBddTest, FeatureTest)
         .data = (uint8_t*)this->content.c_str(),
         .len = this->content.length(),
     };
-    opendal_error* error = opendal_operator_write(this->p, this->path.c_str(), 
data);
+    opendal_error* error = opendal_operator_write(this->p, this->path.c_str(), 
&data);
     EXPECT_EQ(error, nullptr);
 
     // The blocking file "test" should exist
@@ -85,9 +85,9 @@ TEST_F(OpendalBddTest, FeatureTest)
     // The blocking file "test" must have content "Hello, World!"
     struct opendal_result_read r = opendal_operator_read(this->p, 
this->path.c_str());
     EXPECT_EQ(r.error, nullptr);
-    EXPECT_EQ(r.data->len, this->content.length());
-    for (int i = 0; i < r.data->len; i++) {
-        EXPECT_EQ(this->content[i], (char)(r.data->data[i]));
+    EXPECT_EQ(r.data.len, this->content.length());
+    for (int i = 0; i < r.data.len; i++) {
+        EXPECT_EQ(this->content[i], (char)(r.data.data[i]));
     }
 
     // The blocking file should be deleted
@@ -99,7 +99,7 @@ TEST_F(OpendalBddTest, FeatureTest)
 
     opendal_result_operator_writer writer = opendal_operator_writer(this->p, 
this->path.c_str());
     EXPECT_EQ(writer.error, nullptr);
-    opendal_result_writer_write w = opendal_writer_write(writer.writer, data);
+    opendal_result_writer_write w = opendal_writer_write(writer.writer, &data);
     EXPECT_EQ(w.error, nullptr);
     EXPECT_EQ(w.size, this->content.length());
     opendal_writer_free(writer.writer);
@@ -120,7 +120,7 @@ TEST_F(OpendalBddTest, FeatureTest)
     error = opendal_operator_delete(this->p, this->path.c_str());
     EXPECT_EQ(error, nullptr);
 
-    opendal_bytes_free(r.data);
+    opendal_bytes_free(&r.data);
 
     // The directory "tmpdir/" should exist and should be a directory
     error = opendal_operator_create_dir(this->p, "tmpdir/");
diff --git a/bindings/c/tests/error_msg.cpp b/bindings/c/tests/error_msg.cpp
index f2087ea3b0..516d27865a 100644
--- a/bindings/c/tests/error_msg.cpp
+++ b/bindings/c/tests/error_msg.cpp
@@ -59,7 +59,7 @@ TEST_F(OpendalErrorTest, ErrorReadTest)
     ASSERT_GT(error_msg->len, 0);
 
     // the opendal_bytes read is heap allocated, please free it
-    opendal_bytes_free(r.data);
+    opendal_bytes_free(&r.data);
 
     // free the error
     opendal_error_free(r.error);
diff --git a/bindings/c/tests/list.cpp b/bindings/c/tests/list.cpp
index d4e31cf79e..3b64fef460 100644
--- a/bindings/c/tests/list.cpp
+++ b/bindings/c/tests/list.cpp
@@ -65,7 +65,7 @@ TEST_F(OpendalListTest, ListDirTest)
     };
 
     // write must succeed
-    EXPECT_EQ(opendal_operator_write(this->p, path.c_str(), data),
+    EXPECT_EQ(opendal_operator_write(this->p, path.c_str(), &data),
         nullptr);
 
     // list must succeed since the write succeeded
diff --git a/bindings/go/error.go b/bindings/go/error.go
index 33ed9b8c28..37ea26f070 100644
--- a/bindings/go/error.go
+++ b/bindings/go/error.go
@@ -77,7 +77,7 @@ func parseError(ctx context.Context, err *opendalError) error 
{
        defer free(err)
        return &Error{
                code:    ErrorCode(err.code),
-               message: string(parseBytes(&err.message)),
+               message: string(parseBytes(err.message)),
        }
 }
 
diff --git a/bindings/go/reader.go b/bindings/go/reader.go
index c6fbb68238..ce26ce663e 100644
--- a/bindings/go/reader.go
+++ b/bindings/go/reader.go
@@ -68,8 +68,7 @@ func (op *Operator) Read(path string) ([]byte, error) {
        data := parseBytes(bytes)
        if len(data) > 0 {
                free := getFFI[bytesFree](op.ctx, symBytesFree)
-               free(bytes)
-
+               free(&bytes)
        }
        return data, nil
 }
@@ -203,17 +202,17 @@ func (r *Reader) Close() error {
 
 const symOperatorRead = "opendal_operator_read"
 
-type operatorRead func(op *opendalOperator, path string) (*opendalBytes, error)
+type operatorRead func(op *opendalOperator, path string) (opendalBytes, error)
 
 var withOperatorRead = withFFI(ffiOpts{
        sym:    symOperatorRead,
        rType:  &typeResultRead,
        aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
 }, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues 
...unsafe.Pointer)) operatorRead {
-       return func(op *opendalOperator, path string) (*opendalBytes, error) {
+       return func(op *opendalOperator, path string) (opendalBytes, error) {
                bytePath, err := unix.BytePtrFromString(path)
                if err != nil {
-                       return nil, err
+                       return opendalBytes{}, err
                }
                var result resultRead
                ffiCall(
diff --git a/bindings/go/stat.go b/bindings/go/stat.go
index 6b83ad605c..7eb7345939 100644
--- a/bindings/go/stat.go
+++ b/bindings/go/stat.go
@@ -96,7 +96,6 @@ func (op *Operator) Stat(path string) (*Metadata, error) {
 //     } else {
 //             fmt.Println("The file does not exist")
 //     }
-//
 func (op *Operator) IsExist(path string) (bool, error) {
        isExist := getFFI[operatorIsExist](op.ctx, symOperatorIsExist)
        return isExist(op.inner, path)
diff --git a/bindings/go/types.go b/bindings/go/types.go
index 613825af51..5751f0cdb0 100644
--- a/bindings/go/types.go
+++ b/bindings/go/types.go
@@ -38,7 +38,7 @@ var (
        typeResultRead = ffi.Type{
                Type: ffi.Struct,
                Elements: &[]*ffi.Type{
-                       &ffi.TypePointer,
+                       &typeBytes,
                        &ffi.TypePointer,
                        nil,
                }[0],
@@ -217,7 +217,7 @@ type resultOperatorNew struct {
 type opendalOperator struct{}
 
 type resultRead struct {
-       data  *opendalBytes
+       data  opendalBytes
        error *opendalError
 }
 
@@ -284,7 +284,7 @@ type opendalResultListerNext struct {
 
 type opendalEntry struct{}
 
-func toOpendalBytes(data []byte) opendalBytes {
+func toOpendalBytes(data []byte) *opendalBytes {
        var ptr *byte
        l := len(data)
        if l > 0 {
@@ -293,15 +293,15 @@ func toOpendalBytes(data []byte) opendalBytes {
                var b byte
                ptr = &b
        }
-       return opendalBytes{
+       return &opendalBytes{
                data:     ptr,
                len:      uintptr(l),
-               capacity: uintptr(l),
+               capacity: uintptr(cap(data)),
        }
 }
 
-func parseBytes(b *opendalBytes) (data []byte) {
-       if b == nil || b.len == 0 {
+func parseBytes(b opendalBytes) (data []byte) {
+       if b.len == 0 {
                return nil
        }
        data = make([]byte, b.len)
diff --git a/bindings/go/write.go b/bindings/go/write.go
index d287524416..f0c23b816f 100644
--- a/bindings/go/write.go
+++ b/bindings/go/write.go
@@ -196,7 +196,7 @@ type operatorWrite func(op *opendalOperator, path string, 
data []byte) error
 var withOperatorWrite = withFFI(ffiOpts{
        sym:    symOperatorWrite,
        rType:  &ffi.TypePointer,
-       aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer, &typeBytes},
+       aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer, 
&ffi.TypePointer},
 }, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues 
...unsafe.Pointer)) operatorWrite {
        return func(op *opendalOperator, path string, data []byte) error {
                bytePath, err := unix.BytePtrFromString(path)
@@ -290,7 +290,7 @@ type writerWrite func(r *opendalWriter, buf []byte) (size 
int, err error)
 var withWriterWrite = withFFI(ffiOpts{
        sym:    symWriterWrite,
        rType:  &typeResultWriterWrite,
-       aTypes: []*ffi.Type{&ffi.TypePointer, &typeBytes},
+       aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
 }, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues 
...unsafe.Pointer)) writerWrite {
        return func(r *opendalWriter, data []byte) (size int, err error) {
                bytes := toOpendalBytes(data)
diff --git a/bindings/swift/OpenDAL/Sources/OpenDAL/Operator.swift 
b/bindings/swift/OpenDAL/Sources/OpenDAL/Operator.swift
index 2ce27551e3..6e2bb3a7bd 100644
--- a/bindings/swift/OpenDAL/Sources/OpenDAL/Operator.swift
+++ b/bindings/swift/OpenDAL/Sources/OpenDAL/Operator.swift
@@ -57,11 +57,13 @@ public class Operator {
         self.nativeOp = UnsafePointer(ret.op)!
     }
 
-    public func blockingWrite(_ data: Data, to path: String) throws {
-        let ret = data.withUnsafeBytes { dataPointer in
+    public func blockingWrite(_ data: inout Data, to path: String) throws {
+        let ret = data.withUnsafeMutableBytes { dataPointer in
             let address = dataPointer.baseAddress!.assumingMemoryBound(to: 
UInt8.self)
-            let bytes = opendal_bytes(data: address, len: 
UInt(dataPointer.count))
-            return opendal_operator_write(nativeOp, path, bytes)
+            let bytes = opendal_bytes(data: address, len: 
UInt(dataPointer.count), capacity: UInt(dataPointer.count))
+            return withUnsafePointer(to: bytes) { bytesPointer in
+                opendal_operator_write(nativeOp, path, bytesPointer)
+            }
         }
 
         if let err = ret {
@@ -79,7 +81,7 @@ public class Operator {
     }
 
     public func blockingRead(_ path: String) throws -> Data {
-        let ret = opendal_operator_read(nativeOp, path)
+        var ret = opendal_operator_read(nativeOp, path)
         if let err = ret.error {
             defer {
                 opendal_error_free(err)
@@ -93,6 +95,6 @@ public class Operator {
             )
         }
 
-        return Data(openDALBytes: ret.data)
+        return withUnsafeMutablePointer(to: &ret.data) { Data(openDALBytes: 
$0) }
     }
 }
diff --git a/bindings/swift/OpenDAL/Tests/OpenDALTests/OpenDALTests.swift 
b/bindings/swift/OpenDAL/Tests/OpenDALTests/OpenDALTests.swift
index ef17c78874..304e6d5a27 100644
--- a/bindings/swift/OpenDAL/Tests/OpenDALTests/OpenDALTests.swift
+++ b/bindings/swift/OpenDAL/Tests/OpenDALTests/OpenDALTests.swift
@@ -28,8 +28,8 @@ final class OpenDALTests: XCTestCase {
             ]
         )
 
-        let testContents = Data([1, 2, 3, 4])
-        try op.blockingWrite(testContents, to: "test")
+        var testContents = Data([1, 2, 3, 4])
+        try op.blockingWrite(&testContents, to: "test")
 
         let readContents = try op.blockingRead("test")
 
diff --git a/bindings/zig/test/bdd.zig b/bindings/zig/test/bdd.zig
index 98d49525ce..8d2f6ce79f 100644
--- a/bindings/zig/test/bdd.zig
+++ b/bindings/zig/test/bdd.zig
@@ -24,7 +24,7 @@ test "Opendal BDD test" {
     const c_str = [*:0]const u8; // define a type for 'const char*' in C
 
     const OpendalBDDTest = struct {
-        p: [*c]const opendal.c.opendal_operator,
+        p: [*c]opendal.c.opendal_operator,
         scheme: c_str,
         path: c_str,
         content: c_str,
@@ -57,13 +57,15 @@ test "Opendal BDD test" {
     var testkit = OpendalBDDTest.init();
     defer testkit.deinit();
 
+    const allocator = std.heap.page_allocator;
+    const dupe_content = try allocator.dupeZ(u8, 
std.mem.span(testkit.content));
     // When Blocking write path "test" with content "Hello, World!"
     const data: opendal.c.opendal_bytes = .{
-        .data = testkit.content,
-        // c_str does not have len field (.* is ptr)
-        .len = std.mem.len(testkit.content),
+        .data = dupe_content.ptr,
+        .len = dupe_content.len,
+        .capacity = dupe_content.len,
     };
-    const result = opendal.c.opendal_operator_write(testkit.p, testkit.path, 
data);
+    const result = opendal.c.opendal_operator_write(testkit.p, testkit.path, 
&data);
     try testing.expectEqual(result, null);
 
     // The blocking file "test" should exist
@@ -82,14 +84,14 @@ test "Opendal BDD test" {
     defer opendal.c.opendal_metadata_free(meta);
 
     // The blocking file "test" must have content "Hello, World!"
-    const r: opendal.c.opendal_result_read = 
opendal.c.opendal_operator_read(testkit.p, testkit.path);
-    defer opendal.c.opendal_bytes_free(r.data);
+    var r: opendal.c.opendal_result_read = 
opendal.c.opendal_operator_read(testkit.p, testkit.path);
+    defer opendal.c.opendal_bytes_free(&r.data);
     try testing.expect(r.@"error" == null);
-    try testing.expectEqual(std.mem.len(testkit.content), r.data.*.len);
+    try testing.expectEqual(std.mem.len(testkit.content), r.data.len);
 
     var count: usize = 0;
-    while (count < r.data.*.len) : (count += 1) {
-        try testing.expectEqual(testkit.content[count], r.data.*.data[count]);
+    while (count < r.data.len) : (count += 1) {
+        try testing.expectEqual(testkit.content[count], r.data.data[count]);
     }
 }
 

Reply via email to