default.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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. errors "google.golang.org/protobuf/internal/errors"
  16. pref "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 using the Descriptor format on an enum kind, a Value of type string
  30. // representing the enum identifier is returned. It is the caller's
  31. // responsibility to verify that the identifier is valid.
  32. func Unmarshal(s string, k pref.Kind, f Format) (pref.Value, error) {
  33. switch k {
  34. case pref.BoolKind:
  35. if f == GoTag {
  36. switch s {
  37. case "1":
  38. return pref.ValueOf(true), nil
  39. case "0":
  40. return pref.ValueOf(false), nil
  41. }
  42. } else {
  43. switch s {
  44. case "true":
  45. return pref.ValueOf(true), nil
  46. case "false":
  47. return pref.ValueOf(false), nil
  48. }
  49. }
  50. case pref.EnumKind:
  51. if f == GoTag {
  52. // Go tags used the numeric form of the enum value.
  53. if n, err := strconv.ParseInt(s, 10, 32); err == nil {
  54. return pref.ValueOf(pref.EnumNumber(n)), nil
  55. }
  56. } else {
  57. // Descriptor default_value used the enum identifier.
  58. if pref.Name(s).IsValid() {
  59. return pref.ValueOf(s), nil
  60. }
  61. }
  62. case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
  63. if v, err := strconv.ParseInt(s, 10, 32); err == nil {
  64. return pref.ValueOf(int32(v)), nil
  65. }
  66. case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
  67. if v, err := strconv.ParseInt(s, 10, 64); err == nil {
  68. return pref.ValueOf(int64(v)), nil
  69. }
  70. case pref.Uint32Kind, pref.Fixed32Kind:
  71. if v, err := strconv.ParseUint(s, 10, 32); err == nil {
  72. return pref.ValueOf(uint32(v)), nil
  73. }
  74. case pref.Uint64Kind, pref.Fixed64Kind:
  75. if v, err := strconv.ParseUint(s, 10, 64); err == nil {
  76. return pref.ValueOf(uint64(v)), nil
  77. }
  78. case pref.FloatKind, pref.DoubleKind:
  79. var v float64
  80. var err error
  81. switch s {
  82. case "-inf":
  83. v = math.Inf(-1)
  84. case "inf":
  85. v = math.Inf(+1)
  86. case "nan":
  87. v = math.NaN()
  88. default:
  89. v, err = strconv.ParseFloat(s, 64)
  90. }
  91. if err == nil {
  92. if k == pref.FloatKind {
  93. return pref.ValueOf(float32(v)), nil
  94. } else {
  95. return pref.ValueOf(float64(v)), nil
  96. }
  97. }
  98. case pref.StringKind:
  99. // String values are already unescaped and can be used as is.
  100. return pref.ValueOf(s), nil
  101. case pref.BytesKind:
  102. if b, ok := unmarshalBytes(s); ok {
  103. return pref.ValueOf(b), nil
  104. }
  105. }
  106. return pref.Value{}, errors.New("invalid default value for %v: %q", k, s)
  107. }
  108. // Marshal serializes v as the default string according to the given kind k.
  109. // Enums are serialized in numeric form regardless of format chosen.
  110. func Marshal(v pref.Value, k pref.Kind, f Format) (string, error) {
  111. switch k {
  112. case pref.BoolKind:
  113. if f == GoTag {
  114. if v.Bool() {
  115. return "1", nil
  116. } else {
  117. return "0", nil
  118. }
  119. } else {
  120. if v.Bool() {
  121. return "true", nil
  122. } else {
  123. return "false", nil
  124. }
  125. }
  126. case pref.EnumKind:
  127. return strconv.FormatInt(int64(v.Enum()), 10), nil
  128. case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind, pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
  129. return strconv.FormatInt(v.Int(), 10), nil
  130. case pref.Uint32Kind, pref.Fixed32Kind, pref.Uint64Kind, pref.Fixed64Kind:
  131. return strconv.FormatUint(v.Uint(), 10), nil
  132. case pref.FloatKind, pref.DoubleKind:
  133. f := v.Float()
  134. switch {
  135. case math.IsInf(f, -1):
  136. return "-inf", nil
  137. case math.IsInf(f, +1):
  138. return "inf", nil
  139. case math.IsNaN(f):
  140. return "nan", nil
  141. default:
  142. if k == pref.FloatKind {
  143. return strconv.FormatFloat(f, 'g', -1, 32), nil
  144. } else {
  145. return strconv.FormatFloat(f, 'g', -1, 64), nil
  146. }
  147. }
  148. case pref.StringKind:
  149. // String values are serialized as is without any escaping.
  150. return v.String(), nil
  151. case pref.BytesKind:
  152. if s, ok := marshalBytes(v.Bytes()); ok {
  153. return s, nil
  154. }
  155. }
  156. return "", errors.New("invalid default value for %v: %v", k, v)
  157. }
  158. // unmarshalBytes deserializes bytes by applying C unescaping.
  159. func unmarshalBytes(s string) ([]byte, bool) {
  160. // Bytes values use the same escaping as the text format,
  161. // however they lack the surrounding double quotes.
  162. // TODO: Export unmarshalString in the text package to avoid this hack.
  163. v, err := ptext.Unmarshal([]byte(`["` + s + `"]:0`))
  164. if err == nil && len(v.Message()) == 1 {
  165. s := v.Message()[0][0].String()
  166. return []byte(s), true
  167. }
  168. return nil, false
  169. }
  170. // marshalBytes serializes bytes by using C escaping.
  171. // To match the exact output of protoc, this is identical to the
  172. // CEscape function in strutil.cc of the protoc source code.
  173. func marshalBytes(b []byte) (string, bool) {
  174. var s []byte
  175. for _, c := range b {
  176. switch c {
  177. case '\n':
  178. s = append(s, `\n`...)
  179. case '\r':
  180. s = append(s, `\r`...)
  181. case '\t':
  182. s = append(s, `\t`...)
  183. case '"':
  184. s = append(s, `\"`...)
  185. case '\'':
  186. s = append(s, `\'`...)
  187. case '\\':
  188. s = append(s, `\\`...)
  189. default:
  190. if printableASCII := c >= 0x20 && c <= 0x7e; printableASCII {
  191. s = append(s, c)
  192. } else {
  193. s = append(s, fmt.Sprintf(`\%03o`, c)...)
  194. }
  195. }
  196. }
  197. return string(s), true
  198. }