summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/text/internal/gen/bitfield
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/text/internal/gen/bitfield')
-rw-r--r--vendor/golang.org/x/text/internal/gen/bitfield/bitfield.go226
1 files changed, 226 insertions, 0 deletions
diff --git a/vendor/golang.org/x/text/internal/gen/bitfield/bitfield.go b/vendor/golang.org/x/text/internal/gen/bitfield/bitfield.go
new file mode 100644
index 00000000..a8d0a48d
--- /dev/null
+++ b/vendor/golang.org/x/text/internal/gen/bitfield/bitfield.go
@@ -0,0 +1,226 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bitfield converts annotated structs into integer values.
+//
+// Any field that is marked with a bitfield tag is compacted. The tag value has
+// two parts. The part before the comma determines the method name for a
+// generated type. If left blank the name of the field is used.
+// The part after the comma determines the number of bits to use for the
+// representation.
+package bitfield
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+// Config determines settings for packing and generation. If a Config is used,
+// the same Config should be used for packing and generation.
+type Config struct {
+ // NumBits fixes the maximum allowed bits for the integer representation.
+ // If NumBits is not 8, 16, 32, or 64, the actual underlying integer size
+ // will be the next largest available.
+ NumBits uint
+
+ // If Package is set, code generation will write a package clause.
+ Package string
+
+ // TypeName is the name for the generated type. By default it is the name
+ // of the type of the value passed to Gen.
+ TypeName string
+}
+
+var nullConfig = &Config{}
+
+// Pack packs annotated bit ranges of struct x in an integer.
+//
+// Only fields that have a "bitfield" tag are compacted.
+func Pack(x interface{}, c *Config) (packed uint64, err error) {
+ packed, _, err = pack(x, c)
+ return
+}
+
+func pack(x interface{}, c *Config) (packed uint64, nBit uint, err error) {
+ if c == nil {
+ c = nullConfig
+ }
+ nBits := c.NumBits
+ v := reflect.ValueOf(x)
+ v = reflect.Indirect(v)
+ t := v.Type()
+ pos := 64 - nBits
+ if nBits == 0 {
+ pos = 0
+ }
+ for i := 0; i < v.NumField(); i++ {
+ v := v.Field(i)
+ field := t.Field(i)
+ f, err := parseField(field)
+
+ if err != nil {
+ return 0, 0, err
+ }
+ if f.nBits == 0 {
+ continue
+ }
+ value := uint64(0)
+ switch v.Kind() {
+ case reflect.Bool:
+ if v.Bool() {
+ value = 1
+ }
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ value = v.Uint()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ x := v.Int()
+ if x < 0 {
+ return 0, 0, fmt.Errorf("bitfield: negative value for field %q not allowed", field.Name)
+ }
+ value = uint64(x)
+ }
+ if value > (1<<f.nBits)-1 {
+ return 0, 0, fmt.Errorf("bitfield: value %#x of field %q does not fit in %d bits", value, field.Name, f.nBits)
+ }
+ shift := 64 - pos - f.nBits
+ if pos += f.nBits; pos > 64 {
+ return 0, 0, fmt.Errorf("bitfield: no more bits left for field %q", field.Name)
+ }
+ packed |= value << shift
+ }
+ if nBits == 0 {
+ nBits = posToBits(pos)
+ packed >>= (64 - nBits)
+ }
+ return packed, nBits, nil
+}
+
+type field struct {
+ name string
+ value uint64
+ nBits uint
+}
+
+// parseField parses a tag of the form [<name>][:<nBits>][,<pos>[..<end>]]
+func parseField(field reflect.StructField) (f field, err error) {
+ s, ok := field.Tag.Lookup("bitfield")
+ if !ok {
+ return f, nil
+ }
+ switch field.Type.Kind() {
+ case reflect.Bool:
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ default:
+ return f, fmt.Errorf("bitfield: field %q is not an integer or bool type", field.Name)
+ }
+ bits := s
+ f.name = ""
+
+ if i := strings.IndexByte(s, ','); i >= 0 {
+ bits = s[:i]
+ f.name = s[i+1:]
+ }
+ if bits != "" {
+ nBits, err := strconv.ParseUint(bits, 10, 8)
+ if err != nil {
+ return f, fmt.Errorf("bitfield: invalid bit size for field %q: %v", field.Name, err)
+ }
+ f.nBits = uint(nBits)
+ }
+ if f.nBits == 0 {
+ if field.Type.Kind() == reflect.Bool {
+ f.nBits = 1
+ } else {
+ f.nBits = uint(field.Type.Bits())
+ }
+ }
+ if f.name == "" {
+ f.name = field.Name
+ }
+ return f, err
+}
+
+func posToBits(pos uint) (bits uint) {
+ switch {
+ case pos <= 8:
+ bits = 8
+ case pos <= 16:
+ bits = 16
+ case pos <= 32:
+ bits = 32
+ case pos <= 64:
+ bits = 64
+ default:
+ panic("unreachable")
+ }
+ return bits
+}
+
+// Gen generates code for unpacking integers created with Pack.
+func Gen(w io.Writer, x interface{}, c *Config) error {
+ if c == nil {
+ c = nullConfig
+ }
+ _, nBits, err := pack(x, c)
+ if err != nil {
+ return err
+ }
+
+ t := reflect.TypeOf(x)
+ if t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ }
+ if c.TypeName == "" {
+ c.TypeName = t.Name()
+ }
+ firstChar := []rune(c.TypeName)[0]
+
+ buf := &bytes.Buffer{}
+
+ print := func(w io.Writer, format string, args ...interface{}) {
+ if _, e := fmt.Fprintf(w, format+"\n", args...); e != nil && err == nil {
+ err = fmt.Errorf("bitfield: write failed: %v", err)
+ }
+ }
+
+ pos := uint(0)
+ for i := 0; i < t.NumField(); i++ {
+ field := t.Field(i)
+ f, _ := parseField(field)
+ if f.nBits == 0 {
+ continue
+ }
+ shift := nBits - pos - f.nBits
+ pos += f.nBits
+
+ retType := field.Type.Name()
+ print(buf, "\nfunc (%c %s) %s() %s {", firstChar, c.TypeName, f.name, retType)
+ if field.Type.Kind() == reflect.Bool {
+ print(buf, "\tconst bit = 1 << %d", shift)
+ print(buf, "\treturn %c&bit == bit", firstChar)
+ } else {
+ print(buf, "\treturn %s((%c >> %d) & %#x)", retType, firstChar, shift, (1<<f.nBits)-1)
+ }
+ print(buf, "}")
+ }
+
+ if c.Package != "" {
+ print(w, "// Code generated by golang.org/x/text/internal/gen/bitfield. DO NOT EDIT.\n")
+ print(w, "package %s\n", c.Package)
+ }
+
+ bits := posToBits(pos)
+
+ print(w, "type %s uint%d", c.TypeName, bits)
+
+ if _, err := io.Copy(w, buf); err != nil {
+ return fmt.Errorf("bitfield: write failed: %v", err)
+ }
+ return nil
+}