rlpstruct.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. // Copyright 2022 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. // Package rlpstruct implements struct processing for RLP encoding/decoding.
  17. //
  18. // In particular, this package handles all rules around field filtering,
  19. // struct tags and nil value determination.
  20. package rlpstruct
  21. import (
  22. "fmt"
  23. "reflect"
  24. "strings"
  25. )
  26. // Field represents a struct field.
  27. type Field struct {
  28. Name string
  29. Index int
  30. Exported bool
  31. Type Type
  32. Tag string
  33. }
  34. // Type represents the attributes of a Go type.
  35. type Type struct {
  36. Name string
  37. Kind reflect.Kind
  38. IsEncoder bool // whether type implements rlp.Encoder
  39. IsDecoder bool // whether type implements rlp.Decoder
  40. Elem *Type // non-nil for Kind values of Ptr, Slice, Array
  41. }
  42. // defaultNilValue determines whether a nil pointer to t encodes/decodes
  43. // as an empty string or empty list.
  44. func (t Type) DefaultNilValue() NilKind {
  45. k := t.Kind
  46. if isUint(k) || k == reflect.String || k == reflect.Bool || isByteArray(t) {
  47. return NilKindString
  48. }
  49. return NilKindList
  50. }
  51. // NilKind is the RLP value encoded in place of nil pointers.
  52. type NilKind uint8
  53. const (
  54. NilKindString NilKind = 0x80
  55. NilKindList NilKind = 0xC0
  56. )
  57. // Tags represents struct tags.
  58. type Tags struct {
  59. // rlp:"nil" controls whether empty input results in a nil pointer.
  60. // nilKind is the kind of empty value allowed for the field.
  61. NilKind NilKind
  62. NilOK bool
  63. // rlp:"optional" allows for a field to be missing in the input list.
  64. // If this is set, all subsequent fields must also be optional.
  65. Optional bool
  66. // rlp:"tail" controls whether this field swallows additional list elements. It can
  67. // only be set for the last field, which must be of slice type.
  68. Tail bool
  69. // rlp:"-" ignores fields.
  70. Ignored bool
  71. }
  72. // TagError is raised for invalid struct tags.
  73. type TagError struct {
  74. StructType string
  75. // These are set by this package.
  76. Field string
  77. Tag string
  78. Err string
  79. }
  80. func (e TagError) Error() string {
  81. field := "field " + e.Field
  82. if e.StructType != "" {
  83. field = e.StructType + "." + e.Field
  84. }
  85. return fmt.Sprintf("rlp: invalid struct tag %q for %s (%s)", e.Tag, field, e.Err)
  86. }
  87. // ProcessFields filters the given struct fields, returning only fields
  88. // that should be considered for encoding/decoding.
  89. func ProcessFields(allFields []Field) ([]Field, []Tags, error) {
  90. lastPublic := lastPublicField(allFields)
  91. // Gather all exported fields and their tags.
  92. var fields []Field
  93. var tags []Tags
  94. for _, field := range allFields {
  95. if !field.Exported {
  96. continue
  97. }
  98. ts, err := parseTag(field, lastPublic)
  99. if err != nil {
  100. return nil, nil, err
  101. }
  102. if ts.Ignored {
  103. continue
  104. }
  105. fields = append(fields, field)
  106. tags = append(tags, ts)
  107. }
  108. // Verify optional field consistency. If any optional field exists,
  109. // all fields after it must also be optional. Note: optional + tail
  110. // is supported.
  111. var anyOptional bool
  112. var firstOptionalName string
  113. for i, ts := range tags {
  114. name := fields[i].Name
  115. if ts.Optional || ts.Tail {
  116. if !anyOptional {
  117. firstOptionalName = name
  118. }
  119. anyOptional = true
  120. } else {
  121. if anyOptional {
  122. msg := fmt.Sprintf("must be optional because preceding field %q is optional", firstOptionalName)
  123. return nil, nil, TagError{Field: name, Err: msg}
  124. }
  125. }
  126. }
  127. return fields, tags, nil
  128. }
  129. func parseTag(field Field, lastPublic int) (Tags, error) {
  130. name := field.Name
  131. tag := reflect.StructTag(field.Tag)
  132. var ts Tags
  133. for _, t := range strings.Split(tag.Get("rlp"), ",") {
  134. switch t = strings.TrimSpace(t); t {
  135. case "":
  136. // empty tag is allowed for some reason
  137. case "-":
  138. ts.Ignored = true
  139. case "nil", "nilString", "nilList":
  140. ts.NilOK = true
  141. if field.Type.Kind != reflect.Ptr {
  142. return ts, TagError{Field: name, Tag: t, Err: "field is not a pointer"}
  143. }
  144. switch t {
  145. case "nil":
  146. ts.NilKind = field.Type.Elem.DefaultNilValue()
  147. case "nilString":
  148. ts.NilKind = NilKindString
  149. case "nilList":
  150. ts.NilKind = NilKindList
  151. }
  152. case "optional":
  153. ts.Optional = true
  154. if ts.Tail {
  155. return ts, TagError{Field: name, Tag: t, Err: `also has "tail" tag`}
  156. }
  157. case "tail":
  158. ts.Tail = true
  159. if field.Index != lastPublic {
  160. return ts, TagError{Field: name, Tag: t, Err: "must be on last field"}
  161. }
  162. if ts.Optional {
  163. return ts, TagError{Field: name, Tag: t, Err: `also has "optional" tag`}
  164. }
  165. if field.Type.Kind != reflect.Slice {
  166. return ts, TagError{Field: name, Tag: t, Err: "field type is not slice"}
  167. }
  168. default:
  169. return ts, TagError{Field: name, Tag: t, Err: "unknown tag"}
  170. }
  171. }
  172. return ts, nil
  173. }
  174. func lastPublicField(fields []Field) int {
  175. last := 0
  176. for _, f := range fields {
  177. if f.Exported {
  178. last = f.Index
  179. }
  180. }
  181. return last
  182. }
  183. func isUint(k reflect.Kind) bool {
  184. return k >= reflect.Uint && k <= reflect.Uintptr
  185. }
  186. func isByte(typ Type) bool {
  187. return typ.Kind == reflect.Uint8 && !typ.IsEncoder
  188. }
  189. func isByteArray(typ Type) bool {
  190. return (typ.Kind == reflect.Slice || typ.Kind == reflect.Array) && isByte(*typ.Elem)
  191. }