Refactor json

This commit is contained in:
世界 2022-07-03 19:43:27 +08:00
parent dd56b2584b
commit 28b865acf0
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
8 changed files with 179 additions and 188 deletions

46
common/badjson/array.go Normal file
View file

@ -0,0 +1,46 @@
package badjson
import (
"bytes"
"github.com/goccy/go-json"
E "github.com/sagernet/sing/common/exceptions"
)
type JSONArray[T any] []T
func (a JSONArray[T]) MarshalJSON() ([]byte, error) {
return json.Marshal([]T(a))
}
func (a *JSONArray[T]) UnmarshalJSON(content []byte) error {
decoder := json.NewDecoder(bytes.NewReader(content))
arrayStart, err := decoder.Token()
if err != nil {
return err
} else if arrayStart != json.Delim('[') {
return E.New("excepted array start, but got ", arrayStart)
}
err = a.decodeJSON(decoder)
if err != nil {
return err
}
arrayEnd, err := decoder.Token()
if err != nil {
return err
} else if arrayEnd != json.Delim(']') {
return E.New("excepted array end, but got ", arrayEnd)
}
return nil
}
func (a *JSONArray[T]) decodeJSON(decoder *json.Decoder) error {
for decoder.More() {
var item T
err := decoder.Decode(&item)
if err != nil {
return err
}
}
return nil
}

43
common/badjson/json.go Normal file
View file

@ -0,0 +1,43 @@
package badjson
import (
"github.com/goccy/go-json"
E "github.com/sagernet/sing/common/exceptions"
)
func decodeJSON(decoder *json.Decoder) (any, error) {
rawToken, err := decoder.Token()
if err != nil {
return nil, err
}
switch token := rawToken.(type) {
case json.Delim:
switch token {
case '{':
var object JSONObject
err = object.decodeJSON(decoder)
if err != nil {
return nil, err
} else if rawToken != json.Delim('}') {
return nil, E.New("excepted object end, but got ", rawToken)
}
return object, nil
case '[':
var array JSONArray[any]
err = array.decodeJSON(decoder)
if err != nil {
return nil, err
}
rawToken, err = decoder.Token()
if err != nil {
return nil, err
} else if rawToken != json.Delim(']') {
return nil, E.New("excepted array end, but got ", rawToken)
}
return &array, nil
default:
return nil, E.New("excepted object or array end: ", token)
}
}
return rawToken, nil
}

78
common/badjson/object.go Normal file
View file

@ -0,0 +1,78 @@
package badjson
import (
"bytes"
"strings"
"github.com/goccy/go-json"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/x/linkedhashmap"
)
type JSONObject struct {
linkedhashmap.Map[string, any]
}
func (m *JSONObject) MarshalJSON() ([]byte, error) {
buffer := new(bytes.Buffer)
buffer.WriteString("{")
items := m.Entries()
iLen := len(items)
for i, entry := range items {
keyContent, err := json.Marshal(entry.Key)
if err != nil {
return nil, err
}
buffer.WriteString(strings.TrimSpace(string(keyContent)))
buffer.WriteString(": ")
valueContent, err := json.Marshal(entry.Value)
if err != nil {
return nil, err
}
buffer.WriteString(strings.TrimSpace(string(valueContent)))
if i < iLen-1 {
buffer.WriteString(", ")
}
}
buffer.WriteString("}")
return buffer.Bytes(), nil
}
func (m *JSONObject) UnmarshalJSON(content []byte) error {
decoder := json.NewDecoder(bytes.NewReader(content))
m.Clear()
objectStart, err := decoder.Token()
if err != nil {
return err
} else if objectStart != json.Delim('{') {
return E.New("expected json object start, but starts with ", objectStart)
}
err = m.decodeJSON(decoder)
if err != nil {
return err
}
objectEnd, err := decoder.Token()
if err != nil {
return err
} else if objectEnd != json.Delim('}') {
return E.New("expected json object end, but ends with ", objectEnd)
}
return nil
}
func (m *JSONObject) decodeJSON(decoder *json.Decoder) error {
for decoder.More() {
var entryKey string
err := decoder.Decode(&entryKey)
if err != nil {
return err
}
var entryValue any
entryValue, err = decodeJSON(decoder)
if err != nil {
return err
}
m.Put(entryKey, entryValue)
}
return nil
}

