-
Notifications
You must be signed in to change notification settings - Fork 0
/
kvpairs.go
84 lines (74 loc) · 1.72 KB
/
kvpairs.go
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
package gokvpairs
import (
"bytes"
"encoding/json"
"fmt"
"io"
)
type KeyValuePair[T any] struct {
Key string
Value T
}
type KeyValuePairs[T any] []KeyValuePair[T]
func (p *KeyValuePairs[T]) UnmarshalJSON(data []byte) error {
*p = make(KeyValuePairs[T], 0)
dec := json.NewDecoder(bytes.NewReader(data))
dec.UseNumber()
// must open with a delim token '{'
t, err := dec.Token()
if err != nil {
return err
}
if delim, ok := t.(json.Delim); !ok || delim != '{' {
return fmt.Errorf("expect JSON object open with '{'")
}
for dec.More() {
t, err = dec.Token()
if err != nil {
return err
}
key, ok := t.(string)
if !ok {
return fmt.Errorf("expecting JSON key should be always a string: %T: %v", t, t)
}
var value T
err = dec.Decode(&value)
if err != nil {
return fmt.Errorf("JSON value can't be decoded: %T: %v", value, value)
}
*p = append(*p, KeyValuePair[T]{Key: key, Value: value})
}
// must end with a delim token '}'
t, err = dec.Token()
if err != nil {
return err
}
if delim, ok := t.(json.Delim); !ok || delim != '}' {
return fmt.Errorf("expect JSON object close with '}'")
}
if err != nil {
return err
}
t, err = dec.Token()
if err != io.EOF {
return fmt.Errorf("expect end of JSON object but got more token: %T: %v or err: %v", t, t, err)
}
return nil
}
func (p KeyValuePairs[T]) MarshalJSON() ([]byte, error) {
buf := &bytes.Buffer{}
buf.Write([]byte{'{'})
for i, KeyValuePair := range p {
b, err := json.Marshal(&KeyValuePair.Value)
if err != nil {
return nil, err
}
buf.WriteString(fmt.Sprintf("%q:", fmt.Sprintf("%v", KeyValuePair.Key)))
buf.Write(b)
if i < len(p)-1 {
buf.Write([]byte{','})
}
}
buf.Write([]byte{'}'})
return buf.Bytes(), nil
}