trpc.group/trpc-go/trpc-cmdline@v1.0.9/util/apidocs/ordered_map.go (about)

     1  // Tencent is pleased to support the open source community by making tRPC available.
     2  //
     3  // Copyright (C) 2023 THL A29 Limited, a Tencent company.
     4  // All rights reserved.
     5  //
     6  // If you have downloaded a copy of the tRPC source code from Tencent,
     7  // please note that tRPC source code is licensed under the  Apache 2.0 License,
     8  // A copy of the Apache 2.0 License is included in this file.
     9  
    10  package apidocs
    11  
    12  import (
    13  	"bytes"
    14  	"encoding/json"
    15  	"reflect"
    16  	"sort"
    17  )
    18  
    19  // OrderedUnmarshalJSON deserializes JSON data while preserving the order of keys.
    20  func OrderedUnmarshalJSON(b []byte, element interface{}, rank interface{}) error {
    21  	if err := json.Unmarshal(b, element); err != nil {
    22  		return err
    23  	}
    24  
    25  	elemObject := reflect.ValueOf(element).Elem()
    26  	index := make(map[string]int, elemObject.Len())
    27  	keys := make([]string, 0, elemObject.Len())
    28  	for _, key := range elemObject.MapKeys() {
    29  		keys = append(keys, key.String())
    30  		nk, _ := json.Marshal(key.String()) // Escape the key
    31  		index[key.String()] = bytes.Index(b, nk)
    32  	}
    33  
    34  	// Sort keys based on their occurrence index in the JSON data.
    35  	sort.Slice(keys, func(i, j int) bool {
    36  		return index[keys[i]] < index[keys[j]]
    37  	})
    38  
    39  	rankObject := reflect.ValueOf(rank).Elem()
    40  	if rankObject.IsNil() {
    41  		rankObject.Set(reflect.MakeMap(rankObject.Type()))
    42  	}
    43  
    44  	// Assign rank values to keys based on their sorted order.
    45  	for idx, key := range keys {
    46  		rankObject.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(idx+1))
    47  	}
    48  
    49  	return nil
    50  }
    51  
    52  // OrderedMarshalJSON serializes data to JSON while preserving the order of keys.
    53  func OrderedMarshalJSON(element interface{}, rank map[string]int) ([]byte, error) {
    54  	if len(rank) == 0 {
    55  		return json.Marshal(element)
    56  	}
    57  
    58  	var keys []string
    59  	elemObject := reflect.ValueOf(element)
    60  	for _, key := range elemObject.MapKeys() {
    61  		keys = append(keys, key.String())
    62  	}
    63  
    64  	// Sort keys based on their rank values.
    65  	sort.Slice(keys, func(i, j int) bool {
    66  		return rank[keys[i]] < rank[keys[j]]
    67  	})
    68  
    69  	buf := &bytes.Buffer{}
    70  	buf.WriteRune('{')
    71  	l := len(keys)
    72  	for idx, key := range keys {
    73  		k, err := json.Marshal(key)
    74  		if err != nil {
    75  			return nil, err
    76  		}
    77  		buf.Write(k)
    78  		buf.WriteRune(':')
    79  
    80  		v, err := json.Marshal(elemObject.MapIndex(reflect.ValueOf(key)).Interface())
    81  		if err != nil {
    82  			return nil, err
    83  		}
    84  		buf.Write(v)
    85  
    86  		if idx != l-1 {
    87  			buf.WriteRune(',')
    88  		}
    89  	}
    90  	buf.WriteRune('}')
    91  	return buf.Bytes(), nil
    92  }