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

yuchanns pushed a commit to branch feat-c-binding-writer
in repository https://gitbox.apache.org/repos/asf/opendal.git

commit ab9bbae313559b7664cf486d26b3626d0654b6c9
Author: Hanchin Hsieh <[email protected]>
AuthorDate: Tue Sep 24 19:10:56 2024 +0800

    feat(bindings/go): add writer operation
    
    Signed-off-by: Hanchin Hsieh <[email protected]>
---
 bindings/go/types.go |  21 +++++++
 bindings/go/write.go | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 183 insertions(+)

diff --git a/bindings/go/types.go b/bindings/go/types.go
index 49c0daf5d3..4ee2de1884 100644
--- a/bindings/go/types.go
+++ b/bindings/go/types.go
@@ -89,6 +89,15 @@ var (
                }[0],
        }
 
+       typeResultWriterWrite = ffi.Type{
+               Type: ffi.Struct,
+               Elements: &[]*ffi.Type{
+                       &ffi.TypePointer,
+                       &ffi.TypePointer,
+                       nil,
+               }[0],
+       }
+
        typeResultReaderRead = ffi.Type{
                Type: ffi.Struct,
                Elements: &[]*ffi.Type{
@@ -209,6 +218,18 @@ type resultOperatorReader struct {
        error  *opendalError
 }
 
+type opendalWriter struct{}
+
+type resultOperatorWriter struct {
+       writer *opendalWriter
+       error  *opendalError
+}
+
+type resultWriterWrite struct {
+       size  uint
+       error *opendalError
+}
+
 type resultReaderRead struct {
        size  uint
        error *opendalError
diff --git a/bindings/go/write.go b/bindings/go/write.go
index e1d18a1322..4b191dd8f3 100644
--- a/bindings/go/write.go
+++ b/bindings/go/write.go
@@ -21,6 +21,7 @@ package opendal
 
 import (
        "context"
+       "io"
        "unsafe"
 
        "github.com/jupiterrider/ffi"
@@ -98,6 +99,94 @@ func (op *Operator) CreateDir(path string) error {
        return createDir(op.inner, path)
 }
 
+// Writer returns a new Writer for the specified path.
+//
+// Writer is a wrapper around the C-binding function `opendal_operator_writer`.
+// It provides a way to obtain a writer for writing data to the storage system.
+//
+// # Parameters
+//
+//   - path: The destination path where data will be written.
+//
+// # Returns
+//
+//   - *Writer: A pointer to a Writer instance, or an error if the operation 
fails.
+//
+// # Example
+//
+//     func exampleWriter(op *opendal.Operator) {
+//             writer, err := op.Writer("test/")
+//             if err != nil {
+//                     log.Fatal(err)
+//             }
+//             defer writer.Close()
+//             _, err = writer.Write([]byte("Hello opendal writer!"))
+//             if err != nil {
+//                     log.Fatal(err)
+//             }
+//     }
+//
+// Note: This example assumes proper error handling and import statements.
+func (op *Operator) Writer(path string) (*Writer, error) {
+       getWriter := getFFI[operatorWriter](op.ctx,
+               symOperatorWriter)
+       inner, err := getWriter(op.inner, path)
+       if err != nil {
+               return nil, err
+       }
+       writer := &Writer{
+               inner: inner,
+               ctx:   op.ctx,
+       }
+       return writer, nil
+}
+
+type Writer struct {
+       inner *opendalWriter
+       ctx   context.Context
+}
+
+// Write writes the given bytes to the specified path.
+//
+// Write is a wrapper around the C-binding function `opendal_operator_write`. 
It provides a simplified
+// interface for writing data to the storage. Write can be called multiple 
times to write
+// additional data to the same path.
+//
+// # Parameters
+//
+//   - path: The destination path where the bytes will be written.
+//   - data: The byte slice containing the data to be written.
+//
+// # Returns
+//
+//   - error: An error if the write operation fails, or nil if successful.
+//
+// # Example
+//
+//     func exampleWrite(op *opendal.Operator) {
+//             err = op.Write("test", []byte("Hello opendal go binding!"))
+//             if err != nil {
+//                     log.Fatal(err)
+//             }
+//     }
+//
+// Note: This example assumes proper error handling and import statements.
+func (w *Writer) Write(p []byte) (n int, err error) {
+       write := getFFI[writerWrite](w.ctx, symWriterWrite)
+       return write(w.inner, p)
+}
+
+// Close finishes the write and releases the resources associated with the 
Writer.
+// It is important to call Close after writing all the data to ensure that the 
data is
+// properly flushed and written to the storage.
+func (w *Writer) Close() error {
+       free := getFFI[writerFree](w.ctx, symWriterFree)
+       free(w.inner)
+       return nil
+}
+
+var _ io.WriteCloser = (*Writer)(nil)
+
 const symOperatorWrite = "opendal_operator_write"
 
 type operatorWrite func(op *opendalOperator, path string, data []byte) error
@@ -150,3 +239,76 @@ var withOperatorCreateDir = withFFI(ffiOpts{
                return parseError(ctx, e)
        }
 })
+
+const symOperatorWriter = "opendal_operator_writer"
+
+type operatorWriter func(op *opendalOperator, path string) (*opendalWriter, 
error)
+
+var withOperatorWriter = withFFI(ffiOpts{
+       sym:    symOperatorWriter,
+       rType:  &ffi.TypePointer,
+       aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
+}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues 
...unsafe.Pointer)) operatorWriter {
+       return func(op *opendalOperator, path string) (*opendalWriter, error) {
+               bytePath, err := unix.BytePtrFromString(path)
+               if err != nil {
+                       return nil, err
+               }
+               var result resultOperatorWriter
+               ffiCall(
+                       unsafe.Pointer(&result),
+                       unsafe.Pointer(&op),
+                       unsafe.Pointer(&bytePath),
+               )
+               if result.error != nil {
+                       return nil, parseError(ctx, result.error)
+               }
+               return result.writer, nil
+       }
+})
+
+const symWriterFree = "opendal_writer_free"
+
+type writerFree func(w *opendalWriter)
+
+var withWriterFree = withFFI(ffiOpts{
+       sym:    symWriterFree,
+       rType:  &ffi.TypeVoid,
+       aTypes: []*ffi.Type{&ffi.TypePointer},
+}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues 
...unsafe.Pointer)) writerFree {
+       return func(r *opendalWriter) {
+               ffiCall(
+                       nil,
+                       unsafe.Pointer(&r),
+               )
+       }
+})
+
+const symWriterWrite = "opendal_writer_write"
+
+type writerWrite func(r *opendalWriter, buf []byte) (size int, err error)
+
+var withWriterWrite = withFFI(ffiOpts{
+       sym:    symWriterWrite,
+       rType:  &typeResultWriterWrite,
+       aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer, 
&ffi.TypePointer},
+}, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues 
...unsafe.Pointer)) writerWrite {
+       return func(r *opendalWriter, buf []byte) (size int, err error) {
+               var length = len(buf)
+               if length == 0 {
+                       return 0, nil
+               }
+               bytePtr := &buf[0]
+               var result resultWriterWrite
+               ffiCall(
+                       unsafe.Pointer(&result),
+                       unsafe.Pointer(&r),
+                       unsafe.Pointer(&bytePtr),
+                       unsafe.Pointer(&length),
+               )
+               if result.error != nil {
+                       return 0, parseError(ctx, result.error)
+               }
+               return int(result.size), nil
+       }
+})

Reply via email to