From 1e893e1cc74005a8baff5f37c73ff88e4adf48ad Mon Sep 17 00:00:00 2001
From: Gabriel Handford
Date: Fri, 21 Aug 2020 10:57:15 -0700
Subject: [PATCH] json: Use TextMarshaler interface
---
encoding/encode.go | 4 ++++
json/marshal.go | 57 +++++++++++++++++++++++++-------------------
json/marshal_test.go | 20 ++++++++--------
statement.go | 20 ++++++++--------
user/user.go | 14 +++++------
5 files changed, 64 insertions(+), 51 deletions(-)
diff --git a/encoding/encode.go b/encoding/encode.go
index 271a5ad..0bd526a 100644
--- a/encoding/encode.go
+++ b/encoding/encode.go
@@ -2,6 +2,7 @@
package encoding
import (
+ stdencoding "encoding"
"encoding/base32"
"encoding/base64"
"encoding/hex"
@@ -11,6 +12,9 @@ import (
"github.com/pkg/errors"
)
+// TextMarshaler alias for encoding.TextMarshaler.
+type TextMarshaler = stdencoding.TextMarshaler
+
// Encoding is an encoding for bytes to and from a string
type Encoding string
diff --git a/json/marshal.go b/json/marshal.go
index 79c1d65..3ddf160 100644
--- a/json/marshal.go
+++ b/json/marshal.go
@@ -2,12 +2,13 @@
package json
import (
+ "bytes"
"encoding/json"
"regexp"
"strconv"
- "strings"
"github.com/keys-pub/keys/encoding"
+
"github.com/pkg/errors"
)
@@ -21,55 +22,63 @@ type intEntry struct {
value int
}
-// Value to string.
-type Value interface {
- Marshal() (string, error)
-}
-
-// NewString ...
-func NewString(key string, value string) Value {
+// String ...
+func String(key string, value string) encoding.TextMarshaler {
return stringEntry{key: key, value: value}
}
-// NewInt ...
-func NewInt(key string, value int) Value {
+// Int ...
+func Int(key string, value int) encoding.TextMarshaler {
return intEntry{key: key, value: value}
}
var isAlphaNumericDot = regexp.MustCompile(`^[a-zA-Z0-9.]+$`).MatchString
var needsEscape = regexp.MustCompile(`^[\"]+$`).MatchString
-func (e stringEntry) Marshal() (string, error) {
+func (e stringEntry) MarshalText() ([]byte, error) {
if !isAlphaNumericDot(e.key) {
- return "", errors.Errorf("invalid character in key")
+ return nil, errors.Errorf("invalid character in key")
}
if needsEscape(e.value) {
- return "", errors.Errorf("invalid character in value")
+ return nil, errors.Errorf("invalid character in value")
}
if !encoding.IsASCII([]byte(e.value)) {
- return "", errors.Errorf("invalid character in value")
+ return nil, errors.Errorf("invalid character in value")
}
- return `"` + e.key + `":"` + e.value + `"`, nil
+ return []byte(`"` + e.key + `":"` + e.value + `"`), nil
}
-func (e intEntry) Marshal() (string, error) {
+func (e intEntry) MarshalText() ([]byte, error) {
if !isAlphaNumericDot(e.key) {
- return "", errors.Errorf("invalid character in key")
+ return nil, errors.Errorf("invalid character in key")
}
- return `"` + e.key + `":` + strconv.Itoa(e.value), nil
+
+ b := []byte{}
+ b = append(b, '"')
+ b = append(b, []byte(e.key)...)
+ b = append(b, '"', ':')
+ b = append(b, []byte(strconv.Itoa(e.value))...)
+
+ return b, nil
}
// Marshal values.
-func Marshal(es []Value) ([]byte, error) {
- out := make([]string, 0, len(es))
- for _, e := range es {
- s, err := e.Marshal()
+func Marshal(vals ...encoding.TextMarshaler) ([]byte, error) {
+ out := make([][]byte, 0, len(vals))
+ for _, val := range vals {
+ b, err := val.MarshalText()
if err != nil {
return nil, err
}
- out = append(out, s)
+ out = append(out, b)
}
- return []byte("{" + strings.Join(out, ",") + "}"), nil
+
+ b := []byte{}
+ b = append(b, '{')
+ b = append(b, bytes.Join(out, []byte{','})...)
+ b = append(b, '}')
+
+ return b, nil
}
// Unmarshal bytes.
diff --git a/json/marshal_test.go b/json/marshal_test.go
index b7693ca..5738e53 100644
--- a/json/marshal_test.go
+++ b/json/marshal_test.go
@@ -8,19 +8,19 @@ import (
)
func TestMarshal(t *testing.T) {
- b, err := json.Marshal([]json.Value{
- json.NewString("key1", "val1"),
- json.NewInt("key2", 2),
- })
+ b, err := json.Marshal(
+ json.String("key1", "val1"),
+ json.Int("key2", 2),
+ )
require.NoError(t, err)
require.Equal(t, `{"key1":"val1","key2":2}`, string(b))
- _, err = json.Marshal([]json.Value{
- json.NewString(`"`, ""),
- })
+ _, err = json.Marshal(
+ json.String(`"`, ""),
+ )
require.EqualError(t, err, "invalid character in key")
- _, err = json.Marshal([]json.Value{
- json.NewString("key1", `"`),
- })
+ _, err = json.Marshal(
+ json.String("key1", `"`),
+ )
require.EqualError(t, err, "invalid character in value")
}
diff --git a/statement.go b/statement.go
index cfeec76..c1a5a0f 100644
--- a/statement.go
+++ b/statement.go
@@ -210,30 +210,30 @@ func statementBytesToSign(st *Statement) ([]byte, error) {
}
func statementBytes(st *Statement, sig []byte) ([]byte, error) {
- mes := []json.Value{
- json.NewString(".sig", encoding.MustEncode(sig, encoding.Base64)),
+ mes := []encoding.TextMarshaler{
+ json.String(".sig", encoding.MustEncode(sig, encoding.Base64)),
}
if len(st.Data) != 0 {
- mes = append(mes, json.NewString("data", encoding.MustEncode(st.Data, encoding.Base64)))
+ mes = append(mes, json.String("data", encoding.MustEncode(st.Data, encoding.Base64)))
}
- mes = append(mes, json.NewString("kid", st.KID.String()))
+ mes = append(mes, json.String("kid", st.KID.String()))
if len(st.Prev) != 0 {
- mes = append(mes, json.NewString("prev", encoding.MustEncode(st.Prev, encoding.Base64)))
+ mes = append(mes, json.String("prev", encoding.MustEncode(st.Prev, encoding.Base64)))
}
if st.Revoke != 0 {
- mes = append(mes, json.NewInt("revoke", st.Revoke))
+ mes = append(mes, json.Int("revoke", st.Revoke))
}
if st.Seq != 0 {
- mes = append(mes, json.NewInt("seq", st.Seq))
+ mes = append(mes, json.Int("seq", st.Seq))
}
if !st.Timestamp.IsZero() {
- mes = append(mes, json.NewInt("ts", int(tsutil.Millis(st.Timestamp))))
+ mes = append(mes, json.Int("ts", int(tsutil.Millis(st.Timestamp))))
}
if st.Type != "" {
- mes = append(mes, json.NewString("type", st.Type))
+ mes = append(mes, json.String("type", st.Type))
}
- return json.Marshal(mes)
+ return json.Marshal(mes...)
}
// unmarshalJSON returns a Statement from JSON bytes.
diff --git a/user/user.go b/user/user.go
index 0cb946a..623cb79 100644
--- a/user/user.go
+++ b/user/user.go
@@ -45,19 +45,19 @@ func (u User) MarshalJSON() ([]byte, error) {
// Bytes is a serialized User.
func (u User) Bytes() ([]byte, error) {
- mes := []json.Value{}
+ mes := []encoding.TextMarshaler{}
- mes = append(mes, json.NewString("k", u.KID.String()))
- mes = append(mes, json.NewString("n", u.Name))
+ mes = append(mes, json.String("k", u.KID.String()))
+ mes = append(mes, json.String("n", u.Name))
if u.Seq != 0 {
- mes = append(mes, json.NewInt("sq", u.Seq))
+ mes = append(mes, json.Int("sq", u.Seq))
}
- mes = append(mes, json.NewString("sr", u.Service))
+ mes = append(mes, json.String("sr", u.Service))
if u.URL != "" {
- mes = append(mes, json.NewString("u", u.URL))
+ mes = append(mes, json.String("u", u.URL))
}
- return json.Marshal(mes)
+ return json.Marshal(mes...)
}
// Status is the status of the user statement.