1
2
3
4
5
6
7
8
9
10 package defval
11
12 import (
13 "fmt"
14 "math"
15 "strconv"
16
17 ptext "google.golang.org/protobuf/internal/encoding/text"
18 "google.golang.org/protobuf/internal/errors"
19 "google.golang.org/protobuf/reflect/protoreflect"
20 )
21
22
23 type Format int
24
25 const (
26 _ Format = iota
27
28
29
30 Descriptor
31
32
33 GoTag
34 )
35
36
37
38 func Unmarshal(s string, k protoreflect.Kind, evs protoreflect.EnumValueDescriptors, f Format) (protoreflect.Value, protoreflect.EnumValueDescriptor, error) {
39 switch k {
40 case protoreflect.BoolKind:
41 if f == GoTag {
42 switch s {
43 case "1":
44 return protoreflect.ValueOfBool(true), nil, nil
45 case "0":
46 return protoreflect.ValueOfBool(false), nil, nil
47 }
48 } else {
49 switch s {
50 case "true":
51 return protoreflect.ValueOfBool(true), nil, nil
52 case "false":
53 return protoreflect.ValueOfBool(false), nil, nil
54 }
55 }
56 case protoreflect.EnumKind:
57 if f == GoTag {
58
59 if n, err := strconv.ParseInt(s, 10, 32); err == nil {
60 if ev := evs.ByNumber(protoreflect.EnumNumber(n)); ev != nil {
61 return protoreflect.ValueOfEnum(ev.Number()), ev, nil
62 }
63 }
64 } else {
65
66 ev := evs.ByName(protoreflect.Name(s))
67 if ev != nil {
68 return protoreflect.ValueOfEnum(ev.Number()), ev, nil
69 }
70 }
71 case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
72 if v, err := strconv.ParseInt(s, 10, 32); err == nil {
73 return protoreflect.ValueOfInt32(int32(v)), nil, nil
74 }
75 case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
76 if v, err := strconv.ParseInt(s, 10, 64); err == nil {
77 return protoreflect.ValueOfInt64(int64(v)), nil, nil
78 }
79 case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
80 if v, err := strconv.ParseUint(s, 10, 32); err == nil {
81 return protoreflect.ValueOfUint32(uint32(v)), nil, nil
82 }
83 case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
84 if v, err := strconv.ParseUint(s, 10, 64); err == nil {
85 return protoreflect.ValueOfUint64(uint64(v)), nil, nil
86 }
87 case protoreflect.FloatKind, protoreflect.DoubleKind:
88 var v float64
89 var err error
90 switch s {
91 case "-inf":
92 v = math.Inf(-1)
93 case "inf":
94 v = math.Inf(+1)
95 case "nan":
96 v = math.NaN()
97 default:
98 v, err = strconv.ParseFloat(s, 64)
99 }
100 if err == nil {
101 if k == protoreflect.FloatKind {
102 return protoreflect.ValueOfFloat32(float32(v)), nil, nil
103 } else {
104 return protoreflect.ValueOfFloat64(float64(v)), nil, nil
105 }
106 }
107 case protoreflect.StringKind:
108
109 return protoreflect.ValueOfString(s), nil, nil
110 case protoreflect.BytesKind:
111 if b, ok := unmarshalBytes(s); ok {
112 return protoreflect.ValueOfBytes(b), nil, nil
113 }
114 }
115 return protoreflect.Value{}, nil, errors.New("could not parse value for %v: %q", k, s)
116 }
117
118
119
120
121 func Marshal(v protoreflect.Value, ev protoreflect.EnumValueDescriptor, k protoreflect.Kind, f Format) (string, error) {
122 switch k {
123 case protoreflect.BoolKind:
124 if f == GoTag {
125 if v.Bool() {
126 return "1", nil
127 } else {
128 return "0", nil
129 }
130 } else {
131 if v.Bool() {
132 return "true", nil
133 } else {
134 return "false", nil
135 }
136 }
137 case protoreflect.EnumKind:
138 if f == GoTag {
139 return strconv.FormatInt(int64(v.Enum()), 10), nil
140 } else {
141 return string(ev.Name()), nil
142 }
143 case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
144 return strconv.FormatInt(v.Int(), 10), nil
145 case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
146 return strconv.FormatUint(v.Uint(), 10), nil
147 case protoreflect.FloatKind, protoreflect.DoubleKind:
148 f := v.Float()
149 switch {
150 case math.IsInf(f, -1):
151 return "-inf", nil
152 case math.IsInf(f, +1):
153 return "inf", nil
154 case math.IsNaN(f):
155 return "nan", nil
156 default:
157 if k == protoreflect.FloatKind {
158 return strconv.FormatFloat(f, 'g', -1, 32), nil
159 } else {
160 return strconv.FormatFloat(f, 'g', -1, 64), nil
161 }
162 }
163 case protoreflect.StringKind:
164
165 return v.String(), nil
166 case protoreflect.BytesKind:
167 if s, ok := marshalBytes(v.Bytes()); ok {
168 return s, nil
169 }
170 }
171 return "", errors.New("could not format value for %v: %v", k, v)
172 }
173
174
175 func unmarshalBytes(s string) ([]byte, bool) {
176
177
178 v, err := ptext.UnmarshalString(`"` + s + `"`)
179 if err != nil {
180 return nil, false
181 }
182 return []byte(v), true
183 }
184
185
186
187
188 func marshalBytes(b []byte) (string, bool) {
189 var s []byte
190 for _, c := range b {
191 switch c {
192 case '\n':
193 s = append(s, `\n`...)
194 case '\r':
195 s = append(s, `\r`...)
196 case '\t':
197 s = append(s, `\t`...)
198 case '"':
199 s = append(s, `\"`...)
200 case '\'':
201 s = append(s, `\'`...)
202 case '\\':
203 s = append(s, `\\`...)
204 default:
205 if printableASCII := c >= 0x20 && c <= 0x7e; printableASCII {
206 s = append(s, c)
207 } else {
208 s = append(s, fmt.Sprintf(`\%03o`, c)...)
209 }
210 }
211 }
212 return string(s), true
213 }
214
View as plain text