diff options
Diffstat (limited to 'vendor/github.com/iancoleman/orderedmap/orderedmap.go')
-rw-r--r-- | vendor/github.com/iancoleman/orderedmap/orderedmap.go | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/vendor/github.com/iancoleman/orderedmap/orderedmap.go b/vendor/github.com/iancoleman/orderedmap/orderedmap.go new file mode 100644 index 000000000..61587d9c7 --- /dev/null +++ b/vendor/github.com/iancoleman/orderedmap/orderedmap.go @@ -0,0 +1,266 @@ +package orderedmap + +import ( + "bytes" + "encoding/json" + "sort" +) + +type Pair struct { + key string + value interface{} +} + +func (kv *Pair) Key() string { + return kv.key +} + +func (kv *Pair) Value() interface{} { + return kv.value +} + +type ByPair struct { + Pairs []*Pair + LessFunc func(a *Pair, j *Pair) bool +} + +func (a ByPair) Len() int { return len(a.Pairs) } +func (a ByPair) Swap(i, j int) { a.Pairs[i], a.Pairs[j] = a.Pairs[j], a.Pairs[i] } +func (a ByPair) Less(i, j int) bool { return a.LessFunc(a.Pairs[i], a.Pairs[j]) } + +type OrderedMap struct { + keys []string + values map[string]interface{} + escapeHTML bool +} + +func New() *OrderedMap { + o := OrderedMap{} + o.keys = []string{} + o.values = map[string]interface{}{} + o.escapeHTML = true + return &o +} + +func (o *OrderedMap) SetEscapeHTML(on bool) { + o.escapeHTML = on +} + +func (o *OrderedMap) Get(key string) (interface{}, bool) { + val, exists := o.values[key] + return val, exists +} + +func (o *OrderedMap) Set(key string, value interface{}) { + _, exists := o.values[key] + if !exists { + o.keys = append(o.keys, key) + } + o.values[key] = value +} + +func (o *OrderedMap) Delete(key string) { + // check key is in use + _, ok := o.values[key] + if !ok { + return + } + // remove from keys + for i, k := range o.keys { + if k == key { + o.keys = append(o.keys[:i], o.keys[i+1:]...) + break + } + } + // remove from values + delete(o.values, key) +} + +func (o *OrderedMap) Keys() []string { + return o.keys +} + +func (o *OrderedMap) Values() map[string]interface{} { + return o.values +} + +// SortKeys Sort the map keys using your sort func +func (o *OrderedMap) SortKeys(sortFunc func(keys []string)) { + sortFunc(o.keys) +} + +// Sort Sort the map using your sort func +func (o *OrderedMap) Sort(lessFunc func(a *Pair, b *Pair) bool) { + pairs := make([]*Pair, len(o.keys)) + for i, key := range o.keys { + pairs[i] = &Pair{key, o.values[key]} + } + + sort.Sort(ByPair{pairs, lessFunc}) + + for i, pair := range pairs { + o.keys[i] = pair.key + } +} + +func (o *OrderedMap) UnmarshalJSON(b []byte) error { + if o.values == nil { + o.values = map[string]interface{}{} + } + err := json.Unmarshal(b, &o.values) + if err != nil { + return err + } + dec := json.NewDecoder(bytes.NewReader(b)) + if _, err = dec.Token(); err != nil { // skip '{' + return err + } + o.keys = make([]string, 0, len(o.values)) + return decodeOrderedMap(dec, o) +} + +func decodeOrderedMap(dec *json.Decoder, o *OrderedMap) error { + hasKey := make(map[string]bool, len(o.values)) + for { + token, err := dec.Token() + if err != nil { + return err + } + if delim, ok := token.(json.Delim); ok && delim == '}' { + return nil + } + key := token.(string) + if hasKey[key] { + // duplicate key + for j, k := range o.keys { + if k == key { + copy(o.keys[j:], o.keys[j+1:]) + break + } + } + o.keys[len(o.keys)-1] = key + } else { + hasKey[key] = true + o.keys = append(o.keys, key) + } + + token, err = dec.Token() + if err != nil { + return err + } + if delim, ok := token.(json.Delim); ok { + switch delim { + case '{': + if values, ok := o.values[key].(map[string]interface{}); ok { + newMap := OrderedMap{ + keys: make([]string, 0, len(values)), + values: values, + escapeHTML: o.escapeHTML, + } + if err = decodeOrderedMap(dec, &newMap); err != nil { + return err + } + o.values[key] = newMap + } else if oldMap, ok := o.values[key].(OrderedMap); ok { + newMap := OrderedMap{ + keys: make([]string, 0, len(oldMap.values)), + values: oldMap.values, + escapeHTML: o.escapeHTML, + } + if err = decodeOrderedMap(dec, &newMap); err != nil { + return err + } + o.values[key] = newMap + } else if err = decodeOrderedMap(dec, &OrderedMap{}); err != nil { + return err + } + case '[': + if values, ok := o.values[key].([]interface{}); ok { + if err = decodeSlice(dec, values, o.escapeHTML); err != nil { + return err + } + } else if err = decodeSlice(dec, []interface{}{}, o.escapeHTML); err != nil { + return err + } + } + } + } +} + +func decodeSlice(dec *json.Decoder, s []interface{}, escapeHTML bool) error { + for index := 0; ; index++ { + token, err := dec.Token() + if err != nil { + return err + } + if delim, ok := token.(json.Delim); ok { + switch delim { + case '{': + if index < len(s) { + if values, ok := s[index].(map[string]interface{}); ok { + newMap := OrderedMap{ + keys: make([]string, 0, len(values)), + values: values, + escapeHTML: escapeHTML, + } + if err = decodeOrderedMap(dec, &newMap); err != nil { + return err + } + s[index] = newMap + } else if oldMap, ok := s[index].(OrderedMap); ok { + newMap := OrderedMap{ + keys: make([]string, 0, len(oldMap.values)), + values: oldMap.values, + escapeHTML: escapeHTML, + } + if err = decodeOrderedMap(dec, &newMap); err != nil { + return err + } + s[index] = newMap + } else if err = decodeOrderedMap(dec, &OrderedMap{}); err != nil { + return err + } + } else if err = decodeOrderedMap(dec, &OrderedMap{}); err != nil { + return err + } + case '[': + if index < len(s) { + if values, ok := s[index].([]interface{}); ok { + if err = decodeSlice(dec, values, escapeHTML); err != nil { + return err + } + } else if err = decodeSlice(dec, []interface{}{}, escapeHTML); err != nil { + return err + } + } else if err = decodeSlice(dec, []interface{}{}, escapeHTML); err != nil { + return err + } + case ']': + return nil + } + } + } +} + +func (o OrderedMap) MarshalJSON() ([]byte, error) { + var buf bytes.Buffer + buf.WriteByte('{') + encoder := json.NewEncoder(&buf) + encoder.SetEscapeHTML(o.escapeHTML) + for i, k := range o.keys { + if i > 0 { + buf.WriteByte(',') + } + // add key + if err := encoder.Encode(k); err != nil { + return nil, err + } + buf.WriteByte(':') + // add value + if err := encoder.Encode(o.values[k]); err != nil { + return nil, err + } + } + buf.WriteByte('}') + return buf.Bytes(), nil +} |