Skip to content

Commit c80c8f9

Browse files
committed
badjson: Add context marshaler/unmarshaler
1 parent a4eb7fa commit c80c8f9

File tree

13 files changed

+285
-60
lines changed

13 files changed

+285
-60
lines changed

common/json/badjson/json.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ package badjson
22

33
import (
44
"bytes"
5+
"context"
56

67
E "github.com/sagernet/sing/common/exceptions"
78
"github.com/sagernet/sing/common/json"
89
)
910

10-
func Decode(content []byte) (any, error) {
11-
decoder := json.NewDecoder(bytes.NewReader(content))
11+
func Decode(ctx context.Context, content []byte) (any, error) {
12+
decoder := json.NewDecoderContext(ctx, bytes.NewReader(content))
1213
return decodeJSON(decoder)
1314
}
1415

common/json/badjson/merge.go

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package badjson
22

33
import (
4+
"context"
45
"os"
56
"reflect"
67

@@ -9,100 +10,100 @@ import (
910
"github.com/sagernet/sing/common/json"
1011
)
1112

12-
func Omitempty[T any](value T) (T, error) {
13+
func Omitempty[T any](ctx context.Context, value T) (T, error) {
1314
objectContent, err := json.Marshal(value)
1415
if err != nil {
1516
return common.DefaultValue[T](), E.Cause(err, "marshal object")
1617
}
17-
rawNewObject, err := Decode(objectContent)
18+
rawNewObject, err := Decode(ctx, objectContent)
1819
if err != nil {
1920
return common.DefaultValue[T](), err
2021
}
21-
newObjectContent, err := json.Marshal(rawNewObject)
22+
newObjectContent, err := json.MarshalContext(ctx, rawNewObject)
2223
if err != nil {
2324
return common.DefaultValue[T](), E.Cause(err, "marshal new object")
2425
}
2526
var newObject T
26-
err = json.Unmarshal(newObjectContent, &newObject)
27+
err = json.UnmarshalContext(ctx, newObjectContent, &newObject)
2728
if err != nil {
2829
return common.DefaultValue[T](), E.Cause(err, "unmarshal new object")
2930
}
3031
return newObject, nil
3132
}
3233

33-
func Merge[T any](source T, destination T, disableAppend bool) (T, error) {
34-
rawSource, err := json.Marshal(source)
34+
func Merge[T any](ctx context.Context, source T, destination T, disableAppend bool) (T, error) {
35+
rawSource, err := json.MarshalContext(ctx, source)
3536
if err != nil {
3637
return common.DefaultValue[T](), E.Cause(err, "marshal source")
3738
}
38-
rawDestination, err := json.Marshal(destination)
39+
rawDestination, err := json.MarshalContext(ctx, destination)
3940
if err != nil {
4041
return common.DefaultValue[T](), E.Cause(err, "marshal destination")
4142
}
42-
return MergeFrom[T](rawSource, rawDestination, disableAppend)
43+
return MergeFrom[T](ctx, rawSource, rawDestination, disableAppend)
4344
}
4445

45-
func MergeFromSource[T any](rawSource json.RawMessage, destination T, disableAppend bool) (T, error) {
46+
func MergeFromSource[T any](ctx context.Context, rawSource json.RawMessage, destination T, disableAppend bool) (T, error) {
4647
if rawSource == nil {
4748
return destination, nil
4849
}
49-
rawDestination, err := json.Marshal(destination)
50+
rawDestination, err := json.MarshalContext(ctx, destination)
5051
if err != nil {
5152
return common.DefaultValue[T](), E.Cause(err, "marshal destination")
5253
}
53-
return MergeFrom[T](rawSource, rawDestination, disableAppend)
54+
return MergeFrom[T](ctx, rawSource, rawDestination, disableAppend)
5455
}
5556

56-
func MergeFromDestination[T any](source T, rawDestination json.RawMessage, disableAppend bool) (T, error) {
57+
func MergeFromDestination[T any](ctx context.Context, source T, rawDestination json.RawMessage, disableAppend bool) (T, error) {
5758
if rawDestination == nil {
5859
return source, nil
5960
}
60-
rawSource, err := json.Marshal(source)
61+
rawSource, err := json.MarshalContext(ctx, source)
6162
if err != nil {
6263
return common.DefaultValue[T](), E.Cause(err, "marshal source")
6364
}
64-
return MergeFrom[T](rawSource, rawDestination, disableAppend)
65+
return MergeFrom[T](ctx, rawSource, rawDestination, disableAppend)
6566
}
6667

67-
func MergeFrom[T any](rawSource json.RawMessage, rawDestination json.RawMessage, disableAppend bool) (T, error) {
68-
rawMerged, err := MergeJSON(rawSource, rawDestination, disableAppend)
68+
func MergeFrom[T any](ctx context.Context, rawSource json.RawMessage, rawDestination json.RawMessage, disableAppend bool) (T, error) {
69+
rawMerged, err := MergeJSON(ctx, rawSource, rawDestination, disableAppend)
6970
if err != nil {
7071
return common.DefaultValue[T](), E.Cause(err, "merge options")
7172
}
7273
var merged T
73-
err = json.Unmarshal(rawMerged, &merged)
74+
err = json.UnmarshalContext(ctx, rawMerged, &merged)
7475
if err != nil {
7576
return common.DefaultValue[T](), E.Cause(err, "unmarshal merged options")
7677
}
7778
return merged, nil
7879
}
7980

80-
func MergeJSON(rawSource json.RawMessage, rawDestination json.RawMessage, disableAppend bool) (json.RawMessage, error) {
81+
func MergeJSON(ctx context.Context, rawSource json.RawMessage, rawDestination json.RawMessage, disableAppend bool) (json.RawMessage, error) {
8182
if rawSource == nil && rawDestination == nil {
8283
return nil, os.ErrInvalid
8384
} else if rawSource == nil {
8485
return rawDestination, nil
8586
} else if rawDestination == nil {
8687
return rawSource, nil
8788
}
88-
source, err := Decode(rawSource)
89+
source, err := Decode(ctx, rawSource)
8990
if err != nil {
9091
return nil, E.Cause(err, "decode source")
9192
}
92-
destination, err := Decode(rawDestination)
93+
destination, err := Decode(ctx, rawDestination)
9394
if err != nil {
9495
return nil, E.Cause(err, "decode destination")
9596
}
9697
if source == nil {
97-
return json.Marshal(destination)
98+
return json.MarshalContext(ctx, destination)
9899
} else if destination == nil {
99100
return json.Marshal(source)
100101
}
101102
merged, err := mergeJSON(source, destination, disableAppend)
102103
if err != nil {
103104
return nil, err
104105
}
105-
return json.Marshal(merged)
106+
return json.MarshalContext(ctx, merged)
106107
}
107108

108109
func mergeJSON(anySource any, anyDestination any, disableAppend bool) (any, error) {

common/json/badjson/merge_objects.go

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,42 @@
11
package badjson
22

33
import (
4+
"context"
5+
46
E "github.com/sagernet/sing/common/exceptions"
57
"github.com/sagernet/sing/common/json"
68
)
79

810
func MarshallObjects(objects ...any) ([]byte, error) {
11+
return MarshallObjectsContext(context.Background(), objects...)
12+
}
13+
14+
func MarshallObjectsContext(ctx context.Context, objects ...any) ([]byte, error) {
915
if len(objects) == 1 {
1016
return json.Marshal(objects[0])
1117
}
1218
var content JSONObject
1319
for _, object := range objects {
14-
objectMap, err := newJSONObject(object)
20+
objectMap, err := newJSONObject(ctx, object)
1521
if err != nil {
1622
return nil, err
1723
}
1824
content.PutAll(objectMap)
1925
}
20-
return content.MarshalJSON()
26+
return content.MarshalJSONContext(ctx)
2127
}
2228

2329
func UnmarshallExcluded(inputContent []byte, parentObject any, object any) error {
24-
parentContent, err := newJSONObject(parentObject)
30+
return UnmarshallExcludedContext(context.Background(), inputContent, parentObject, object)
31+
}
32+
33+
func UnmarshallExcludedContext(ctx context.Context, inputContent []byte, parentObject any, object any) error {
34+
parentContent, err := newJSONObject(ctx, parentObject)
2535
if err != nil {
2636
return err
2737
}
2838
var content JSONObject
29-
err = content.UnmarshalJSON(inputContent)
39+
err = content.UnmarshalJSONContext(ctx, inputContent)
3040
if err != nil {
3141
return err
3242
}
@@ -39,20 +49,20 @@ func UnmarshallExcluded(inputContent []byte, parentObject any, object any) error
3949
}
4050
return E.New("unexpected key: ", content.Keys()[0])
4151
}
42-
inputContent, err = content.MarshalJSON()
52+
inputContent, err = content.MarshalJSONContext(ctx)
4353
if err != nil {
4454
return err
4555
}
46-
return json.UnmarshalDisallowUnknownFields(inputContent, object)
56+
return json.UnmarshalContextDisallowUnknownFields(ctx, inputContent, object)
4757
}
4858

49-
func newJSONObject(object any) (*JSONObject, error) {
50-
inputContent, err := json.Marshal(object)
59+
func newJSONObject(ctx context.Context, object any) (*JSONObject, error) {
60+
inputContent, err := json.MarshalContext(ctx, object)
5161
if err != nil {
5262
return nil, err
5363
}
5464
var content JSONObject
55-
err = content.UnmarshalJSON(inputContent)
65+
err = content.UnmarshalJSONContext(ctx, inputContent)
5666
if err != nil {
5767
return nil, err
5868
}

common/json/badjson/object.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package badjson
22

33
import (
44
"bytes"
5+
"context"
56
"strings"
67

78
"github.com/sagernet/sing/common"
@@ -28,6 +29,10 @@ func (m *JSONObject) IsEmpty() bool {
2829
}
2930

3031
func (m *JSONObject) MarshalJSON() ([]byte, error) {
32+
return m.MarshalJSONContext(context.Background())
33+
}
34+
35+
func (m *JSONObject) MarshalJSONContext(ctx context.Context) ([]byte, error) {
3136
buffer := new(bytes.Buffer)
3237
buffer.WriteString("{")
3338
items := common.Filter(m.Entries(), func(it collections.MapEntry[string, any]) bool {
@@ -38,13 +43,13 @@ func (m *JSONObject) MarshalJSON() ([]byte, error) {
3843
})
3944
iLen := len(items)
4045
for i, entry := range items {
41-
keyContent, err := json.Marshal(entry.Key)
46+
keyContent, err := json.MarshalContext(ctx, entry.Key)
4247
if err != nil {
4348
return nil, err
4449
}
4550
buffer.WriteString(strings.TrimSpace(string(keyContent)))
4651
buffer.WriteString(": ")
47-
valueContent, err := json.Marshal(entry.Value)
52+
valueContent, err := json.MarshalContext(ctx, entry.Value)
4853
if err != nil {
4954
return nil, err
5055
}
@@ -58,7 +63,11 @@ func (m *JSONObject) MarshalJSON() ([]byte, error) {
5863
}
5964

6065
func (m *JSONObject) UnmarshalJSON(content []byte) error {
61-
decoder := json.NewDecoder(bytes.NewReader(content))
66+
return m.UnmarshalJSONContext(context.Background(), content)
67+
}
68+
69+
func (m *JSONObject) UnmarshalJSONContext(ctx context.Context, content []byte) error {
70+
decoder := json.NewDecoderContext(ctx, bytes.NewReader(content))
6271
m.Clear()
6372
objectStart, err := decoder.Token()
6473
if err != nil {

common/json/badjson/typed.go

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package badjson
22

33
import (
44
"bytes"
5+
"context"
56
"strings"
67

78
E "github.com/sagernet/sing/common/exceptions"
@@ -14,18 +15,22 @@ type TypedMap[K comparable, V any] struct {
1415
}
1516

1617
func (m TypedMap[K, V]) MarshalJSON() ([]byte, error) {
18+
return m.MarshalJSONContext(context.Background())
19+
}
20+
21+
func (m TypedMap[K, V]) MarshalJSONContext(ctx context.Context) ([]byte, error) {
1722
buffer := new(bytes.Buffer)
1823
buffer.WriteString("{")
1924
items := m.Entries()
2025
iLen := len(items)
2126
for i, entry := range items {
22-
keyContent, err := json.Marshal(entry.Key)
27+
keyContent, err := json.MarshalContext(ctx, entry.Key)
2328
if err != nil {
2429
return nil, err
2530
}
2631
buffer.WriteString(strings.TrimSpace(string(keyContent)))
2732
buffer.WriteString(": ")
28-
valueContent, err := json.Marshal(entry.Value)
33+
valueContent, err := json.MarshalContext(ctx, entry.Value)
2934
if err != nil {
3035
return nil, err
3136
}
@@ -39,15 +44,19 @@ func (m TypedMap[K, V]) MarshalJSON() ([]byte, error) {
3944
}
4045

4146
func (m *TypedMap[K, V]) UnmarshalJSON(content []byte) error {
42-
decoder := json.NewDecoder(bytes.NewReader(content))
47+
return m.UnmarshalJSONContext(context.Background(), content)
48+
}
49+
50+
func (m *TypedMap[K, V]) UnmarshalJSONContext(ctx context.Context, content []byte) error {
51+
decoder := json.NewDecoderContext(ctx, bytes.NewReader(content))
4352
m.Clear()
4453
objectStart, err := decoder.Token()
4554
if err != nil {
4655
return err
4756
} else if objectStart != json.Delim('{') {
4857
return E.New("expected json object start, but starts with ", objectStart)
4958
}
50-
err = m.decodeJSON(decoder)
59+
err = m.decodeJSON(ctx, decoder)
5160
if err != nil {
5261
return E.Cause(err, "decode json object content")
5362
}
@@ -60,18 +69,18 @@ func (m *TypedMap[K, V]) UnmarshalJSON(content []byte) error {
6069
return nil
6170
}
6271

63-
func (m *TypedMap[K, V]) decodeJSON(decoder *json.Decoder) error {
72+
func (m *TypedMap[K, V]) decodeJSON(ctx context.Context, decoder *json.Decoder) error {
6473
for decoder.More() {
6574
keyToken, err := decoder.Token()
6675
if err != nil {
6776
return err
6877
}
69-
keyContent, err := json.Marshal(keyToken)
78+
keyContent, err := json.MarshalContext(ctx, keyToken)
7079
if err != nil {
7180
return err
7281
}
7382
var entryKey K
74-
err = json.Unmarshal(keyContent, &entryKey)
83+
err = json.UnmarshalContext(ctx, keyContent, &entryKey)
7584
if err != nil {
7685
return err
7786
}

common/json/context_ext.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package json
2+
3+
import (
4+
"context"
5+
6+
"github.com/sagernet/sing/common/json/internal/contextjson"
7+
)
8+
9+
var (
10+
MarshalContext = json.MarshalContext
11+
UnmarshalContext = json.UnmarshalContext
12+
NewEncoderContext = json.NewEncoderContext
13+
NewDecoderContext = json.NewDecoderContext
14+
UnmarshalContextDisallowUnknownFields = json.UnmarshalContextDisallowUnknownFields
15+
)
16+
17+
type ContextMarshaler interface {
18+
MarshalJSONContext(ctx context.Context) ([]byte, error)
19+
}
20+
21+
type ContextUnmarshaler interface {
22+
UnmarshalJSONContext(ctx context.Context, content []byte) error
23+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package json
2+
3+
import "context"
4+
5+
type ContextMarshaler interface {
6+
MarshalJSONContext(ctx context.Context) ([]byte, error)
7+
}
8+
9+
type ContextUnmarshaler interface {
10+
UnmarshalJSONContext(ctx context.Context, content []byte) error
11+
}

0 commit comments

Comments
 (0)