swift-cgo: Implement scan/delete/batch/permission/get/put
Various refactors, formatting, and bug fixes plus:
Implements:
Collection.Scan
Collection.DeleteRange
Collection.get/put using user-supplied byte arrays*
Database.watch using user-supplied byte arrays*
Database.setPermission/getPermission
Service.setPermission/getPermission
Collection.getPermission/setPermission
Batch.runInBatch
Database.beginBatch / BatchDatabase.abort/commit
Unit tests:
Scan
Delete
Get/put
Batch operations
Missing unit tests:
None for permissions
* Removes the JSON support for arbitrary byte arrays as a stop
gap until VOM is implemented in Swift.
MultiPart: 1/2
Change-Id: I9f9c268f45d94eab7313e924dd4fcd6c16e12847
diff --git a/services/syncbase/bridge/cgo/impl.go b/services/syncbase/bridge/cgo/impl.go
index b58fd86..1c936cf 100644
--- a/services/syncbase/bridge/cgo/impl.go
+++ b/services/syncbase/bridge/cgo/impl.go
@@ -68,10 +68,17 @@
import "C"
// Global state, initialized by v23_syncbase_Init.
-var b *bridge.Bridge
+var (
+ b *bridge.Bridge
+ // clientUnderstandsVOM specifies whether the Cgo layer should assume
+ // the client does VOM encoding and decoding. If false, the Cgo layer
+ // itself does VOM encoding and decoding, and the client deals in byte
+ // arrays.
+ clientUnderstandsVOM bool
+)
//export v23_syncbase_Init
-func v23_syncbase_Init() {
+func v23_syncbase_Init(cClientUnderstandVom C.v23_syncbase_Bool) {
// Strip all flags beyond the binary name; otherwise, v23.Init will fail when it encounters
// unknown flags passed by Xcode, e.g. NSTreatUnknownArgumentsAsOpen.
os.Args = os.Args[:1]
@@ -79,6 +86,7 @@
ctx, _ := v23.Init()
srv, disp, _ := syncbaselib.Serve(ctx, syncbaselib.Opts{})
b = bridge.NewBridge(ctx, srv, disp)
+ clientUnderstandsVOM = cClientUnderstandVom.toBool()
}
////////////////////////////////////////
@@ -648,7 +656,14 @@
if !ok {
return verror.NewErrInternal(s.ctx)
}
- value, err := vom.Encode(kv.Value)
+ var value []byte
+ var err error
+ if clientUnderstandsVOM {
+ value, err = vom.Encode(kv.Value)
+ } else {
+ rawBytes := (*vom.RawBytes)(kv.Value)
+ err = rawBytes.ToValue(&value)
+ }
if err != nil {
return err
}
@@ -729,7 +744,16 @@
return
}
valueAsRawBytes, err := stub.Get(ctx, call, batchHandle)
- value, err := vom.Encode(valueAsRawBytes)
+ if err != nil {
+ cErr.init(err)
+ return
+ }
+ var value []byte
+ if clientUnderstandsVOM {
+ value, err = vom.Encode(valueAsRawBytes)
+ } else {
+ err = valueAsRawBytes.ToValue(&value)
+ }
if err != nil {
cErr.init(err)
return
@@ -748,12 +772,21 @@
cErr.init(err)
return
}
- var valueAsRawBytes vom.RawBytes
- if err := vom.Decode(value, &valueAsRawBytes); err != nil {
+ var valueAsRawBytes *vom.RawBytes
+ if clientUnderstandsVOM {
+ var bytes vom.RawBytes
+ err = vom.Decode(value, &bytes)
+ if err == nil {
+ valueAsRawBytes = &bytes
+ }
+ } else {
+ valueAsRawBytes, err = vom.RawBytesFromValue(value)
+ }
+ if err != nil {
cErr.init(err)
return
}
- cErr.init(stub.Put(ctx, call, batchHandle, &valueAsRawBytes))
+ cErr.init(stub.Put(ctx, call, batchHandle, valueAsRawBytes))
}
//export v23_syncbase_RowDelete
diff --git a/services/syncbase/bridge/cgo/types.go b/services/syncbase/bridge/cgo/types.go
index 3dbfc9c..4b45351 100644
--- a/services/syncbase/bridge/cgo/types.go
+++ b/services/syncbase/bridge/cgo/types.go
@@ -25,6 +25,21 @@
import "C"
////////////////////////////////////////////////////////////
+// C.v23_syncbase_BatchOptions
+
+func (x *C.v23_syncbase_BatchOptions) init(opts wire.BatchOptions) {
+ x.hint.init(opts.Hint)
+ x.readOnly = C.bool(opts.ReadOnly)
+}
+
+func (x *C.v23_syncbase_BatchOptions) toBatchOptions() wire.BatchOptions {
+ return wire.BatchOptions{
+ Hint: x.hint.toString(),
+ ReadOnly: bool(x.readOnly),
+ }
+}
+
+////////////////////////////////////////////////////////////
// C.v23_syncbase_Bool
func (x *C.v23_syncbase_Bool) init(b bool) {
@@ -43,22 +58,6 @@
}
////////////////////////////////////////////////////////////
-// C.v23_syncbase_String
-
-func (x *C.v23_syncbase_String) init(s string) {
- x.n = C.int(len(s))
- x.p = C.CString(s)
-}
-
-func (x *C.v23_syncbase_String) toString() string {
- if x.p == nil {
- return ""
- }
- defer C.free(unsafe.Pointer(x.p))
- return C.GoStringN(x.p, x.n)
-}
-
-////////////////////////////////////////////////////////////
// C.v23_syncbase_Bytes
func init() {
@@ -68,6 +67,12 @@
}
func (x *C.v23_syncbase_Bytes) init(b []byte) {
+ // Special-case for len(b) == 0, because memcpy fails on invalid pointers even if size is 0.
+ if len(b) == 0 {
+ x.n = 0
+ x.p = nil
+ return
+ }
x.n = C.int(len(b))
x.p = (*C.uint8_t)(C.malloc(C.size_t(x.n)))
C.memcpy(unsafe.Pointer(x.p), unsafe.Pointer(&b[0]), C.size_t(len(b)))
@@ -82,126 +87,6 @@
}
////////////////////////////////////////////////////////////
-// C.v23_syncbase_Strings
-
-func (x *C.v23_syncbase_Strings) at(i int) *C.v23_syncbase_String {
- return (*C.v23_syncbase_String)(unsafe.Pointer(uintptr(unsafe.Pointer(x.p)) + uintptr(C.size_t(i)*C.sizeof_v23_syncbase_String)))
-}
-
-func (x *C.v23_syncbase_Strings) init(strs []string) {
- x.n = C.int(len(strs))
- x.p = (*C.v23_syncbase_String)(C.malloc(C.size_t(x.n) * C.sizeof_v23_syncbase_String))
- for i, v := range strs {
- x.at(i).init(v)
- }
-}
-
-func (x *C.v23_syncbase_Strings) toStrings() []string {
- if x.p == nil {
- return nil
- }
- defer C.free(unsafe.Pointer(x.p))
- res := make([]string, x.n)
- for i := 0; i < int(x.n); i++ {
- res[i] = x.at(i).toString()
- }
- return res
-}
-
-////////////////////////////////////////////////////////////
-// C.v23_syncbase_VError
-
-func (x *C.v23_syncbase_VError) init(err error) {
- if err == nil {
- return
- }
- x.id.init(string(verror.ErrorID(err)))
- x.actionCode = C.uint(verror.Action(err))
- x.msg.init(err.Error())
- x.stack.init(verror.Stack(err).String())
-}
-
-////////////////////////////////////////////////////////////
-// C.v23_syncbase_Permissions
-
-func (x *C.v23_syncbase_Permissions) init(perms access.Permissions) {
- b := new(bytes.Buffer)
- if err := access.WritePermissions(b, perms); err != nil {
- panic(err)
- }
- x.json.init(b.Bytes())
-}
-
-func (x *C.v23_syncbase_Permissions) toPermissions() access.Permissions {
- b := x.json.toBytes()
- if len(b) == 0 {
- return nil
- }
- perms, err := access.ReadPermissions(bytes.NewReader(b))
- if err != nil {
- panic(err)
- }
- return perms
-}
-
-////////////////////////////////////////////////////////////
-// C.v23_syncbase_Id
-
-func (x *C.v23_syncbase_Id) init(id wire.Id) {
- x.blessing.init(id.Blessing)
- x.name.init(id.Name)
-}
-
-func (x *C.v23_syncbase_Id) toId() wire.Id {
- return wire.Id{
- Blessing: x.blessing.toString(),
- Name: x.name.toString(),
- }
-}
-
-////////////////////////////////////////////////////////////
-// C.v23_syncbase_Ids
-
-func (x *C.v23_syncbase_Ids) at(i int) *C.v23_syncbase_Id {
- return (*C.v23_syncbase_Id)(unsafe.Pointer(uintptr(unsafe.Pointer(x.p)) + uintptr(C.size_t(i)*C.sizeof_v23_syncbase_Id)))
-}
-
-func (x *C.v23_syncbase_Ids) init(ids []wire.Id) {
- x.n = C.int(len(ids))
- x.p = (*C.v23_syncbase_Id)(C.malloc(C.size_t(x.n) * C.sizeof_v23_syncbase_Id))
- for i, v := range ids {
- x.at(i).init(v)
- }
-}
-
-func (x *C.v23_syncbase_Ids) toIds() []wire.Id {
- if x.p == nil {
- return nil
- }
- defer C.free(unsafe.Pointer(x.p))
- res := make([]wire.Id, x.n)
- for i := 0; i < int(x.n); i++ {
- res[i] = x.at(i).toId()
- }
- return res
-}
-
-////////////////////////////////////////////////////////////
-// C.v23_syncbase_BatchOptions
-
-func (x *C.v23_syncbase_BatchOptions) init(opts wire.BatchOptions) {
- x.hint.init(opts.Hint)
- x.readOnly = C.bool(opts.ReadOnly)
-}
-
-func (x *C.v23_syncbase_BatchOptions) toBatchOptions() wire.BatchOptions {
- return wire.BatchOptions{
- Hint: x.hint.toString(),
- ReadOnly: bool(x.readOnly),
- }
-}
-
-////////////////////////////////////////////////////////////
// C.v23_syncbase_CollectionRowPattern
func (x *C.v23_syncbase_CollectionRowPattern) init(crp wire.CollectionRowPattern) {
@@ -246,21 +131,45 @@
}
////////////////////////////////////////////////////////////
-// C.v23_syncbase_WatchChange
+// C.v23_syncbase_Id
-func (x *C.v23_syncbase_WatchChange) init(wc syncbase.WatchChange) error {
- x.collection.init(wc.Collection)
- x.row.init(wc.Row)
- x.changeType = C.v23_syncbase_ChangeType(wc.ChangeType)
- value, err := vom.Encode(wc.Value)
- if err != nil {
- return err
+func (x *C.v23_syncbase_Id) init(id wire.Id) {
+ x.blessing.init(id.Blessing)
+ x.name.init(id.Name)
+}
+
+func (x *C.v23_syncbase_Id) toId() wire.Id {
+ return wire.Id{
+ Blessing: x.blessing.toString(),
+ Name: x.name.toString(),
}
- x.value.init(value)
- x.resumeMarker.init(string(wc.ResumeMarker))
- x.fromSync = C.bool(wc.FromSync)
- x.continued = C.bool(wc.Continued)
- return nil
+}
+
+////////////////////////////////////////////////////////////
+// C.v23_syncbase_Ids
+
+func (x *C.v23_syncbase_Ids) at(i int) *C.v23_syncbase_Id {
+ return (*C.v23_syncbase_Id)(unsafe.Pointer(uintptr(unsafe.Pointer(x.p)) + uintptr(C.size_t(i)*C.sizeof_v23_syncbase_Id)))
+}
+
+func (x *C.v23_syncbase_Ids) init(ids []wire.Id) {
+ x.n = C.int(len(ids))
+ x.p = (*C.v23_syncbase_Id)(C.malloc(C.size_t(x.n) * C.sizeof_v23_syncbase_Id))
+ for i, v := range ids {
+ x.at(i).init(v)
+ }
+}
+
+func (x *C.v23_syncbase_Ids) toIds() []wire.Id {
+ if x.p == nil {
+ return nil
+ }
+ defer C.free(unsafe.Pointer(x.p))
+ res := make([]wire.Id, x.n)
+ for i := 0; i < int(x.n); i++ {
+ res[i] = x.at(i).toId()
+ }
+ return res
}
////////////////////////////////////////////////////////////
@@ -272,6 +181,72 @@
}
////////////////////////////////////////////////////////////
+// C.v23_syncbase_Permissions
+
+func (x *C.v23_syncbase_Permissions) init(perms access.Permissions) {
+ b := new(bytes.Buffer)
+ if err := access.WritePermissions(b, perms); err != nil {
+ panic(err)
+ }
+ x.json.init(b.Bytes())
+}
+
+func (x *C.v23_syncbase_Permissions) toPermissions() access.Permissions {
+ b := x.json.toBytes()
+ if len(b) == 0 {
+ return nil
+ }
+ perms, err := access.ReadPermissions(bytes.NewReader(b))
+ if err != nil {
+ panic(err)
+ }
+ return perms
+}
+
+////////////////////////////////////////////////////////////
+// C.v23_syncbase_String
+
+func (x *C.v23_syncbase_String) init(s string) {
+ x.n = C.int(len(s))
+ x.p = C.CString(s)
+}
+
+func (x *C.v23_syncbase_String) toString() string {
+ if x.p == nil {
+ return ""
+ }
+ defer C.free(unsafe.Pointer(x.p))
+ return C.GoStringN(x.p, x.n)
+}
+
+////////////////////////////////////////////////////////////
+// C.v23_syncbase_Strings
+
+func (x *C.v23_syncbase_Strings) at(i int) *C.v23_syncbase_String {
+ return (*C.v23_syncbase_String)(unsafe.Pointer(uintptr(unsafe.Pointer(x.p)) + uintptr(C.size_t(i)*C.sizeof_v23_syncbase_String)))
+}
+
+func (x *C.v23_syncbase_Strings) init(strs []string) {
+ x.n = C.int(len(strs))
+ x.p = (*C.v23_syncbase_String)(C.malloc(C.size_t(x.n) * C.sizeof_v23_syncbase_String))
+ for i, v := range strs {
+ x.at(i).init(v)
+ }
+}
+
+func (x *C.v23_syncbase_Strings) toStrings() []string {
+ if x.p == nil {
+ return nil
+ }
+ defer C.free(unsafe.Pointer(x.p))
+ res := make([]string, x.n)
+ for i := 0; i < int(x.n); i++ {
+ res[i] = x.at(i).toString()
+ }
+ return res
+}
+
+////////////////////////////////////////////////////////////
// C.v23_syncbase_SyncgroupSpec
func (x *C.v23_syncbase_SyncgroupSpec) init(spec wire.SyncgroupSpec) {
@@ -330,3 +305,46 @@
i++
}
}
+
+////////////////////////////////////////////////////////////
+// C.v23_syncbase_VError
+
+func (x *C.v23_syncbase_VError) init(err error) {
+ if err == nil {
+ return
+ }
+ x.id.init(string(verror.ErrorID(err)))
+ x.actionCode = C.uint(verror.Action(err))
+ x.msg.init(err.Error())
+ x.stack.init(verror.Stack(err).String())
+}
+
+////////////////////////////////////////////////////////////
+// C.v23_syncbase_WatchChange
+
+func (x *C.v23_syncbase_WatchChange) init(wc syncbase.WatchChange) error {
+ x.collection.init(wc.Collection)
+ x.row.init(wc.Row)
+ x.changeType = C.v23_syncbase_ChangeType(wc.ChangeType)
+ var value []byte
+ if wc.ChangeType != syncbase.DeleteChange {
+ var valueAsRawBytes vom.RawBytes
+ var err error
+ if err = wc.Value(&valueAsRawBytes); err != nil {
+ return err
+ }
+ if clientUnderstandsVOM {
+ value, err = vom.Encode(valueAsRawBytes)
+ } else {
+ err = valueAsRawBytes.ToValue(&value)
+ }
+ if err != nil {
+ return err
+ }
+ }
+ x.value.init(value)
+ x.resumeMarker.init(string(wc.ResumeMarker))
+ x.fromSync = C.bool(wc.FromSync)
+ x.continued = C.bool(wc.Continued)
+ return nil
+}