Core

/app/util/mapordered.go (2.1 KB)

  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
}