Skip to content

Commit d7ddbd2

Browse files
committed
Added the functionality to deserialize orderedmaps
into CustomTypes like `JSDict`. I added these method to my previous added OrderedMap interface: - SetKeys(keys []string) - InitValues() - Clone(v ...map[string]interface{}) OrderedMap
1 parent 82392f2 commit d7ddbd2

File tree

2 files changed

+218
-52
lines changed

2 files changed

+218
-52
lines changed

orderedmap.go

Lines changed: 66 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,36 @@ type OrderedMap interface {
4040
Set(key string, value interface{})
4141
Delete(key string)
4242
Keys() []string
43+
SetKeys(keys []string)
4344
Values() map[string]interface{}
45+
InitValues()
4446
SortKeys(sortFunc func(keys []string))
4547
Sort(lessFunc func(a *Pair, b *Pair) bool)
4648
UnmarshalJSON(b []byte) error
4749
MarshalJSON() ([]byte, error)
50+
Clone(v ...map[string]interface{}) OrderedMap
4851
}
4952

5053
func New() OrderedMap {
51-
o := OrderedMapImpl{}
52-
o.keys = []string{}
53-
o.values = map[string]interface{}{}
54-
o.escapeHTML = true
55-
return &o
54+
return &OrderedMapImpl{
55+
keys: make([]string, 0, 1),
56+
values: make(map[string]interface{}, 1),
57+
escapeHTML: true,
58+
}
59+
}
60+
61+
func (o *OrderedMapImpl) Clone(oms ...map[string]interface{}) OrderedMap {
62+
var om map[string]interface{}
63+
if len(oms) > 0 {
64+
om = oms[0]
65+
} else {
66+
om = make(map[string]interface{})
67+
}
68+
return &OrderedMapImpl{
69+
keys: make([]string, 0, len(om)),
70+
values: om,
71+
escapeHTML: o.escapeHTML,
72+
}
5673
}
5774

