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
+}