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  }