encoding/jsonpb: add support for basic unmarshaling

Unmarshaling of scalar, messages, repeated, and maps.

Need to further improve on error messages for consistency, some error
messages contain the position info while some currently do not.  There
are cases where position info is wrong as well when a value is decoded
in another pass, e.g. numbers in string value, or map keys.

Change-Id: I6f9e903c499b5e87fb258dbdada7434389fc7522
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/166338
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/internal/encoding/json/decode.go b/internal/encoding/json/decode.go
index 543abbc..452e873 100644
--- a/internal/encoding/json/decode.go
+++ b/internal/encoding/json/decode.go
@@ -15,9 +15,24 @@
 	"github.com/golang/protobuf/v2/internal/errors"
 )
 
+// call specifies which Decoder method was invoked.
+type call uint8
+
+const (
+	readCall call = iota
+	peekCall
+)
+
 // Decoder is a token-based JSON decoder.
 type Decoder struct {
-	lastType Type
+	// lastCall is last method called, eiterh readCall or peekCall.
+	lastCall call
+
+	// value contains the last read value.
+	value Value
+
+	// err contains the last read error.
+	err error
 
 	// startStack is a stack containing StartObject and StartArray types. The
 	// top of stack represents the object or the array the current value is
@@ -35,10 +50,24 @@
 	return &Decoder{orig: b, in: b}
 }
 
