Skip to content

Commit

Permalink
add encode
Browse files Browse the repository at this point in the history
  • Loading branch information
mattn committed Jul 11, 2018
1 parent bd0191c commit 0202c96
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 5 deletions.
4 changes: 2 additions & 2 deletions sion.go → decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type Map map[interface{}]interface{}

func (m Map) MarshalJSON() ([]byte, error) {
var buf bytes.Buffer
_, err := buf.WriteString("{")
err := buf.WriteByte('{')
if err != nil {
return nil, err
}
Expand All @@ -42,7 +42,7 @@ func (m Map) MarshalJSON() ([]byte, error) {
}
fmt.Fprintf(&buf, "%q:%s", fmt.Sprint(k), strings.TrimRight(vbuf.String(), "\n"))
}
_, err = buf.WriteString("}")
err = buf.WriteByte('}')
if err != nil {
return nil, err
}
Expand Down
113 changes: 113 additions & 0 deletions encode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package sion

import (
"bytes"
"encoding/json"
"io"
"reflect"
"strings"
)

type Encoder struct {
w io.Writer
}

func NewEncoder(w io.Writer) *Encoder {
return &Encoder{
w: w,
}
}

func (e *Encoder) encodeArray(rv reflect.Value) error {
_, err := e.w.Write([]byte{'['})
if err != nil {
return err
}
for i := 0; i < rv.Len(); i++ {
if i > 0 {
_, err = e.w.Write([]byte{','})
if err != nil {
return err
}
}
err = e.encode(rv.Index(i).Interface())
if err != nil {
return err
}
}
_, err = e.w.Write([]byte{']'})
if err != nil {
return err
}
return nil
}

func (e *Encoder) encodeMap(rv reflect.Value) error {
if rv.Len() == 0 {
_, err := e.w.Write([]byte("[:]"))
return err
}
_, err := e.w.Write([]byte{'['})
if err != nil {
return err
}
for i, key := range rv.MapKeys() {
if i > 0 {
_, err = e.w.Write([]byte{','})
if err != nil {
return err
}
}
err = e.encode(key.Interface())
if err != nil {
return err
}
_, err = e.w.Write([]byte{':'})
if err != nil {
return err
}
err = e.encode(rv.MapIndex(key).Interface())
if err != nil {
return err
}
}
_, err = e.w.Write([]byte{']'})
if err != nil {
return err
}
return nil
}

func (e *Encoder) encode(v interface{}) error {
rv := reflect.Indirect(reflect.ValueOf(v))
rk := rv.Type().Kind()
if rk == reflect.Map {
return e.encodeMap(rv)
} else if rk == reflect.Slice || rk == reflect.Array {
return e.encodeArray(rv)
} else if rk == reflect.Struct {
var buf bytes.Buffer
err := json.NewEncoder(&buf).Encode(v)
if err != nil {
return err
}
s := strings.TrimRight(buf.String(), "\n")
if len(s) > 1 && s[0] == '{' && s[len(s)-1] == '}' {
s = s[1 : len(s)-1]
}
_, err = e.w.Write([]byte(s))
return err
}
var buf bytes.Buffer
err := json.NewEncoder(&buf).Encode(v)
if err != nil {
return err
}
s := strings.TrimRight(buf.String(), "\n")
_, err = e.w.Write([]byte(s))
return err
}

func (e *Encoder) Encode(v interface{}) error {
return e.encode(v)
}
66 changes: 63 additions & 3 deletions sion_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sion

import (
"bytes"
"reflect"
"strings"
"testing"
Expand All @@ -11,8 +12,8 @@ func addressOf(v interface{}) interface{} {
return &v
}

func TestSION(t *testing.T) {
tests := []struct {
func TestDecode(t *testing.T) {
var tests = []struct {
input string
result interface{}
}{
Expand Down Expand Up @@ -158,7 +159,7 @@ func TestSION(t *testing.T) {
}
}

func TestStruct(t *testing.T) {
func TestDecodeStruct(t *testing.T) {
s := `
[
"title": "hello\nworld",
Expand All @@ -181,3 +182,62 @@ func TestStruct(t *testing.T) {
t.Fatalf("v.Created should be %v but %v", 1531314574, v.CreatedAt.Unix())
}
}

func TestEncode(t *testing.T) {
tests := []struct {
input string
result interface{}
}{
{
input: `"foo"`,
result: "foo",
},
{
input: `"fo\no"`,
result: "fo\no",
},
{
input: `314.3`,
result: 314.3,
},
{
input: `-314.3`,
result: -314.3,
},
{
input: `true`,
result: true,
},
{
input: `false`,
result: false,
},
{
input: `[true, 1]`,
result: Array{true, int64(1)},
},
{
input: `[true, [1: "foo"]]`,
result: Array{true, Map{int64(1): "foo"}},
},
{
input: `[true, [:]]`,
result: Array{true, Map{}},
},
}
for _, test := range tests {
var buf bytes.Buffer
err := NewEncoder(&buf).Encode(test.result)
if err != nil {
t.Fatal(err)
}
var v interface{}
err = NewDecoder(&buf).Decode(&v)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(v, test.result) {
t.Fatalf("want %+v but got %+v", test.result, v)
}
}
}

0 comments on commit 0202c96

Please sign in to comment.