Browse Source

Refactor json

世界 3 years ago
parent
commit
28b865acf0
8 changed files with 179 additions and 188 deletions
  1. 46 0
      common/badjson/array.go
  2. 43 0
      common/badjson/json.go
  3. 78 0
      common/badjson/object.go
  4. 0 171
      common/linkedhashmap/map.go
  5. 0 7
      constant/require.go
  6. 1 1
      go.mod
  7. 2 2
      go.sum
  8. 9 7
      option/json.go

+ 46 - 0
common/badjson/array.go

@@ -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 - 0
common/badjson/json.go

@@ -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 - 0
common/badjson/object.go

@@ -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
+}

+ 0 - 171
common/linkedhashmap/map.go

@@ -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]{}
-}

+ 0 - 7
constant/require.go

@@ -1,7 +0,0 @@
-//go:build !go1.19
-
-package constant
-
-func init() {
-	panic("sing-box requires Go 1.19 or later")
-}

+ 1 - 1
go.mod

@@ -7,7 +7,7 @@ require (
 	github.com/goccy/go-json v0.9.8
 	github.com/logrusorgru/aurora v2.0.3+incompatible
 	github.com/oschwald/geoip2-golang v1.7.0
-	github.com/sagernet/sing v0.0.0-20220703051339-f128942ffe12
+	github.com/sagernet/sing v0.0.0-20220703114149-368e41b67bc4
 	github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649
 	github.com/sirupsen/logrus v1.8.1
 	github.com/spf13/cobra v1.5.0

+ 2 - 2
go.sum

@@ -20,8 +20,8 @@ github.com/oschwald/maxminddb-golang v1.9.0/go.mod h1:TK+s/Z2oZq0rSl4PSeAEoP0bgm
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/sagernet/sing v0.0.0-20220703051339-f128942ffe12 h1:HN3IoHyR2tpI4WwBVSDo5VJ0tKrQKqltkjlHTG9vbdo=
-github.com/sagernet/sing v0.0.0-20220703051339-f128942ffe12/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c=
+github.com/sagernet/sing v0.0.0-20220703114149-368e41b67bc4 h1:ePp3j7E71+yJfuIxDLzYkngK1AelkP2jITjkMKaHoBs=
+github.com/sagernet/sing v0.0.0-20220703114149-368e41b67bc4/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c=
 github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649 h1:whNDUGOAX5GPZkSy4G3Gv9QyIgk5SXRyjkRuP7ohF8k=
 github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649/go.mod h1:MuyT+9fEPjvauAv0fSE0a6Q+l0Tv2ZrAafTkYfnxBFw=
 github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=

+ 9 - 7
option/json.go

@@ -4,15 +4,15 @@ import (
 	"bytes"
 
 	"github.com/goccy/go-json"
-	"github.com/sagernet/sing-box/common/linkedhashmap"
+	"github.com/sagernet/sing-box/common/badjson"
 )
 
-func ToMap(v any) (*linkedhashmap.Map[string, any], error) {
+func ToMap(v any) (*badjson.JSONObject, error) {
 	inputContent, err := json.Marshal(v)
 	if err != nil {
 		return nil, err
 	}
-	var content linkedhashmap.Map[string, any]
+	var content badjson.JSONObject
 	err = content.UnmarshalJSON(inputContent)
 	if err != nil {
 		return nil, err
@@ -20,8 +20,8 @@ func ToMap(v any) (*linkedhashmap.Map[string, any], error) {
 	return &content, nil
 }
 
-func MergeObjects(objects ...any) (*linkedhashmap.Map[string, any], error) {
-	var content linkedhashmap.Map[string, any]
+func MergeObjects(objects ...any) (*badjson.JSONObject, error) {
+	var content badjson.JSONObject
 	for _, object := range objects {
 		objectMap, err := ToMap(object)
 		if err != nil {
@@ -45,12 +45,14 @@ func UnmarshallExcluded(inputContent []byte, parentObject any, object any) error
 	if err != nil {
 		return err
 	}
-	var content linkedhashmap.Map[string, any]
+	var content badjson.JSONObject
 	err = content.UnmarshalJSON(inputContent)
 	if err != nil {
 		return err
 	}
-	content.RemoveAll(parentContent.Keys())
+	for _, key := range parentContent.Keys() {
+		content.Remove(key)
+	}
 	inputContent, err = content.MarshalJSON()
 	if err != nil {
 		return err