From f16807b8fab522d0a3857214aa1da325d97ab598 Mon Sep 17 00:00:00 2001 From: "Aldo \"xoen\" Giambelluca" Date: Thu, 21 Apr 2016 12:14:44 +0100 Subject: [PATCH 1/2] Implemented io.Reader interface Pretty much as implemented in bytes.Read() [1] [1]: https://golang.org/src/bytes/reader.go?s=3260:3292#L38 --- simplejson.go | 49 +++++++++++++++++++++++++++++++++++++--------- simplejson_test.go | 13 ++++++++++++ 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/simplejson.go b/simplejson.go index 27ce986..060accb 100644 --- a/simplejson.go +++ b/simplejson.go @@ -3,6 +3,7 @@ package simplejson import ( "encoding/json" "errors" + "io" "log" ) @@ -12,7 +13,39 @@ func Version() string { } type Json struct { - data interface{} + data interface{} + reader *Reader +} + +// Keeps the JSON's bytes and the reader index +type Reader struct { + s []byte // JSON's bytes + i int64 // current reading index +} + +// Implements the io.Reader interface. +func (j *Json) Read(b []byte) (int, error) { + if j.reader == nil { + bytes, err := j.Encode() + if err != nil { + return 0, err + } + + j.reader = &Reader{s: bytes, i: 0} + } + + if len(b) == 0 { + return 0, nil + } + + if j.reader.i > int64(len(j.reader.s)) { + return 0, io.EOF + } + + n := copy(b, j.reader.s[j.reader.i:]) + j.reader.i += int64(n) + + return n, nil } // NewJson returns a pointer to a new `Json` object @@ -28,9 +61,7 @@ func NewJson(body []byte) (*Json, error) { // New returns a pointer to a new, empty `Json` object func New() *Json { - return &Json{ - data: make(map[string]interface{}), - } + return &Json{data: make(map[string]interface{}), reader: nil} } // Interface returns the underlying data @@ -120,10 +151,10 @@ func (j *Json) Get(key string) *Json { m, err := j.Map() if err == nil { if val, ok := m[key]; ok { - return &Json{val} + return &Json{data: val, reader: nil} } } - return &Json{nil} + return &Json{data: nil, reader: nil} } // GetPath searches for the item as specified by the branch @@ -148,10 +179,10 @@ func (j *Json) GetIndex(index int) *Json { a, err := j.Array() if err == nil { if len(a) > index { - return &Json{a[index]} + return &Json{data: a[index], reader: nil} } } - return &Json{nil} + return &Json{data: nil, reader: nil} } // CheckGet returns a pointer to a new `Json` object and @@ -165,7 +196,7 @@ func (j *Json) CheckGet(key string) (*Json, bool) { m, err := j.Map() if err == nil { if val, ok := m[key]; ok { - return &Json{val}, true + return &Json{data: val, reader: nil}, true } } return nil, false diff --git a/simplejson_test.go b/simplejson_test.go index b46ffff..fe0e2cf 100644 --- a/simplejson_test.go +++ b/simplejson_test.go @@ -149,6 +149,19 @@ func TestStdlibInterfaces(t *testing.T) { assert.Equal(t, val, val2) // stable } +func TestIoReader(t *testing.T) { + strIn := `{"name":"myobject","params":{"string":"simplejson"}}` + bIn := []byte(strIn) + jIn, _ := NewJson(bIn) + + jOut, err := NewFromReader(jIn) + assert.Equal(t, nil, err) + + bOut, err := jOut.Encode() + assert.Equal(t, nil, err) + assert.Equal(t, bOut, bIn) +} + func TestSet(t *testing.T) { js, err := NewJson([]byte(`{}`)) assert.Equal(t, nil, err) From d16666b7459a290dc67d8b04a570b263027036cd Mon Sep 17 00:00:00 2001 From: "Aldo \"xoen\" Giambelluca" Date: Fri, 22 Apr 2016 00:20:40 +0100 Subject: [PATCH 2/2] Reset reader pointer when the JSON data changes As the reader pointer contains the bytes for the JSON, whne it changes these would not be valid anymore. NOTE: If the JSON changes between 2 Read() calls the result would still be incorrect as the 2nd read would returns bytes from the new JSON. Not sure how this --- simplejson.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/simplejson.go b/simplejson.go index 060accb..d12a42a 100644 --- a/simplejson.go +++ b/simplejson.go @@ -92,11 +92,14 @@ func (j *Json) Set(key string, val interface{}) { return } m[key] = val + j.reader = nil // JSON changed, reset reader } // SetPath modifies `Json`, recursively checking/creating map keys for the supplied path, // and then finally writing in the value func (j *Json) SetPath(branch []string, val interface{}) { + j.reader = nil // JSON changed, reset reader + if len(branch) == 0 { j.data = val return @@ -140,6 +143,7 @@ func (j *Json) Del(key string) { return } delete(m, key) + j.reader = nil // JSON changed, reset reader } // Get returns a pointer to a new `Json` object