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.
 
 
 

227 lines
5.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 bitfield converts annotated structs into integer values.
  5. //
  6. // Any field that is marked with a bitfield tag is compacted. The tag value has
  7. // two parts. The part before the comma determines the method name for a
  8. // generated type. If left blank the name of the field is used.
  9. // The part after the comma determines the number of bits to use for the
  10. // representation.
  11. package bitfield
  12. import (
  13. "bytes"
  14. "fmt"
  15. "io"
  16. "reflect"
  17. "strconv"
  18. "strings"
  19. )
  20. // Config determines settings for packing and generation. If a Config is used,
  21. // the same Config should be used for packing and generation.
  22. type Config struct {
  23. // NumBits fixes the maximum allowed bits for the integer representation.
  24. // If NumBits is not 8, 16, 32, or 64, the actual underlying integer size
  25. // will be the next largest available.
  26. NumBits uint
  27. // If Package is set, code generation will write a package clause.
  28. Package string
  29. // TypeName is the name for the generated type. By default it is the name
  30. // of the type of the value passed to Gen.
  31. TypeName string
  32. }
  33. var nullConfig = &Config{}
  34. // Pack packs annotated bit ranges of struct x in an integer.
  35. //
  36. // Only fields that have a "bitfield" tag are compacted.
  37. func Pack(x interface{}, c *Config) (packed uint64, err error) {
  38. packed, _, err = pack(x, c)
  39. return
  40. }
  41. func pack(x interface{}, c *Config) (packed uint64, nBit uint, err error) {
  42. if c == nil {
  43. c = nullConfig
  44. }
  45. nBits := c.NumBits
  46. v := reflect.ValueOf(x)
  47. v = reflect.Indirect(v)
  48. t := v.Type()
  49. pos := 64 - nBits
  50. if nBits == 0 {
  51. pos = 0
  52. }
  53. for i := 0; i < v.NumField(); i++ {
  54. v := v.Field(i)
  55. field := t.Field(i)
  56. f, err := parseField(field)
  57. if err != nil {
  58. return 0, 0, err
  59. }
  60. if f.nBits == 0 {
  61. continue
  62. }
  63. value := uint64(0)
  64. switch v.Kind() {
  65. case reflect.Bool:
  66. if v.Bool() {
  67. value = 1
  68. }
  69. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  70. value = v.Uint()
  71. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  72. x := v.Int()
  73. if x < 0 {
  74. return 0, 0, fmt.Errorf("bitfield: negative value for field %q not allowed", field.Name)
  75. }
  76. value = uint64(x)
  77. }
  78. if value > (1<<f.nBits)-1 {
  79. return 0, 0, fmt.Errorf("bitfield: value %#x of field %q does not fit in %d bits", value, field.Name, f.nBits)
  80. }
  81. shift := 64 - pos - f.nBits
  82. if pos += f.nBits; pos > 64 {
  83. return 0, 0, fmt.Errorf("bitfield: no more bits left for field %q", field.Name)
  84. }
  85. packed |= value << shift
  86. }
  87. if nBits == 0 {
  88. nBits = posToBits(pos)
  89. packed >>= (64 - nBits)
  90. }
  91. return packed, nBits, nil
  92. }
  93. type field struct {
  94. name string
  95. value uint64
  96. nBits uint
  97. }
  98. // parseField parses a tag of the form [<name>][:<nBits>][,<pos>[..<end>]]
  99. func parseField(field reflect.StructField) (f field, err error) {
  100. s, ok := field.Tag.Lookup("bitfield")
  101. if !ok {
  102. return f, nil
  103. }
  104. switch field.Type.Kind() {
  105. case reflect.Bool:
  106. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  107. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  108. default:
  109. return f, fmt.Errorf("bitfield: field %q is not an integer or bool type", field.Name)
  110. }
  111. bits := s
  112. f.name = ""
  113. if i := strings.IndexByte(s, ','); i >= 0 {
  114. bits = s[:i]
  115. f.name = s[i+1:]
  116. }
  117. if bits != "" {
  118. nBits, err := strconv.ParseUint(bits, 10, 8)
  119. if err != nil {
  120. return f, fmt.Errorf("bitfield: invalid bit size for field %q: %v", field.Name, err)
  121. }
  122. f.nBits = uint(nBits)
  123. }
  124. if f.nBits == 0 {
  125. if field.Type.Kind() == reflect.Bool {
  126. f.nBits = 1
  127. } else {
  128. f.nBits = uint(field.Type.Bits())
  129. }
  130. }
  131. if f.name == "" {
  132. f.name = field.Name
  133. }
  134. return f, err
  135. }
  136. func posToBits(pos uint) (bits uint) {
  137. switch {
  138. case pos <= 8:
  139. bits = 8
  140. case pos <= 16:
  141. bits = 16
  142. case pos <= 32:
  143. bits = 32
  144. case pos <= 64:
  145. bits = 64
  146. default:
  147. panic("unreachable")
  148. }
  149. return bits
  150. }
  151. // Gen generates code for unpacking integers created with Pack.
  152. func Gen(w io.Writer, x interface{}, c *Config) error {
  153. if c == nil {
  154. c = nullConfig
  155. }
  156. _, nBits, err := pack(x, c)
  157. if err != nil {
  158. return err
  159. }
  160. t := reflect.TypeOf(x)
  161. if t.Kind() == reflect.Ptr {
  162. t = t.Elem()
  163. }
  164. if c.TypeName == "" {
  165. c.TypeName = t.Name()
  166. }
  167. firstChar := []rune(c.TypeName)[0]
  168. buf := &bytes.Buffer{}
  169. print := func(w io.Writer, format string, args ...interface{}) {
  170. if _, e := fmt.Fprintf(w, format+"\n", args...); e != nil && err == nil {
  171. err = fmt.Errorf("bitfield: write failed: %v", err)
  172. }
  173. }
  174. pos := uint(0)
  175. for i := 0; i < t.NumField(); i++ {
  176. field := t.Field(i)
  177. f, _ := parseField(field)
  178. if f.nBits == 0 {
  179. continue
  180. }
  181. shift := nBits - pos - f.nBits
  182. pos += f.nBits
  183. retType := field.Type.Name()
  184. print(buf, "\nfunc (%c %s) %s() %s {", firstChar, c.TypeName, f.name, retType)
  185. if field.Type.Kind() == reflect.Bool {
  186. print(buf, "\tconst bit = 1 << %d", shift)
  187. print(buf, "\treturn %c&bit == bit", firstChar)
  188. } else {
  189. print(buf, "\treturn %s((%c >> %d) & %#x)", retType, firstChar, shift, (1<<f.nBits)-1)
  190. }
  191. print(buf, "}")
  192. }
  193. if c.Package != "" {
  194. print(w, "// Code generated by golang.org/x/text/internal/gen/bitfield. DO NOT EDIT.\n")
  195. print(w, "package %s\n", c.Package)
  196. }
  197. bits := posToBits(pos)
  198. print(w, "type %s uint%d", c.TypeName, bits)
  199. if _, err := io.Copy(w, buf); err != nil {
  200. return fmt.Errorf("bitfield: write failed: %v", err)
  201. }
  202. return nil
  203. }