-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwkt_fieldmask.go
96 lines (89 loc) · 2.6 KB
/
wkt_fieldmask.go
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package jsoniterpb
import (
"fmt"
"strings"
"unsafe"
jsoniter "github.com/json-iterator/go"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/known/fieldmaskpb"
)
const (
FieldMask_Paths_field_fullname protoreflect.FullName = "google.protobuf.FieldMask.paths"
)
var wktFieldmaskCodec = (&ProtoCodec{}).
SetElemEncodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, stream *jsoniter.Stream) {
v := ((*fieldmaskpb.FieldMask)(ptr))
paths := make([]string, 0, len(v.GetPaths()))
for _, s := range v.GetPaths() {
if !protoreflect.FullName(s).IsValid() {
stream.Error = fmt.Errorf("%s contains invalid path: %q", FieldMask_Paths_field_fullname, s)
return
}
// Return error if conversion to camelCase is not reversible.
cc := JSONCamelCase(s)
if s != JSONSnakeCase(cc) {
stream.Error = fmt.Errorf("%s contains irreversible value %q", FieldMask_Paths_field_fullname, s)
return
}
paths = append(paths, cc)
}
stream.WriteVal(strings.Join(paths, ","))
}).
SetElemDecodeFunc(func(e *ProtoExtension, ptr unsafe.Pointer, iter *jsoniter.Iterator) {
var str string
iter.ReadVal(&str)
if str == "" {
(*fieldmaskpb.FieldMask)(ptr).Paths = []string{}
return
}
paths := strings.Split(str, ",")
for idx, s0 := range paths {
s := JSONSnakeCase(s0)
if strings.Contains(s0, "_") || !protoreflect.FullName(s).IsValid() {
iter.ReportError("protobuf", fmt.Sprintf("%v contains invalid path: %q", FieldMask_Paths_field_fullname, s0))
return
}
paths[idx] = s
}
(*fieldmaskpb.FieldMask)(ptr).Paths = paths
})
func isASCIILower(c byte) bool {
return 'a' <= c && c <= 'z'
}
func isASCIIUpper(c byte) bool {
return 'A' <= c && c <= 'Z'
}
func isASCIIDigit(c byte) bool {
return '0' <= c && c <= '9'
}
// JSONCamelCase converts a snake_case identifier to a camelCase identifier,
// according to the protobuf JSON specification.
func JSONCamelCase(s string) string {
var b []byte
var wasUnderscore bool
for i := 0; i < len(s); i++ { // proto identifiers are always ASCII
c := s[i]
if c != '_' {
if wasUnderscore && isASCIILower(c) {
c -= 'a' - 'A' // convert to uppercase
}
b = append(b, c)
}
wasUnderscore = c == '_'
}
return string(b)
}
// JSONSnakeCase converts a camelCase identifier to a snake_case identifier,
// according to the protobuf JSON specification.
func JSONSnakeCase(s string) string {
var b []byte
for i := 0; i < len(s); i++ { // proto identifiers are always ASCII
c := s[i]
if isASCIIUpper(c) {
b = append(b, '_')
c += 'a' - 'A' // convert to lowercase
}
b = append(b, c)
}
return string(b)
}