...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package collate
29
30 import (
31 "sort"
32 "sync"
33
34 "golang.org/x/text/collate"
35 "golang.org/x/text/language"
36 )
37
38 var (
39 collatorMu = new(sync.Mutex)
40 collator = collate.New(language.Und)
41 )
42
43
44
45 func CompareString(a, b string) int {
46 collatorMu.Lock()
47 defer collatorMu.Unlock()
48 return collator.CompareString(a, b)
49 }
50
51
52
53
54
55 func CompareObject(a, b interface{}) int {
56 aType := jsonTypeOf(a)
57 switch bType := jsonTypeOf(b); {
58 case aType < bType:
59 return -1
60 case aType > bType:
61 return 1
62 }
63
64 switch aType {
65 case jsonTypeBool:
66 aBool := a.(bool)
67 bBool := b.(bool)
68 if aBool == bBool {
69 return 0
70 }
71
72 if !aBool {
73 return -1
74 }
75 return 1
76 case jsonTypeNull:
77 if b == nil {
78 return 0
79 }
80 return -1
81 case jsonTypeNumber:
82 return int(a.(float64) - b.(float64))
83 case jsonTypeString:
84 return CompareString(a.(string), b.(string))
85 case jsonTypeArray:
86 aArray := a.([]interface{})
87 bArray := b.([]interface{})
88 for i := 0; i < len(aArray) && i < len(bArray); i++ {
89 if cmp := CompareObject(aArray[i], bArray[i]); cmp != 0 {
90 return cmp
91 }
92 }
93 return len(aArray) - len(bArray)
94 case jsonTypeObject:
95 aObject := a.(map[string]interface{})
96 bObject := b.(map[string]interface{})
97 keyMap := make(map[string]struct{}, len(aObject))
98 for k := range aObject {
99 keyMap[k] = struct{}{}
100 }
101 for k := range bObject {
102 keyMap[k] = struct{}{}
103 }
104 keys := make([]string, 0, len(keyMap))
105 for k := range keyMap {
106 keys = append(keys, k)
107 }
108 sort.Slice(keys, func(i, j int) bool {
109 return CompareString(keys[i], keys[j]) < 0
110 })
111
112 for i, k := range keys {
113 av, aok := aObject[k]
114 if !aok {
115 return 1
116 }
117 bv, bok := bObject[k]
118 if !bok {
119 return -1
120 }
121 if cmp := CompareObject(av, bv); cmp != 0 {
122 return cmp
123 }
124 if i+1 == len(aObject) || i+1 == len(bObject) {
125 return len(aObject) - len(bObject)
126 }
127 }
128 }
129 panic("unexpected JSON type")
130 }
131
View as plain text