168 lines
5.0 KiB
Go
168 lines
5.0 KiB
Go
package hjson
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
)
|
|
|
|
// OrderedMap wraps a map and a slice containing all of the keys from the map,
|
|
// so that the order of the keys can be specified. The Keys slice can be sorted
|
|
// or rearranged like any other slice, but do not add or remove keys manually
|
|
// on it. Use OrderedMap.Insert(), OrderedMap.Set(), OrderedMap.DeleteIndex() or
|
|
// OrderedMap.DeleteKey() instead.
|
|
//
|
|
// Example of how to iterate through the elements of an OrderedMap in order:
|
|
//
|
|
// for _, key := range om.Keys {
|
|
// fmt.Printf("%v\n", om.Map[key])
|
|
// }
|
|
//
|
|
// Always use the functions Insert() or Set() instead of setting values
|
|
// directly on OrderedMap.Map, because any new keys must also be added to
|
|
// OrderedMap.Keys. Otherwise those keys will be ignored when iterating through
|
|
// the elements of the OrderedMap in order, as for example happens in the
|
|
// function hjson.Marshal().
|
|
type OrderedMap struct {
|
|
Keys []string
|
|
Map map[string]interface{}
|
|
}
|
|
|
|
// KeyValue is only used as input to NewOrderedMapFromSlice().
|
|
type KeyValue struct {
|
|
Key string
|
|
Value interface{}
|
|
}
|
|
|
|
// NewOrderedMap returns a pointer to a new OrderedMap. An OrderedMap should
|
|
// always be passed by reference, never by value. If an OrderedMap is passed
|
|
// by value then appending new keys won't affect all of the copies of the
|
|
// OrderedMap.
|
|
func NewOrderedMap() *OrderedMap {
|
|
return &OrderedMap{
|
|
Keys: nil,
|
|
Map: map[string]interface{}{},
|
|
}
|
|
}
|
|
|
|
// NewOrderedMapFromSlice is like NewOrderedMap but with initial values.
|
|
// Example:
|
|
//
|
|
// om := NewOrderedMapFromSlice([]KeyValue{
|
|
// {"B", "first"},
|
|
// {"A", "second"},
|
|
// })
|
|
func NewOrderedMapFromSlice(args []KeyValue) *OrderedMap {
|
|
c := NewOrderedMap()
|
|
for _, elem := range args {
|
|
c.Set(elem.Key, elem.Value)
|
|
}
|
|
return c
|
|
}
|
|
|
|
// Len returns the number of values contained in the OrderedMap.
|
|
func (c *OrderedMap) Len() int {
|
|
return len(c.Keys)
|
|
}
|
|
|
|
// AtIndex returns the value found at the specified index. Panics if
|
|
// index < 0 or index >= c.Len().
|
|
func (c *OrderedMap) AtIndex(index int) interface{} {
|
|
return c.Map[c.Keys[index]]
|
|
}
|
|
|
|
// AtKey returns the value found for the specified key, and true if the value
|
|
// was found. Returns nil and false if the value was not found.
|
|
func (c *OrderedMap) AtKey(key string) (interface{}, bool) {
|
|
ret, ok := c.Map[key]
|
|
return ret, ok
|
|
}
|
|
|
|
// Insert inserts a new key/value pair at the specified index. Panics if
|
|
// index < 0 or index > c.Len(). If the key already exists in the OrderedMap,
|
|
// the new value is set but the position of the key is not changed. Returns
|
|
// the old value and true if the key already exists in the OrderedMap, nil and
|
|
// false otherwise.
|
|
func (c *OrderedMap) Insert(index int, key string, value interface{}) (interface{}, bool) {
|
|
oldValue, exists := c.Map[key]
|
|
c.Map[key] = value
|
|
if exists {
|
|
return oldValue, true
|
|
}
|
|
if index == len(c.Keys) {
|
|
c.Keys = append(c.Keys, key)
|
|
} else {
|
|
c.Keys = append(c.Keys[:index+1], c.Keys[index:]...)
|
|
c.Keys[index] = key
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
// Set sets the specified value for the specified key. If the key does not
|
|
// already exist in the OrderedMap it is appended to the end of the OrderedMap.
|
|
// If the key already exists in the OrderedMap, the new value is set but the
|
|
// position of the key is not changed. Returns the old value and true if the
|
|
// key already exists in the OrderedMap, nil and false otherwise.
|
|
func (c *OrderedMap) Set(key string, value interface{}) (interface{}, bool) {
|
|
return c.Insert(len(c.Keys), key, value)
|
|
}
|
|
|
|
// DeleteIndex deletes the key/value pair found at the specified index.
|
|
// Returns the deleted key and value. Panics if index < 0 or index >= c.Len().
|
|
func (c *OrderedMap) DeleteIndex(index int) (string, interface{}) {
|
|
key := c.Keys[index]
|
|
value := c.Map[key]
|
|
delete(c.Map, key)
|
|
c.Keys = append(c.Keys[:index], c.Keys[index+1:]...)
|
|
return key, value
|
|
}
|
|
|
|
// DeleteKey deletes the key/value pair with the specified key, if found.
|
|
// Returns the deleted value and true if the key was found, nil and false
|
|
// otherwise.
|
|
func (c *OrderedMap) DeleteKey(key string) (interface{}, bool) {
|
|
for index, ck := range c.Keys {
|
|
if ck == key {
|
|
_, value := c.DeleteIndex(index)
|
|
return value, true
|
|
}
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
// MarshalJSON is an implementation of the json.Marshaler interface, enabling
|
|
// hjson.OrderedMap to be used as input for json.Marshal().
|
|
func (c *OrderedMap) MarshalJSON() ([]byte, error) {
|
|
var b bytes.Buffer
|
|
|
|
b.WriteString("{")
|
|
|
|
for index, key := range c.Keys {
|
|
if index > 0 {
|
|
b.WriteString(",")
|
|
}
|
|
jbuf, err := json.Marshal(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
b.Write(jbuf)
|
|
b.WriteString(":")
|
|
jbuf, err = json.Marshal(c.Map[key])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
b.Write(jbuf)
|
|
}
|
|
|
|
b.WriteString("}")
|
|
|
|
return b.Bytes(), nil
|
|
}
|
|
|
|
// UnmarshalJSON is an implementation of the json.Unmarshaler interface,
|
|
// enabling hjson.OrderedMap to be used as destination for json.Unmarshal().
|
|
func (c *OrderedMap) UnmarshalJSON(b []byte) error {
|
|
c.Keys = nil
|
|
c.Map = map[string]interface{}{}
|
|
return Unmarshal(b, c)
|
|
}
|