5875
func (o *OrderedMapImpl) SetEscapeHTML(on bool) {
@@ -93,10 +110,20 @@ func (o *OrderedMapImpl) Keys() []string {
93110
return o.keys
94111
}
95112

113+
func (o *OrderedMapImpl) SetKeys(keys []string) {
114+
o.keys = keys
115+
}
116+
96117
func (o *OrderedMapImpl) Values() map[string]interface{} {
97118
return o.values
98119
}
99120

121+
func (o *OrderedMapImpl) InitValues() {
122+
if o.values == nil {
123+
o.values = make(map[string]interface{})
124+
}
125+
}
126+
100127
// SortKeys Sort the map keys using your sort func
101128
func (o *OrderedMapImpl) SortKeys(sortFunc func(keys []string)) {
102129
sortFunc(o.keys)
@@ -116,24 +143,27 @@ func (o *OrderedMapImpl) Sort(lessFunc func(a *Pair, b *Pair) bool) {
116143
}
117144
}
118145

119-
func (o *OrderedMapImpl) UnmarshalJSON(b []byte) error {
120-
if o.values == nil {
121-
o.values = map[string]interface{}{}
122-
}
123-
err := json.Unmarshal(b, &o.values)
146+
func BoundUnmarshalJSON(o OrderedMap, b []byte) error {
147+
o.InitValues()
148+
val := o.Values()
149+
err := json.Unmarshal(b, &val)
124150
if err != nil {
125151
return err
126152
}
127153
dec := json.NewDecoder(bytes.NewReader(b))
128154
if _, err = dec.Token(); err != nil { // skip '{'
129155
return err
130156
}
131-
o.keys = make([]string, 0, len(o.values))
157+
// o.SetKeys(make([]string, 0, len(o.Values())))
132158
return decodeOrderedMap(dec, o)
133159
}
134160

135-
func decodeOrderedMap(dec *json.Decoder, o *OrderedMapImpl) error {
136-
hasKey := make(map[string]bool, len(o.values))
161+
func (o *OrderedMapImpl) UnmarshalJSON(b []byte) error {
162+
return BoundUnmarshalJSON(o, b)
163+
}
164+
165+
func decodeOrderedMap(dec *json.Decoder, o OrderedMap) error {
166+
hasKey := make(map[string]bool, len(o.Values()))
137167
for {
138168
token, err := dec.Token()
139169
if err != nil {
@@ -145,16 +175,16 @@ func decodeOrderedMap(dec *json.Decoder, o *OrderedMapImpl) error {
145175
key := token.(string)
146176
if hasKey[key] {
147177
// duplicate key
148-
for j, k := range o.keys {
178+
for j, k := range o.Keys() {
149179
if k == key {
150-
copy(o.keys[j:], o.keys[j+1:])
180+
copy(o.Keys()[j:], o.Keys()[j+1:])
151181
break
152182
}
153183
}
154-
o.keys[len(o.keys)-1] = key
184+
o.Keys()[len(o.Keys())-1] = key
155185
} else {
156186
hasKey[key] = true
157-
o.keys = append(o.keys, key)
187+
o.SetKeys(append(o.Keys(), key))
158188
}
159189

160190
token, err = dec.Token()
@@ -164,43 +194,35 @@ func decodeOrderedMap(dec *json.Decoder, o *OrderedMapImpl) error {
164194
if delim, ok := token.(json.Delim); ok {
165195
switch delim {
166196
case '{':
167-
if values, ok := o.values[key].(map[string]interface{}); ok {
168-
newMap := &OrderedMapImpl{
169-
keys: make([]string, 0, len(values)),
170-
values: values,
171-
escapeHTML: o.escapeHTML,
172-
}
197+
if values, ok := o.Values()[key].(map[string]interface{}); ok {
198+
newMap := o.Clone(values)
173199
if err = decodeOrderedMap(dec, newMap); err != nil {
174200
return err
175201
}
176-
o.values[key] = newMap
177-
} else if oldMap, ok := o.values[key].(*OrderedMapImpl); ok {
178-
newMap := &OrderedMapImpl{
179-
keys: make([]string, 0, len(oldMap.values)),
180-
values: oldMap.values,
181-
escapeHTML: o.escapeHTML,
182-
}
202+
o.Values()[key] = newMap
203+
} else if oldMap, ok := o.Values()[key].(OrderedMap); ok {
204+
newMap := o.Clone(oldMap.Values())
183205
if err = decodeOrderedMap(dec, newMap); err != nil {
184206
return err
185207
}
186-
o.values[key] = newMap
187-
} else if err = decodeOrderedMap(dec, &OrderedMapImpl{}); err != nil {
208+
o.Values()[key] = newMap
209+
} else if err = decodeOrderedMap(dec, o.Clone()); err != nil {
188210
return err
189211
}
190212
case '[':
191-
if values, ok := o.values[key].([]interface{}); ok {
192-
if err = decodeSlice(dec, values, o.escapeHTML); err != nil {
213+
if values, ok := o.Values()[key].([]interface{}); ok {
214+
if err = decodeSlice(dec, values, o); err != nil {
193215
return err
194216
}
195-
} else if err = decodeSlice(dec, []interface{}{}, o.escapeHTML); err != nil {
217+
} else if err = decodeSlice(dec, []interface{}{}, o); err != nil {
196218
return err
197219
}
198220
}
199221
}
200222
}
201223
}
202224

203-
func decodeSlice(dec *json.Decoder, s []interface{}, escapeHTML bool) error {
225+
func decodeSlice(dec *json.Decoder, s []interface{}, o OrderedMap) error {
204226
for index := 0; ; index++ {
205227
token, err := dec.Token()
206228
if err != nil {
@@ -211,41 +233,33 @@ func decodeSlice(dec *json.Decoder, s []interface{}, escapeHTML bool) error {
211233
case '{':
212234
if index < len(s) {
213235
if values, ok := s[index].(map[string]interface{}); ok {
214-
newMap := &OrderedMapImpl{
215-
keys: make([]string, 0, len(values)),
216-
values: values,
217-
escapeHTML: escapeHTML,
218-
}
236+
newMap := o.Clone(values)
219237
if err = decodeOrderedMap(dec, newMap); err != nil {
220238
return err
221239
}
222240
s[index] = newMap
223-
} else if oldMap, ok := s[index].(*OrderedMapImpl); ok {
224-
newMap := &OrderedMapImpl{
225-
keys: make([]string, 0, len(oldMap.values)),
226-
values: oldMap.values,
227-
escapeHTML: escapeHTML,
228-
}
241+
} else if oldMap, ok := s[index].(OrderedMap); ok {
242+
newMap := o.Clone(oldMap.Values())
229243
if err = decodeOrderedMap(dec, newMap); err != nil {
230244
return err
231245
}
232246
s[index] = newMap
233-
} else if err = decodeOrderedMap(dec, &OrderedMapImpl{}); err != nil {
247+
} else if err = decodeOrderedMap(dec, o.Clone()); err != nil {
234248
return err
235249
}
236-
} else if err = decodeOrderedMap(dec, &OrderedMapImpl{}); err != nil {
250+
} else if err = decodeOrderedMap(dec, o.Clone()); err != nil {
237251
return err
238252
}
239253
case '[':
240254
if index < len(s) {
241255
if values, ok := s[index].([]interface{}); ok {
242-
if err = decodeSlice(dec, values, escapeHTML); err != nil {
256+
if err = decodeSlice(dec, values, o); err != nil {
243257
return err
244258
}
245-
} else if err = decodeSlice(dec, []interface{}{}, escapeHTML); err != nil {
259+
} else if err = decodeSlice(dec, []interface{}{}, o); err != nil {
246260
return err
247261
}
248-
} else if err = decodeSlice(dec, []interface{}{}, escapeHTML); err != nil {
262+
} else if err = decodeSlice(dec, []interface{}{}, o); err != nil {
249263
return err
250264
}
251265
case ']':

orderedmap_test.go

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,3 +639,155 @@ func TestMutableAfterUnmarshal(t *testing.T) {
639639
t.Fatal("expect blabla")
640640
}
641641
}
642+
643+
type myType struct {
644+
omap OrderedMap
645+
}
646+
647+
func NewMyType() OrderedMap {
648+
return &myType{
649+
omap: New(),
650+
}
651+
}
652+
653+
func (j *myType) Clone(v ...map[string]interface{}) OrderedMap {
654+
return &myType{
655+
omap: j.omap.Clone(v...),
656+
}
657+
}
658+
659+
func (j *myType) Delete(key string) {
660+
j.omap.Delete(key)
661+
}
662+
663+
func (j *myType) SortKeys(fn func([]string)) {
664+
j.omap.SortKeys(fn)
665+
}
666+
func (j *myType) Sort(fn func(*Pair, *Pair) bool) {
667+
j.omap.Sort(fn)
668+
}
669+
670+
func (j *myType) SetKeys(keys []string) {
671+
j.omap.SetKeys(keys)
672+
}
673+
674+
func (j *myType) SetEscapeHTML(bool) {
675+
j.omap.SetEscapeHTML(true)
676+
}
677+
678+
func (j *myType) InitValues() {
679+
j.omap.InitValues()
680+
}
681+
682+
// Len implements JSONProperty.
683+
func (j *myType) Len() int {
684+
return len(j.omap.Keys())
685+
}
686+
687+
// Get implements JSONProperty.
688+
func (j *myType) Get(key string) (interface{}, bool) {
689+
return j.Lookup(key)
690+
}
691+
692+
// Lookup implements JSONProperty.
693+
func (j *myType) Lookup(key string) (interface{}, bool) {
694+
out, found := j.omap.Get(key)
695+
if !found {
696+
return nil, false
697+
}
698+
isOmap, found := out.(OrderedMap)
699+
if found {
700+
return &myType{
701+
omap: isOmap,
702+
}, true
703+
}
704+
return out, true
705+
706+
}
707+
708+
// MarshalJSON implements JSONProperty.
709+
func (j *myType) MarshalJSON() ([]byte, error) {
710+
return j.omap.MarshalJSON()
711+
}
712+
713+
// Set implements JSONProperty.
714+
func (j *myType) Set(key string, value interface{}) {
715+
j.omap.Set(key, value)
716+
}
717+
718+
// UnmarshalJSON implements JSONProperty.
719+
func (j *myType) UnmarshalJSON(b []byte) error {
720+
return BoundUnmarshalJSON(j, b)
721+
}
722+
723+
func (j *myType) Keys() []string {
724+
return j.omap.Keys()
725+
}
726+
727+
func (j *myType) Values() map[string]interface{} {
728+
return j.omap.Values()
729+
}
730+
731+
func TestClone(t *testing.T) {
732+
const input = `{
733+
"foo": [
734+
{ "x": 1 },
735+
{ "y": 2 },
736+
"string",
737+
4711
738+
],
739+
"bar": {
740+
"x": 1
741+
}
742+
}`
743+
out := NewMyType()
744+
err := json.Unmarshal([]byte(input), &out)
745+
if err != nil {
746+
t.Fatal(err)
747+
}
748+
749+
oarray, found := out.Get("foo")
750+
if !found {
751+
t.Fatal("foo is not found")
752+
}
753+
array, found := oarray.([]interface{})
754+
if !found {
755+
t.Fatal("foo is not an array")
756+
}
757+
758+
if len(array) != 4 {
759+
t.Fatal("array has not 4 elements")
760+
}
761+
_, found = array[0].(*myType)
762+
if !found {
763+
t.Fatal("array[0] is not a myType")
764+
}
765+
_, found = array[1].(*myType)
766+
if !found {
767+
t.Fatal("array[1] is not a myType")
768+
}
769+
if array[2].(string) != "string" {
770+
t.Fatal("array[2] is not a string")
771+
}
772+
if array[3].(float64) != 4711 {
773+
t.Fatal("array[3] is not a float64")
774+
}
775+
if array[0].(*myType).Keys()[0] != "x" {
776+
t.Fatal("array[0].x is not 1")
777+
}
778+
if array[1].(*myType).Keys()[0] != "y" {
779+
t.Fatal("array[1].y is not 2")
780+
}
781+
782+
obar, found := out.Get("bar")
783+
if !found {
784+
t.Fatal("bar is not found")
785+
}
786+
bar, found := obar.(*myType)
787+
if !found {
788+
t.Fatal("bar is not a myType")
789+
}
790+
if bar.Keys()[0] != "x" {
791+
t.Fatal("bar.x is not 1")
792+
}
793+
}

0 commit comments

Comments
 (0)