...

Source file src/golang.org/x/text/internal/gen/bitfield/bitfield.go

Documentation: golang.org/x/text/internal/gen/bitfield

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

View as plain text