View file

@ -1,171 +0,0 @@
package linkedhashmap
import (
"bytes"
"github.com/goccy/go-json"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/x/list"
)
type Map[K comparable, V any] struct {
raw list.List[mapEntry[K, V]]
rawMap map[K]*list.Element[mapEntry[K, V]]
}
func (m *Map[K, V]) init() {
if m.rawMap == nil {
m.rawMap = make(map[K]*list.Element[mapEntry[K, V]])
}
}
func (m *Map[K, V]) MarshalJSON() ([]byte, error) {
buffer := new(bytes.Buffer)
buffer.WriteString("{")
for item := m.raw.Front(); item != nil; {
entry := item.Value
err := json.NewEncoder(buffer).Encode(entry.Key)
if err != nil {
return nil, err
}
buffer.WriteString(": ")
err = json.NewEncoder(buffer).Encode(entry.Value)
if err != nil {
return nil, err
}
item = item.Next()
if item != nil {
buffer.WriteString(", ")
}
}
buffer.WriteString("}")
return buffer.Bytes(), nil
}
func (m *Map[K, V]) UnmarshalJSON(content []byte) error {
decoder := json.NewDecoder(bytes.NewReader(content))
m.Clear()
m.init()
objectStart, err := decoder.Token()
if err != nil {
return err
} else if objectStart != json.Delim('{') {
return E.New("expected json object start, but starts with ", objectStart)
}
for decoder.More() {
var entryKey K
err = decoder.Decode(&entryKey)
if err != nil {
return err
}
var entryValue V
err = decoder.Decode(&entryValue)
if err != nil {
return err
}
m.rawMap[entryKey] = m.raw.PushBack(mapEntry[K, V]{Key: entryKey, Value: entryValue})
}
objectEnd, err := decoder.Token()
if err != nil {
return err
} else if objectEnd != json.Delim('}') {
return E.New("expected json object end, but ends with ", objectEnd)
}
return nil
}
type mapEntry[K comparable, V any] struct {
Key K
Value V
}
func (m *Map[K, V]) Size() int {
return m.raw.Size()
}
func (m *Map[K, V]) IsEmpty() bool {
return m.raw.IsEmpty()
}
func (m *Map[K, V]) ContainsKey(key K) bool {
m.init()
_, loaded := m.rawMap[key]
return loaded
}
func (m *Map[K, V]) Get(key K) (V, bool) {
m.init()
value, loaded := m.rawMap[key]
return value.Value.Value, loaded
}
func (m *Map[K, V]) Put(key K, value V) V {
m.init()
entry, loaded := m.rawMap[key]
if loaded {
oldValue := entry.Value.Value
entry.Value.Value = value
return oldValue
}
entry = m.raw.PushBack(mapEntry[K, V]{Key: key, Value: value})
m.rawMap[key] = entry
return common.DefaultValue[V]()
}
func (m *Map[K, V]) PutAll(other *Map[K, V]) {
for item := other.raw.Front(); item != nil; item = item.Next() {
m.Put(item.Value.Key, item.Value.Value)
}
}
func (m *Map[K, V]) Remove(key K) bool {
m.init()
entry, loaded := m.rawMap[key]
if !loaded {
return false
}
m.raw.Remove(entry)
delete(m.rawMap, key)
return true
}
func (m *Map[K, V]) RemoveAll(keys []K) {
m.init()
for _, key := range keys {
entry, loaded := m.rawMap[key]
if !loaded {
continue
}
m.raw.Remove(entry)
delete(m.rawMap, key)
}
}
func (m *Map[K, V]) AsMap() map[K]V {
result := make(map[K]V, m.raw.Len())
for item := m.raw.Front(); item != nil; item = item.Next() {
result[item.Value.Key] = item.Value.Value
}
return result
}
func (m *Map[K, V]) Keys() []K {
result := make([]K, 0, m.raw.Len())
for item := m.raw.Front(); item != nil; item = item.Next() {
result = append(result, item.Value.Key)
}
return result
}
func (m *Map[K, V]) Values() []V {
result := make([]V, 0, m.raw.Len())
for item := m.raw.Front(); item != nil; item = item.Next() {
result = append(result, item.Value.Value)
}
return result
}
func (m *Map[K, V]) Clear() {
*m = Map[K, V]{}
}