pkg/util/orderedmap/orderedmap.go (72 lines of code) (raw):
package orderedmap
// Copyright (c) Microsoft Corporation.
// Licensed under the Apache License 2.0.
import (
"bytes"
"encoding/json"
"fmt"
"reflect"
)
// UnmarshalJSON unmarshals a JSON object into a slice of key/value structs,
// preserving key order.
func UnmarshalJSON(b []byte, i interface{}) error {
xs := reflect.ValueOf(i).Elem()
d := json.NewDecoder(bytes.NewReader(b))
tok, err := d.Token()
if err != nil {
return err
}
if tok != json.Delim('{') {
return fmt.Errorf("unexpected token %v", tok)
}
indexes := map[string]int{}
for {
tok, err = d.Token()
if err != nil {
return err
}
if tok == json.Delim('}') {
break
}
k, ok := tok.(string)
if !ok {
return fmt.Errorf("unexpected token %v", tok)
}
kv := reflect.New(xs.Type().Elem()).Elem()
kv.Field(0).SetString(k)
err = d.Decode(kv.Field(1).Addr().Interface())
if err != nil {
return err
}
if i, found := indexes[k]; found {
xs.Index(i).Set(kv)
} else {
indexes[k] = xs.Len()
xs = reflect.Append(xs, kv)
}
}
reflect.ValueOf(i).Elem().Set(xs)
return nil
}
// MarshalJSON unmarshals a slice of key/value structs into a JSON object,
// preserving key order.
func MarshalJSON(i interface{}) ([]byte, error) {
if i == nil {
return []byte("null"), nil
}
buf := &bytes.Buffer{}
buf.WriteByte('{')
xs := reflect.ValueOf(i)
for i := 0; i < xs.Len(); i++ {
b, err := json.Marshal(xs.Index(i).Field(0).String())
if err != nil {
return nil, err
}
buf.Write(b)
buf.WriteByte(':')
b, err = json.Marshal(xs.Index(i).Field(1).Interface())
if err != nil {
return nil, err
}
buf.Write(b)
if i < xs.Len()-1 {
buf.WriteByte(',')
}
}
buf.WriteByte('}')
return buf.Bytes(), nil
}