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

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

commit a2e1bc3c83c2fd712bfc6ea335a1eaa27fc64b85
Author: Hanchin Hsieh <[email protected]>
AuthorDate: Wed Apr 9 13:30:56 2025 +0800

    feat(bindings/go): support windows platform
    
    Hanchin Hsieh <[email protected]>
---
 bindings/go/delete.go        |  3 +-
 bindings/go/ffi.go           |  7 ++---
 bindings/go/go.mod           |  4 +--
 bindings/go/go.sum           |  4 +++
 bindings/go/lister.go        |  7 ++---
 bindings/go/operator.go      | 15 +++++-----
 bindings/go/operator_info.go |  7 ++---
 bindings/go/reader.go        |  5 ++--
 bindings/go/stat.go          |  5 ++--
 bindings/go/util_unix.go     | 67 ++++++++++++++++++++++++++++++++++++++++++
 bindings/go/util_windows.go  | 70 ++++++++++++++++++++++++++++++++++++++++++++
 bindings/go/write.go         |  7 ++---
 12 files changed, 167 insertions(+), 34 deletions(-)

diff --git a/bindings/go/delete.go b/bindings/go/delete.go
index f92df487a..1a8b64317 100644
--- a/bindings/go/delete.go
+++ b/bindings/go/delete.go
@@ -24,7 +24,6 @@ import (
        "unsafe"
 
        "github.com/jupiterrider/ffi"
-       "golang.org/x/sys/unix"
 )
 
 // Delete removes the file or directory at the specified path.
@@ -55,7 +54,7 @@ var withOperatorDelete = withFFI(ffiOpts{
        aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
 }, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues 
...unsafe.Pointer)) operatorDelete {
        return func(op *opendalOperator, path string) error {
-               bytePath, err := unix.BytePtrFromString(path)
+               bytePath, err := BytePtrFromString(path)
                if err != nil {
                        return err
                }
diff --git a/bindings/go/ffi.go b/bindings/go/ffi.go
index 931c345f2..3a39f0b20 100644
--- a/bindings/go/ffi.go
+++ b/bindings/go/ffi.go
@@ -24,12 +24,11 @@ import (
        "errors"
        "unsafe"
 
-       "github.com/ebitengine/purego"
        "github.com/jupiterrider/ffi"
 )
 
 func contextWithFFIs(path string) (ctx context.Context, cancel 
context.CancelFunc, err error) {
-       libopendal, err := purego.Dlopen(path, 
purego.RTLD_LAZY|purego.RTLD_GLOBAL)
+       libopendal, err := LoadLibrary(path)
        if err != nil {
                return
        }
@@ -41,7 +40,7 @@ func contextWithFFIs(path string) (ctx context.Context, 
cancel context.CancelFun
                }
        }
        cancel = func() {
-               purego.Dlclose(libopendal)
+               FreeLibrary(libopendal)
        }
        return
 }
@@ -83,7 +82,7 @@ func withFFI[T any](
                ); status != ffi.OK {
                        return nil, errors.New(status.String())
                }
-               fn, err := purego.Dlsym(libopendal, opts.sym.String())
+               fn, err := GetProcAddress(libopendal, opts.sym.String())
                if err != nil {
                        return nil, err
                }
diff --git a/bindings/go/go.mod b/bindings/go/go.mod
index ac1f39f5c..17bc50945 100644
--- a/bindings/go/go.mod
+++ b/bindings/go/go.mod
@@ -22,7 +22,7 @@ go 1.22.4
 toolchain go1.22.5
 
 require (
-       github.com/ebitengine/purego v0.7.1
-       github.com/jupiterrider/ffi v0.1.0
+       github.com/ebitengine/purego v0.8.2
+       github.com/jupiterrider/ffi v0.4.0
        golang.org/x/sys v0.24.0
 )
diff --git a/bindings/go/go.sum b/bindings/go/go.sum
index b08aa464c..ac2837037 100644
--- a/bindings/go/go.sum
+++ b/bindings/go/go.sum
@@ -1,6 +1,10 @@
 github.com/ebitengine/purego v0.7.1 
h1:6/55d26lG3o9VCZX8lping+bZcmShseiqlh2bnUDiPA=
 github.com/ebitengine/purego v0.7.1/go.mod 
h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ=
+github.com/ebitengine/purego v0.8.2 
h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
+github.com/ebitengine/purego v0.8.2/go.mod 
h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
 github.com/jupiterrider/ffi v0.1.0 
h1:OI6ZHZJW1Io1PcfqGeLk/CBLj+//8aNdOuo558ykQQo=
 github.com/jupiterrider/ffi v0.1.0/go.mod 
h1:tyr9EitV+PW99I6137IDwdO6ZzNyFp/noXNSfU3OYqk=
+github.com/jupiterrider/ffi v0.4.0 
h1:7mhlrfiBZa0kHhh2DV7mGAdXN/D8zDeu8UlaBO+ZSko=
+github.com/jupiterrider/ffi v0.4.0/go.mod 
h1:1QCaf2VVPpGyIeU3RqQ2rHYrAPT8m9l0GhQupVYQB24=
 golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
 golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
diff --git a/bindings/go/lister.go b/bindings/go/lister.go
index bbd58f1f1..a328f3d05 100644
--- a/bindings/go/lister.go
+++ b/bindings/go/lister.go
@@ -24,7 +24,6 @@ import (
        "unsafe"
 
        "github.com/jupiterrider/ffi"
-       "golang.org/x/sys/unix"
 )
 
 // Check verifies if the operator is functioning correctly.
@@ -312,7 +311,7 @@ var withOperatorList = withFFI(ffiOpts{
        aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
 }, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues 
...unsafe.Pointer)) operatorList {
        return func(op *opendalOperator, path string) (*opendalLister, error) {
-               bytePath, err := unix.BytePtrFromString(path)
+               bytePath, err := BytePtrFromString(path)
                if err != nil {
                        return nil, err
                }
@@ -400,7 +399,7 @@ var withEntryName = withFFI(ffiOpts{
                        unsafe.Pointer(&bytePtr),
                        unsafe.Pointer(&e),
                )
-               return unix.BytePtrToString(bytePtr)
+               return BytePtrToString(bytePtr)
        }
 })
 