-// ReadNext returns the next JSON value. It will return an error if there is no
-// valid JSON value.  For String types containing invalid UTF8 characters, a
-// non-fatal error is returned and caller can call ReadNext for the next value.
-func (d *Decoder) ReadNext() (Value, error) {
+// Peek looks ahead and returns the next JSON type without advancing a read.
+func (d *Decoder) Peek() Type {
+	defer func() { d.lastCall = peekCall }()
+	if d.lastCall == readCall {
+		d.value, d.err = d.Read()
+	}
+	return d.value.typ
+}
+
+// Read returns the next JSON value. It will return an error if there is no
+// valid value.  For String types containing invalid UTF8 characters, a
+// non-fatal error is returned and caller can call Read for the next value.
+func (d *Decoder) Read() (Value, error) {
+	defer func() { d.lastCall = readCall }()
+	if d.lastCall == peekCall {
+		return d.value, d.err
+	}
+
 	var nerr errors.NonFatal
 	value, n, err := d.parseNext()
 	if !nerr.Merge(err) {
@@ -48,7 +77,7 @@
 	switch value.typ {
 	case EOF:
 		if len(d.startStack) != 0 ||
-			d.lastType&Null|Bool|Number|String|EndObject|EndArray == 0 {
+			d.value.typ&Null|Bool|Number|String|EndObject|EndArray == 0 {
 			return Value{}, io.ErrUnexpectedEOF
 		}
 
@@ -67,7 +96,7 @@
 			break
 		}
 		// Check if this is for an object name.
-		if d.lastType&(StartObject|comma) == 0 {
+		if d.value.typ&(StartObject|comma) == 0 {
 			return Value{}, d.newSyntaxError("unexpected value %q", value)
 		}
 		d.in = d.in[n:]
@@ -86,7 +115,7 @@
 
 	case EndObject:
 		if len(d.startStack) == 0 ||
-			d.lastType == comma ||
+			d.value.typ == comma ||
 			d.startStack[len(d.startStack)-1] != StartObject {
 			return Value{}, d.newSyntaxError("unexpected character }")
 		}
@@ -94,7 +123,7 @@
 
 	case EndArray:
 		if len(d.startStack) == 0 ||
-			d.lastType == comma ||
+			d.value.typ == comma ||
 			d.startStack[len(d.startStack)-1] != StartArray {
 			return Value{}, d.newSyntaxError("unexpected character ]")
 		}
@@ -102,18 +131,18 @@
 
 	case comma:
 		if len(d.startStack) == 0 ||
-			d.lastType&(Null|Bool|Number|String|EndObject|EndArray) == 0 {
+			d.value.typ&(Null|Bool|Number|String|EndObject|EndArray) == 0 {
 			return Value{}, d.newSyntaxError("unexpected character ,")
 		}
 	}
 
 	// Update lastType only after validating value to be in the right
 	// sequence.
-	d.lastType = value.typ
+	d.value.typ = value.typ
 	d.in = d.in[n:]
 
-	if d.lastType == comma {
-		return d.ReadNext()
+	if d.value.typ == comma {
+		return d.Read()
 	}
 	return value, nerr.E
 }
@@ -244,19 +273,19 @@
 // Number, String or Bool.
 func (d *Decoder) isValueNext() bool {
 	if len(d.startStack) == 0 {
-		return d.lastType == 0
+		return d.value.typ == 0
 	}
 
 	start := d.startStack[len(d.startStack)-1]
 	switch start {
 	case StartObject:
-		return d.lastType&Name != 0
+		return d.value.typ&Name != 0
 	case StartArray:
-		return d.lastType&(StartArray|comma) != 0
+		return d.value.typ&(StartArray|comma) != 0
 	}
 	panic(fmt.Sprintf(
 		"unreachable logic in Decoder.isValueNext, lastType: %v, startStack: %v",
-		d.lastType, start))
+		d.value.typ, start))
 }
 
 // newValue constructs a Value.
@@ -271,7 +300,7 @@
 	}
 }
 
-// Value contains a JSON type and value parsed from calling Decoder.ReadNext.
+// Value contains a JSON type and value parsed from calling Decoder.Read.
 type Value struct {
 	input  []byte
 	line   int
diff --git a/internal/encoding/json/decode_test.go b/internal/encoding/json/decode_test.go
index 4917bc2..dc7f25f 100644
--- a/internal/encoding/json/decode_test.go
+++ b/internal/encoding/json/decode_test.go
@@ -13,9 +13,9 @@
 )
 
 type R struct {
-	// T is expected Type returned from calling Decoder.ReadNext.
+	// T is expected Type returned from calling Decoder.Read.
 	T json.Type
-	// E is expected error substring from calling Decoder.ReadNext if set.
+	// E is expected error substring from calling Decoder.Read if set.
 	E string
 	// V is expected value from calling
 	// Value.{Bool()|Float()|Int()|Uint()|String()} depending on type.
@@ -31,8 +31,8 @@
 	tests := []struct {
 		input string
 		// want is a list of expected values returned from calling
-		// Decoder.ReadNext. An item makes the test code invoke
-		// Decoder.ReadNext and compare against R.T and R.E.  For Bool,
+		// Decoder.Read. An item makes the test code invoke
+		// Decoder.Read and compare against R.T and R.E.  For Bool,
 		// Number and String tokens, it invokes the corresponding getter method
 		// and compares the returned value against R.V or R.VE if it returned an
 		// error.
@@ -47,8 +47,8 @@
 			want:  []R{{T: json.EOF}},
 		},
 		{
-			// Calling ReadNext after EOF will keep returning EOF for
-			// succeeding ReadNext calls.
+			// Calling Read after EOF will keep returning EOF for
+			// succeeding Read calls.
 			input: space,
 			want: []R{
 				{T: json.EOF},
@@ -119,7 +119,7 @@
 			},
 		},
 		{
-			// Invalid UTF-8 error is returned in ReadString instead of ReadNext.
+			// Invalid UTF-8 error is returned in ReadString instead of Read.
 			input: "\"\xff\"",
 			want: []R{
 				{T: json.String, E: `invalid UTF-8 detected`, V: string("\xff")},
@@ -1009,22 +1009,26 @@
 		t.Run("", func(t *testing.T) {
 			dec := json.NewDecoder([]byte(tc.input))
 			for i, want := range tc.want {
-				value, err := dec.ReadNext()
+				typ := dec.Peek()
+				if typ != want.T {
+					t.Errorf("input: %v\nPeek() got %v want %v", tc.input, typ, want.T)
+				}
+				value, err := dec.Read()
 				if err != nil {
 					if want.E == "" {
-						t.Errorf("input: %v\nReadNext() got unexpected error: %v", tc.input, err)
+						t.Errorf("input: %v\nRead() got unexpected error: %v", tc.input, err)
 
 					} else if !strings.Contains(err.Error(), want.E) {
-						t.Errorf("input: %v\nReadNext() got %q, want %q", tc.input, err, want.E)
+						t.Errorf("input: %v\nRead() got %q, want %q", tc.input, err, want.E)
 					}
 				} else {
 					if want.E != "" {
-						t.Errorf("input: %v\nReadNext() got nil error, want %q", tc.input, want.E)
+						t.Errorf("input: %v\nRead() got nil error, want %q", tc.input, want.E)
 					}
 				}
 				token := value.Type()
 				if token != want.T {
-					t.Errorf("input: %v\nReadNext() got %v, want %v", tc.input, token, want.T)
+					t.Errorf("input: %v\nRead() got %v, want %v", tc.input, token, want.T)
 					break
 				}
 				checkValue(t, value, i, want)
diff --git a/internal/encoding/json/types.go b/internal/encoding/json/types.go
index 28901e8..35feeb7 100644
--- a/internal/encoding/json/types.go
+++ b/internal/encoding/json/types.go
@@ -8,7 +8,7 @@
 type Type uint
 
 const (
-	_ Type = (1 << iota) / 2
+	Invalid Type = (1 << iota) / 2
 	EOF
 	Null
 	Bool