github.com/sagernet/sing@v0.4.0-beta.19.0.20240518125136-f67a0988a636/common/json/badjson/merge.go (about) 1 package badjson 2 3 import ( 4 "os" 5 "reflect" 6 7 "github.com/sagernet/sing/common" 8 E "github.com/sagernet/sing/common/exceptions" 9 "github.com/sagernet/sing/common/json" 10 ) 11 12 func Omitempty[T any](value T) (T, error) { 13 objectContent, err := json.Marshal(value) 14 if err != nil { 15 return common.DefaultValue[T](), E.Cause(err, "marshal object") 16 } 17 rawNewObject, err := Decode(objectContent) 18 if err != nil { 19 return common.DefaultValue[T](), err 20 } 21 newObjectContent, err := json.Marshal(rawNewObject) 22 if err != nil { 23 return common.DefaultValue[T](), E.Cause(err, "marshal new object") 24 } 25 var newObject T 26 err = json.Unmarshal(newObjectContent, &newObject) 27 if err != nil { 28 return common.DefaultValue[T](), E.Cause(err, "unmarshal new object") 29 } 30 return newObject, nil 31 } 32 33 func Merge[T any](source T, destination T) (T, error) { 34 rawSource, err := json.Marshal(source) 35 if err != nil { 36 return common.DefaultValue[T](), E.Cause(err, "marshal source") 37 } 38 rawDestination, err := json.Marshal(destination) 39 if err != nil { 40 return common.DefaultValue[T](), E.Cause(err, "marshal destination") 41 } 42 return MergeFrom[T](rawSource, rawDestination) 43 } 44 45 func MergeFromSource[T any](rawSource json.RawMessage, destination T) (T, error) { 46 if rawSource == nil { 47 return destination, nil 48 } 49 rawDestination, err := json.Marshal(destination) 50 if err != nil { 51 return common.DefaultValue[T](), E.Cause(err, "marshal destination") 52 } 53 return MergeFrom[T](rawSource, rawDestination) 54 } 55 56 func MergeFromDestination[T any](source T, rawDestination json.RawMessage) (T, error) { 57 if rawDestination == nil { 58 return source, nil 59 } 60 rawSource, err := json.Marshal(source) 61 if err != nil { 62 return common.DefaultValue[T](), E.Cause(err, "marshal source") 63 } 64 return MergeFrom[T](rawSource, rawDestination) 65 } 66 67 func MergeFrom[T any](rawSource json.RawMessage, rawDestination json.RawMessage) (T, error) { 68 rawMerged, err := MergeJSON(rawSource, rawDestination) 69 if err != nil { 70 return common.DefaultValue[T](), E.Cause(err, "merge options") 71 } 72 var merged T 73 err = json.Unmarshal(rawMerged, &merged) 74 if err != nil { 75 return common.DefaultValue[T](), E.Cause(err, "unmarshal merged options") 76 } 77 return merged, nil 78 } 79 80 func MergeJSON(rawSource json.RawMessage, rawDestination json.RawMessage) (json.RawMessage, error) { 81 if rawSource == nil && rawDestination == nil { 82 return nil, os.ErrInvalid 83 } else if rawSource == nil { 84 return rawDestination, nil 85 } else if rawDestination == nil { 86 return rawSource, nil 87 } 88 source, err := Decode(rawSource) 89 if err != nil { 90 return nil, E.Cause(err, "decode source") 91 } 92 destination, err := Decode(rawDestination) 93 if err != nil { 94 return nil, E.Cause(err, "decode destination") 95 } 96 if source == nil { 97 return json.Marshal(destination) 98 } else if destination == nil { 99 return json.Marshal(source) 100 } 101 merged, err := mergeJSON(source, destination) 102 if err != nil { 103 return nil, err 104 } 105 return json.Marshal(merged) 106 } 107 108 func mergeJSON(anySource any, anyDestination any) (any, error) { 109 switch destination := anyDestination.(type) { 110 case JSONArray: 111 switch source := anySource.(type) { 112 case JSONArray: 113 destination = append(destination, source...) 114 default: 115 destination = append(destination, source) 116 } 117 return destination, nil 118 case *JSONObject: 119 switch source := anySource.(type) { 120 case *JSONObject: 121 for _, entry := range source.Entries() { 122 oldValue, loaded := destination.Get(entry.Key) 123 if loaded { 124 var err error 125 entry.Value, err = mergeJSON(entry.Value, oldValue) 126 if err != nil { 127 return nil, E.Cause(err, "merge object item ", entry.Key) 128 } 129 } 130 destination.Put(entry.Key, entry.Value) 131 } 132 default: 133 return nil, E.New("cannot merge json object into ", reflect.TypeOf(source)) 134 } 135 return destination, nil 136 default: 137 return destination, nil 138 } 139 }