@@ -419,6 +418,6 @@ var withEntryPath = withFFI(ffiOpts{
                        unsafe.Pointer(&bytePtr),
                        unsafe.Pointer(&e),
                )
-               return unix.BytePtrToString(bytePtr)
+               return BytePtrToString(bytePtr)
        }
 })
diff --git a/bindings/go/operator.go b/bindings/go/operator.go
index d63bacda6..304b05d06 100644
--- a/bindings/go/operator.go
+++ b/bindings/go/operator.go
@@ -24,7 +24,6 @@ import (
        "unsafe"
 
        "github.com/jupiterrider/ffi"
-       "golang.org/x/sys/unix"
 )
 
 // Copy duplicates a file from the source path to the destination path.
@@ -111,7 +110,7 @@ var withOperatorNew = withFFI(ffiOpts{
 }, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues 
...unsafe.Pointer)) operatorNew {
        return func(scheme Scheme, opts *operatorOptions) (op *opendalOperator, 
err error) {
                var byteName *byte
-               byteName, err = unix.BytePtrFromString(scheme.Name())
+               byteName, err = BytePtrFromString(scheme.Name())
                if err != nil {
                        return
                }
@@ -177,11 +176,11 @@ var withOperatorOptionsSet = withFFI(ffiOpts{
                        byteKey   *byte
                        byteValue *byte
                )
-               byteKey, err = unix.BytePtrFromString(key)
+               byteKey, err = BytePtrFromString(key)
                if err != nil {
                        return err
                }
-               byteValue, err = unix.BytePtrFromString(value)
+               byteValue, err = BytePtrFromString(value)
                if err != nil {
                        return err
                }
@@ -226,11 +225,11 @@ var withOperatorCopy = withFFI(ffiOpts{
                        byteSrc  *byte
                        byteDest *byte
                )
-               byteSrc, err = unix.BytePtrFromString(src)
+               byteSrc, err = BytePtrFromString(src)
                if err != nil {
                        return err
                }
-               byteDest, err = unix.BytePtrFromString(dest)
+               byteDest, err = BytePtrFromString(dest)
                if err != nil {
                        return err
                }
@@ -259,11 +258,11 @@ var withOperatorRename = withFFI(ffiOpts{
                        byteSrc  *byte
                        byteDest *byte
                )
-               byteSrc, err = unix.BytePtrFromString(src)
+               byteSrc, err = BytePtrFromString(src)
                if err != nil {
                        return err
                }
-               byteDest, err = unix.BytePtrFromString(dest)
+               byteDest, err = BytePtrFromString(dest)
                if err != nil {
                        return err
                }
diff --git a/bindings/go/operator_info.go b/bindings/go/operator_info.go
index 6ea7f15fc..9fffe909c 100644
--- a/bindings/go/operator_info.go
+++ b/bindings/go/operator_info.go
@@ -24,7 +24,6 @@ import (
        "unsafe"
 
        "github.com/jupiterrider/ffi"
-       "golang.org/x/sys/unix"
 )
 
 // Info returns metadata about the Operator.
@@ -325,7 +324,7 @@ var withOperatorInfoGetScheme = withFFI(ffiOpts{
                        unsafe.Pointer(&bytePtr),
                        unsafe.Pointer(&info),
                )
-               return unix.BytePtrToString(bytePtr)
+               return BytePtrToString(bytePtr)
        }
 })
 
@@ -344,7 +343,7 @@ var withOperatorInfoGetRoot = withFFI(ffiOpts{
                        unsafe.Pointer(&bytePtr),
                        unsafe.Pointer(&info),
                )
-               return unix.BytePtrToString(bytePtr)
+               return BytePtrToString(bytePtr)
        }
 })
 
@@ -363,6 +362,6 @@ var withOperatorInfoGetName = withFFI(ffiOpts{
                        unsafe.Pointer(&bytePtr),
                        unsafe.Pointer(&info),
                )
-               return unix.BytePtrToString(bytePtr)
+               return BytePtrToString(bytePtr)
        }
 })
