You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by yu...@apache.org on 2024/09/24 11:11:28 UTC

(opendal) 02/02: feat(bindings/go): add writer operation

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 <me...@yuchanns.xyz>
AuthorDate: Tue Sep 24 19:10:56 2024 +0800

    feat(bindings/go): add writer operation
    
    Signed-off-by: Hanchin Hsieh <me...@yuchanns.xyz>
---
 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
+	}
+})