You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

214 lines
6.4 KiB

  1. // Copyright 2018 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package defval marshals and unmarshals textual forms of default values.
  5. //
  6. // This package handles both the form historically used in Go struct field tags
  7. // and also the form used by google.protobuf.FieldDescriptorProto.default_value
  8. // since they differ in superficial ways.
  9. package defval
  10. import (
  11. "fmt"
  12. "math"
  13. "strconv"
  14. ptext "google.golang.org/protobuf/internal/encoding/text"
  15. "google.golang.org/protobuf/internal/errors"
  16. "google.golang.org/protobuf/reflect/protoreflect"
  17. )
  18. // Format is the serialization format used to represent the default value.
  19. type Format int
  20. const (
  21. _ Format = iota
  22. // Descriptor uses the serialization format that protoc uses with the
  23. // google.protobuf.FieldDescriptorProto.default_value field.
  24. Descriptor
  25. // GoTag uses the historical serialization format in Go struct field tags.
  26. GoTag
  27. )
  28. // Unmarshal deserializes the default string s according to the given kind k.
  29. // When k is an enum, a list of enum value descriptors must be provided.
  30. func Unmarshal(s string, k protoreflect.Kind, evs protoreflect.EnumValueDescriptors, f Format) (protoreflect.Value, protoreflect.EnumValueDescriptor, error) {
  31. switch k {
  32. case protoreflect.BoolKind:
  33. if f == GoTag {
  34. switch s {
  35. case "1":
  36. return protoreflect.ValueOfBool(true), nil, nil
  37. case "0":
  38. return protoreflect.ValueOfBool(false), nil, nil
  39. }
  40. } else {
  41. switch s {
  42. case "true":
  43. return protoreflect.ValueOfBool(true), nil, nil
  44. case "false":
  45. return protoreflect.ValueOfBool(false), nil, nil
  46. }
  47. }
  48. case protoreflect.EnumKind:
  49. if f == GoTag {
  50. // Go tags use the numeric form of the enum value.
  51. if n, err := strconv.ParseInt(s, 10, 32); err == nil {
  52. if ev := evs.ByNumber(protoreflect.EnumNumber(n)); ev != nil {
  53. return protoreflect.ValueOfEnum(ev.Number()), ev, nil
  54. }
  55. }
  56. } else {
  57. // Descriptor default_value use the enum identifier.
  58. ev := evs.ByName(protoreflect.Name(s))
  59. if ev != nil {
  60. return protoreflect.ValueOfEnum(ev.Number()), ev, nil
  61. }
  62. }
  63. case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
  64. if v, err := strconv.ParseInt(s, 10, 32); err == nil {
  65. return protoreflect.ValueOfInt32(int32(v)), nil, nil
  66. }
  67. case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
  68. if v, err := strconv.ParseInt(s, 10, 64); err == nil {
  69. return protoreflect.ValueOfInt64(int64(v)), nil, nil
  70. }
  71. case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
  72. if v, err := strconv.ParseUint(s, 10, 32); err == nil {
  73. return protoreflect.ValueOfUint32(uint32(v)), nil, nil
  74. }
  75. case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
  76. if v, err := strconv.ParseUint(s, 10, 64); err == nil {
  77. return protoreflect.ValueOfUint64(uint64(v)), nil, nil
  78. }
  79. case protoreflect.FloatKind, protoreflect.DoubleKind:
  80. var v float64
  81. var err error
  82. switch s {
  83. case "-inf":
  84. v = math.Inf(-1)
  85. case "inf":
  86. v = math.Inf(+1)
  87. case "nan":
  88. v = math.NaN()
  89. default:
  90. v, err = strconv.ParseFloat(s, 64)
  91. }
  92. if err == nil {
  93. if k == protoreflect.FloatKind {
  94. return protoreflect.ValueOfFloat32(float32(v)), nil, nil
  95. } else {
  96. return protoreflect.ValueOfFloat64(float64(v)), nil, nil
  97. }
  98. }
  99. case protoreflect.StringKind:
  100. // String values are already unescaped and can be used as is.
  101. return protoreflect.ValueOfString(s), nil, nil
  102. case protoreflect.BytesKind:
  103. if b, ok := unmarshalBytes(s); ok {
  104. return protoreflect.ValueOfBytes(b), nil, nil
  105. }
  106. }
  107. return protoreflect.Value{}, nil, errors.New("could not parse value for %v: %q", k, s)
  108. }
  109. // Marshal serializes v as the default string according to the given kind k.
  110. // When specifying the Descriptor format for an enum kind, the associated
  111. // enum value descriptor must be provided.
  112. func Marshal(v protoreflect.Value, ev protoreflect.EnumValueDescriptor, k protoreflect.Kind, f Format) (string, error) {
  113. switch k {
  114. case protoreflect.BoolKind:
  115. if f == GoTag {
  116. if v.Bool() {
  117. return "1", nil
  118. } else {
  119. return "0", nil
  120. }
  121. } else {
  122. if v.Bool() {
  123. return "true", nil
  124. } else {
  125. return "false", nil
  126. }
  127. }
  128. case protoreflect.EnumKind:
  129. if f == GoTag {
  130. return strconv.FormatInt(int64(v.Enum()), 10), nil
  131. } else {
  132. return string(ev.Name()), nil
  133. }
  134. case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
  135. return strconv.FormatInt(v.Int(), 10), nil
  136. case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
  137. return strconv.FormatUint(v.Uint(), 10), nil
  138. case protoreflect.FloatKind, protoreflect.DoubleKind:
  139. f := v.Float()
  140. switch {
  141. case math.IsInf(f, -1):
  142. return "-inf", nil
  143. case math.IsInf(f, +1):
  144. return "inf", nil
  145. case math.IsNaN(f):
  146. return "nan", nil
  147. default:
  148. if k == protoreflect.FloatKind {
  149. return strconv.FormatFloat(f, 'g', -1, 32), nil
  150. } else {
  151. return strconv.FormatFloat(f, 'g', -1, 64), nil
  152. }
  153. }
  154. case protoreflect.StringKind:
  155. // String values are serialized as is without any escaping.
  156. return v.String(), nil
  157. case protoreflect.BytesKind:
  158. if s, ok := marshalBytes(v.Bytes()); ok {
  159. return s, nil
  160. }
  161. }
  162. return "", errors.New("could not format value for %v: %v", k, v)
  163. }
  164. // unmarshalBytes deserializes bytes by applying C unescaping.
  165. func unmarshalBytes(s string) ([]byte, bool) {
  166. // Bytes values use the same escaping as the text format,
  167. // however they lack the surrounding double quotes.
  168. v, err := ptext.UnmarshalString(`"` + s + `"`)
  169. if err != nil {
  170. return nil, false
  171. }
  172. return []byte(v), true
  173. }
  174. // marshalBytes serializes bytes by using C escaping.
  175. // To match the exact output of protoc, this is identical to the
  176. // CEscape function in strutil.cc of the protoc source code.
  177. func marshalBytes(b []byte) (string, bool) {
  178. var s []byte
  179. for _, c := range b {
  180. switch c {
  181. case '\n':
  182. s = append(s, `\n`...)
  183. case '\r':
  184. s = append(s, `\r`...)
  185. case '\t':
  186. s = append(s, `\t`...)
  187. case '"':
  188. s = append(s, `\"`...)
  189. case '\'':
  190. s = append(s, `\'`...)
  191. case '\\':
  192. s = append(s, `\\`...)
  193. default:
  194. if printableASCII := c >= 0x20 && c <= 0x7e; printableASCII {
  195. s = append(s, c)
  196. } else {
  197. s = append(s, fmt.Sprintf(`\%03o`, c)...)
  198. }
  199. }
  200. }
  201. return string(s), true
  202. }