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 }