Skip to content

Commit

Permalink
Expose Reader and Writer from JSPB.
Browse files Browse the repository at this point in the history
Interfaces are still WIP
  • Loading branch information
Johan Brandhorst committed Aug 12, 2017
1 parent 2a2371e commit 41cb18e
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 0 deletions.
6 changes: 6 additions & 0 deletions jspb/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package jspb

const (
// InvalidFieldNumber is a Flag to indicate a missing field.
InvalidFieldNumber = -1
)
19 changes: 19 additions & 0 deletions jspb/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package jspb

import "github.com/gopherjs/gopherjs/js"

// catchException recovers any JS exceptions and
// stores the error in the parameter
func catchException(err *error) {
e := recover()

if e == nil {
return
}

if e, ok := e.(*js.Error); ok {
*err = e
} else {
panic(e)
}
}
120 changes: 120 additions & 0 deletions jspb/reader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package jspb

import "github.com/gopherjs/gopherjs/js"

// Reader encapsulates the jspb.BinaryReader
type Reader interface {
Next() bool
Err() error

GetFieldNumber() int
SkipField()

// Scalars
ReadInt32() int32
ReadUint32() uint32
ReadString() string
ReadBool() bool

// Slices
ReadUint32Slice() []uint32

// Specials
ReadMessage(func())
ReadEnum() int
}

// NewReader returns a new Reader ready for writing
func NewReader(data []byte) Reader {
return &reader{
Object: js.Global.Get("BinaryReader").New(data),
}
}

// reader implements the Reader interface
type reader struct {
*js.Object
err error
}

// Reads the next field header in the stream if there is one, returns true if
// we saw a valid field header or false if we've read the whole stream.
// Sets err if we encountered a deprecated START_GROUP/END_GROUP field.
func (r *reader) Next() bool {
defer catchException(&r.err)
return r.err == nil && r.Call("nextField").Bool() && !r.Call("isEndGroup").Bool()
}

// Err returns the error state of the Reader.
func (r reader) Err() error {
return r.err
}

// The field number of the next field in the buffer, or
// InvalidFieldNumber if there is no next field.
func (r reader) GetFieldNumber() int {
return r.Call("getFieldNumber").Int()
}

// Skips over the next field in the binary stream.
func (r reader) SkipField() {
r.Call("skipField")
}

// ReadInt32 reads a signed 32-bit integer field from the binary
// stream, sets err if the next field in the
// stream is not of the correct wire type.
func (r *reader) ReadInt32() int32 {
defer catchException(&r.err)
return int32(r.Call("readInt32").Int())
}

// ReadUit32 reads an unsigned 32-bit integer field from the binary
// stream, sets err if the next field in the
// stream is not of the correct wire type.
func (r *reader) ReadUint32() uint32 {
defer catchException(&r.err)
return uint32(r.Call("readUint32").Int())
}

// ReadString reads a string field from the binary stream, sets err
// if the next field in the stream is not of the correct wire type.
func (r *reader) ReadString() string {
defer catchException(&r.err)
return r.Call("readString").String()
}

// ReadBool reads a bool field from the binary stream, sets err
// if the next field in the stream is not of the correct wire type.
func (r *reader) ReadBool() bool {
defer catchException(&r.err)
return r.Call("readBool").Bool()
}

// ReadUint32Slice reads a packed 32-bit unsigned integer field
// from the binary stream, sets err if the next field
// in the stream is not of the correct wire type.
func (r *reader) ReadUint32Slice() (ret []uint32) {
defer catchException(&r.err)
values := r.Call("readPackedUint32").Interface().([]interface{})
for _, value := range values {
ret = append(ret, uint32(value.(float64)))
}

return ret
}

// ReadMessage deserializes a proto using
// the provided reader function.
func (r *reader) ReadMessage(readFunc func()) {
defer catchException(&r.err)
r.Call("readMessage", js.Undefined /* Unused */, readFunc)
}

// ReadEnum reads an enum field from the binary stream,
// sets err if the next field in the stream
// is not of the correct wire type.
func (r *reader) ReadEnum() int {
defer catchException(&r.err)
return r.Call("readEnum").Int()
}
73 changes: 73 additions & 0 deletions jspb/writer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package jspb

import "github.com/gopherjs/gopherjs/js"

// Writer encapsulates the jspb.BinaryWriter.
type Writer interface {
GetResult() []byte

// Scalars
WriteInt32(int, int32)
WriteUint32(int, uint32)
WriteString(int, string)
WriteBool(int, bool)

// Slices
WriteUint32Slice(int, []uint32)

// Specials
WriteMessage(int, func())
WriteEnum(int, int)
}

// NewWriter returns a new Writer ready for writing.
func NewWriter() Writer {
return &writer{
Object: js.Global.Get("BinaryWriter").New(),
}
}

// writer implements the Writer interface.
type writer struct {
*js.Object
}

// GetResult returns the contents of the buffer as a byte slice.
func (w writer) GetResult() []byte {
return w.Call("getResultBuffer").Interface().([]byte)
}

// WriteInt32 writes an int32 field to the buffer.
func (w writer) WriteInt32(field int, value int32) {
w.Call("writeInt32", field, value)
}

// WriteInt32 writes a uint32 field to the buffer.
func (w writer) WriteUint32(field int, value uint32) {
w.Call("writeUint32", field, value)
}

// WriteString writes a string field to the buffer
func (w writer) WriteString(field int, value string) {
w.Call("writeString", field, value)
}

// WriteBool writes a string field to the buffer
func (w writer) WriteBool(field int, value bool) {
w.Call("writeBool", field, value)
}

// WriteUint32Slice writes a uint32 slice field to the buffer
func (w writer) WriteUint32Slice(field int, value []uint32) {
w.Call("writePackedUint32", field, value)
}

// WriteMessage writes a message to the buffer using writeFunc
func (w writer) WriteMessage(field int, writeFunc func()) {
w.Call("writeMessage", field, 0 /* Unused */, writeFunc)
}

// WriteEnum writes an enum (as an int) to the buffer
func (w writer) WriteEnum(field int, value int) {
w.Call("writeEnum", field, value)
}

0 comments on commit 41cb18e

Please sign in to comment.