github.com/sagernet/sing@v0.4.0-beta.19.0.20240518125136-f67a0988a636/common/json/badjson/object.go (about)

     1  package badjson
     2  
     3  import (
     4  	"bytes"
     5  	"strings"
     6  
     7  	"github.com/sagernet/sing/common"
     8  	E "github.com/sagernet/sing/common/exceptions"
     9  	"github.com/sagernet/sing/common/json"
    10  	"github.com/sagernet/sing/common/x/collections"
    11  	"github.com/sagernet/sing/common/x/linkedhashmap"
    12  )
    13  
    14  type JSONObject struct {
    15  	linkedhashmap.Map[string, any]
    16  }
    17  
    18  func (m *JSONObject) IsEmpty() bool {
    19  	if m.Size() == 0 {
    20  		return true
    21  	}
    22  	return common.All(m.Entries(), func(it collections.MapEntry[string, any]) bool {
    23  		if valueInterface, valueMaybeEmpty := it.Value.(isEmpty); valueMaybeEmpty && valueInterface.IsEmpty() {
    24  			return true
    25  		}
    26  		return false
    27  	})
    28  }
    29  
    30  func (m *JSONObject) MarshalJSON() ([]byte, error) {
    31  	buffer := new(bytes.Buffer)
    32  	buffer.WriteString("{")
    33  	items := common.Filter(m.Entries(), func(it collections.MapEntry[string, any]) bool {
    34  		if valueInterface, valueMaybeEmpty := it.Value.(isEmpty); valueMaybeEmpty && valueInterface.IsEmpty() {
    35  			return false
    36  		}
    37  		return true
    38  	})
    39  	iLen := len(items)
    40  	for i, entry := range items {
    41  		keyContent, err := json.Marshal(entry.Key)
    42  		if err != nil {
    43  			return nil, err
    44  		}
    45  		buffer.WriteString(strings.TrimSpace(string(keyContent)))
    46  		buffer.WriteString(": ")
    47  		valueContent, err := json.Marshal(entry.Value)
    48  		if err != nil {
    49  			return nil, err
    50  		}
    51  		buffer.WriteString(strings.TrimSpace(string(valueContent)))
    52  		if i < iLen-1 {
    53  			buffer.WriteString(", ")
    54  		}
    55  	}
    56  	buffer.WriteString("}")
    57  	return buffer.Bytes(), nil
    58  }
    59  
    60  func (m *JSONObject) UnmarshalJSON(content []byte) error {
    61  	decoder := json.NewDecoder(bytes.NewReader(content))
    62  	m.Clear()
    63  	objectStart, err := decoder.Token()
    64  	if err != nil {
    65  		return err
    66  	} else if objectStart != json.Delim('{') {
    67  		return E.New("expected json object start, but starts with ", objectStart)
    68  	}
    69  	err = m.decodeJSON(decoder)
    70  	if err != nil {
    71  		return E.Cause(err, "decode json object content")
    72  	}
    73  	objectEnd, err := decoder.Token()
    74  	if err != nil {
    75  		return err
    76  	} else if objectEnd != json.Delim('}') {
    77  		return E.New("expected json object end, but ends with ", objectEnd)
    78  	}
    79  	return nil
    80  }
    81  
    82  func (m *JSONObject) decodeJSON(decoder *json.Decoder) error {
    83  	for decoder.More() {
    84  		var entryKey string
    85  		keyToken, err := decoder.Token()
    86  		if err != nil {
    87  			return err
    88  		}
    89  		entryKey = keyToken.(string)
    90  		var entryValue any
    91  		entryValue, err = decodeJSON(decoder)
    92  		if err != nil {
    93  			return E.Cause(err, "decode value for ", entryKey)
    94  		}
    95  		m.Put(entryKey, entryValue)
    96  	}
    97  	return nil
    98  }