diff --git a/bindings/go/reader.go b/bindings/go/reader.go
index ce26ce663..52810ddeb 100644
--- a/bindings/go/reader.go
+++ b/bindings/go/reader.go
@@ -25,7 +25,6 @@ import (
        "unsafe"
 
        "github.com/jupiterrider/ffi"
-       "golang.org/x/sys/unix"
 )
 
 // Read reads the entire contents of the file at the specified path into a 
byte slice.
@@ -210,7 +209,7 @@ var withOperatorRead = withFFI(ffiOpts{
        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) {
-               bytePath, err := unix.BytePtrFromString(path)
+               bytePath, err := BytePtrFromString(path)
                if err != nil {
                        return opendalBytes{}, err
                }
@@ -234,7 +233,7 @@ var withOperatorReader = withFFI(ffiOpts{
        aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
 }, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues 
...unsafe.Pointer)) operatorReader {
        return func(op *opendalOperator, path string) (*opendalReader, error) {
-               bytePath, err := unix.BytePtrFromString(path)
+               bytePath, err := BytePtrFromString(path)
                if err != nil {
                        return nil, err
                }
diff --git a/bindings/go/stat.go b/bindings/go/stat.go
index 7eb734593..feb37d860 100644
--- a/bindings/go/stat.go
+++ b/bindings/go/stat.go
@@ -24,7 +24,6 @@ import (
        "unsafe"
 
        "github.com/jupiterrider/ffi"
-       "golang.org/x/sys/unix"
 )
 
 // Stat retrieves metadata for the specified path.
@@ -111,7 +110,7 @@ var withOperatorStat = withFFI(ffiOpts{
        aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
 }, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues 
...unsafe.Pointer)) operatorStat {
        return func(op *opendalOperator, path string) (*opendalMetadata, error) 
{
-               bytePath, err := unix.BytePtrFromString(path)
+               bytePath, err := BytePtrFromString(path)
                if err != nil {
                        return nil, err
                }
@@ -138,7 +137,7 @@ var withOperatorIsExists = withFFI(ffiOpts{
        aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
 }, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues 
...unsafe.Pointer)) operatorIsExist {
        return func(op *opendalOperator, path string) (bool, error) {
-               bytePath, err := unix.BytePtrFromString(path)
+               bytePath, err := BytePtrFromString(path)
                if err != nil {
                        return false, err
                }
diff --git a/bindings/go/util_unix.go b/bindings/go/util_unix.go
new file mode 100644
index 000000000..fb6e45f25
--- /dev/null
+++ b/bindings/go/util_unix.go
@@ -0,0 +1,67 @@
+//go:build !windows
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package opendal
+
+import (
+       "github.com/ebitengine/purego"
+       "golang.org/x/sys/unix"
+)
+
+func BytePtrFromString(s string) (*byte, error) {
+       if s == "" {
+               return nil, nil
+       }
+       return unix.BytePtrFromString(s)
+}
+
+func BytePtrToString(p *byte) string {
+       if p == nil {
+               return ""
+       }
+       return unix.BytePtrToString(p)
+}
+
+func LoadLibrary(path string) (uintptr, error) {
+       return purego.Dlopen(path, purego.RTLD_LAZY|purego.RTLD_GLOBAL)
+}
+
+func FreeLibrary(handle uintptr) error {
+       if handle == 0 {
+               return nil
+       }
+       err := purego.Dlclose(handle)
+       if err != nil {
+               return err
+       }
+       return nil
+}
+
+func GetProcAddress(handle uintptr, name string) (uintptr, error) {
+       if handle == 0 {
+               return 0, nil
+       }
+       addr, err := purego.Dlsym(handle, name)
+       if err != nil {
+               return 0, err
+       }
+       return addr, nil
+}
diff --git a/bindings/go/util_windows.go b/bindings/go/util_windows.go
new file mode 100644
index 000000000..1ead26988
--- /dev/null
+++ b/bindings/go/util_windows.go
@@ -0,0 +1,70 @@
+//go:build windows
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package opendal
+
+import (
+       "golang.org/x/sys/windows"
+)
+
+func BytePtrFromString(s string) (*byte, error) {
+       if s == "" {
+               return nil, nil
+       }
+       return windows.BytePtrFromString(s)
+}
+
+func BytePtrToString(p *byte) string {
+       if p == nil {
+               return ""
+       }
+       return windows.BytePtrToString(p)
+}
+
+func LoadLibrary(path string) (uintptr, error) {
+       handle, err := windows.LoadLibrary(path)
+       if err != nil {
+               return 0, err
+       }
+       return uintptr(handle), nil
+}
+
+func FreeLibrary(handle uintptr) error {
+       if handle == 0 {
+               return nil
+       }
+       err := windows.FreeLibrary(windows.Handle(handle))
+       if err != nil {
+               return err
+       }
+       return nil
+}
+
+func GetProcAddress(handle uintptr, name string) (uintptr, error) {
+       if handle == 0 {
+               return 0, nil
+       }
+       proc, err := windows.GetProcAddress(windows.Handle(handle), name)
+       if err != nil {
+               return 0, err
+       }
+       return proc, nil
+}
diff --git a/bindings/go/write.go b/bindings/go/write.go
index f0c23b816..a426c9eae 100644
--- a/bindings/go/write.go
+++ b/bindings/go/write.go
@@ -25,7 +25,6 @@ import (
        "unsafe"
 
        "github.com/jupiterrider/ffi"
-       "golang.org/x/sys/unix"
 )
 
 // Write writes the given bytes to the specified path.
@@ -199,7 +198,7 @@ var withOperatorWrite = withFFI(ffiOpts{
        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)
+               bytePath, err := BytePtrFromString(path)
                if err != nil {
                        return err
                }
@@ -225,7 +224,7 @@ var withOperatorCreateDir = withFFI(ffiOpts{
        aTypes: []*ffi.Type{&ffi.TypePointer, &ffi.TypePointer},
 }, func(ctx context.Context, ffiCall func(rValue unsafe.Pointer, aValues 
...unsafe.Pointer)) operatorCreateDir {
        return func(op *opendalOperator, path string) error {
-               bytePath, err := unix.BytePtrFromString(path)
+               bytePath, err := BytePtrFromString(path)
                if err != nil {
                        return err
                }
@@ -249,7 +248,7 @@ var withOperatorWriter = withFFI(ffiOpts{
        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)
+               bytePath, err := BytePtrFromString(path)
                if err != nil {
                        return nil, err
                }

Reply via email to