1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
| package util
import ( "bytes" "cmp" "encoding/json" "encoding/xml" "slices"
"github.com/samber/lo" )
type OrderedMap[V any] struct { Lexical bool Order []string Map map[string]V }
func NewOrderedMap[V any](lexical bool, capacity int) *OrderedMap[V] { return &OrderedMap[V]{Lexical: lexical, Order: make([]string, 0, capacity), Map: make(map[string]V, capacity)} }
func (o *OrderedMap[V]) Append(k string, v V) { o.Order = append(o.Order, k) o.Map[k] = v if o.Lexical { slices.Sort(o.Order) } }
func (o *OrderedMap[V]) Get(k string) (V, bool) { ret, ok := o.Map[k] return ret, ok }
func (o *OrderedMap[V]) GetSimple(k string) V { return o.Map[k] }
func (o OrderedMap[V]) MarshalYAML() (any, error) { return o.Map, nil }
func (o OrderedMap[V]) MarshalXML(e *xml.Encoder, start xml.StartElement) error { if err := e.EncodeToken(start); err != nil { return err }
for _, key := range o.Order { n := xml.Name{Local: key} t := xml.StartElement{Name: n}
v := o.Map[key] e := e.EncodeElement(v, t) if e != nil { return e } }
if err := e.EncodeToken(xml.EndElement{Name: start.Name}); err != nil { return err }
return e.Flush() }
func (o *OrderedMap[V]) UnmarshalJSON(b []byte) error { if err := FromJSON(b, &o.Map); err != nil { return err }
index := make(map[string]int) lo.ForEach(lo.Keys(o.Map), func(key string, _ int) { o.Order = append(o.Order, key) esc := ToJSONBytes(key, false) // escape the key index[key] = bytes.Index(b, esc) })
if o.Lexical { slices.SortFunc(o.Order, func(l string, r string) int { return cmp.Compare(index[l], index[r]) }) } return nil }
func (o OrderedMap[V]) MarshalJSON() ([]byte, error) { var b []byte buf := bytes.NewBuffer(b) buf.WriteByte('{') l := len(o.Order) for i, key := range o.Order { km, err := json.Marshal(key) if err != nil { return nil, err } buf.Write(km) buf.WriteByte(':') vm, err := json.Marshal(o.Map[key]) if err != nil { return nil, err } buf.Write(vm) if i != l-1 { buf.WriteByte(',') } } buf.WriteByte('}') return buf.Bytes(), nil }
|