pax_global_header00006660000000000000000000000064141223174500014511gustar00rootroot0000000000000052 comment=d663d39234ffa02aa3d9d4deb33e455bc2072950 golang-github-go-restruct-restruct-1.2.0-alpha/000077500000000000000000000000001412231745000214505ustar00rootroot00000000000000golang-github-go-restruct-restruct-1.2.0-alpha/.gitignore000066400000000000000000000000151412231745000234340ustar00rootroot00000000000000coverage.out golang-github-go-restruct-restruct-1.2.0-alpha/.travis.yml000066400000000000000000000006061412231745000235630ustar00rootroot00000000000000language: go go: - '1.7' - '1.11' - '1.12' - '1.13' - tip script: - go test -coverprofile=coverage.txt -covermode=atomic - "if [[ $TRAVIS_GO_VERSION == 1.13 ]]; then bash <(curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh) -b $(go env GOPATH)/bin v1.20.0 && golangci-lint run; fi" after_success: - bash <(curl -s https://codecov.io/bash) golang-github-go-restruct-restruct-1.2.0-alpha/CONTRIBUTORS.md000066400000000000000000000010171412231745000237260ustar00rootroot00000000000000restruct is an open source project that anyone can contribute to. This file contains a list of all contributors up to this point. This list is obtained by running `git shortlog -s` and is listed in alphabetical order. If this file falls out of date and is missing a name, or an entry should be changed, please [file an issue](https://github.com/go-restruct/restruct/issues/new). * [Dave Cheney](https://github.com/davecheney) * [John Chadwick](https://github.com/jchv) * [jlojosnegros](https://github.com/jlojosnegros) golang-github-go-restruct-restruct-1.2.0-alpha/LICENSE.md000066400000000000000000000014021412231745000230510ustar00rootroot00000000000000ISC License Copyright © 2015, John Chadwick Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. golang-github-go-restruct-restruct-1.2.0-alpha/README.md000066400000000000000000000034701412231745000227330ustar00rootroot00000000000000# restruct [![Build Status](https://travis-ci.org/go-restruct/restruct.svg)](https://travis-ci.org/go-restruct/restruct) [![codecov.io](http://codecov.io/github/go-restruct/restruct/coverage.svg?branch=master)](http://codecov.io/github/go-restruct/restruct?branch=master) [![godoc.org](http://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](https://godoc.org/github.com/go-restruct/restruct) [![Go Report Card](https://goreportcard.com/badge/github.com/go-restruct/restruct)](https://goreportcard.com/report/github.com/go-restruct/restruct) `restruct` is a library for reading and writing binary data in Go. Similar to lunixbochs `struc` and `encoding/binary`, this library reads data based on the layout of structures and, like `struc`, based on what is contained in struct tags. To install Restruct, use the following command: ``` go get github.com/go-restruct/restruct ``` `restruct` aims to provide a clean, flexible, robust implementation of struct packing. In the future, through fast-path optimizations and code generation, it also aims to be quick, but it is currently very slow. `restruct` currently requires Go 1.7+. ## Status * As of writing, coverage is hovering around 95%, but more thorough testing is always useful and desirable. * Unpacking and packing are fully functional. * More optimizations are probably possible. ## Example ```go package main import ( "encoding/binary" "io/ioutil" "os" "github.com/go-restruct/restruct" ) type Record struct { Message string `struct:"[128]byte"` } type Container struct { Version int `struct:"int32"` NumRecord int `struct:"int32,sizeof=Records"` Records []Record } func main() { var c Container file, _ := os.Open("records") defer file.Close() data, _ := ioutil.ReadAll(file) restruct.Unpack(data, binary.LittleEndian, &c) } ``` golang-github-go-restruct-restruct-1.2.0-alpha/arrayof.go000066400000000000000000000001661412231745000234450ustar00rootroot00000000000000package restruct // RegisterArrayType is deprecated; it is now a noop. func RegisterArrayType(array interface{}) { } golang-github-go-restruct-restruct-1.2.0-alpha/decoder.go000066400000000000000000000211651412231745000234110ustar00rootroot00000000000000package restruct import ( "encoding/binary" "fmt" "math" "reflect" "strings" ) // Unpacker is a type capable of unpacking a binary representation of itself // into a native representation. The Unpack function is expected to consume // a number of bytes from the buffer, then return a slice of the remaining // bytes in the buffer. You may use a pointer receiver even if the type is // used by value. type Unpacker interface { Unpack(buf []byte, order binary.ByteOrder) ([]byte, error) } type decoder struct { structstack order binary.ByteOrder sfields []field bitCounter uint8 bitSize int } func putBit(buf []byte, bitSize int, bit int, val byte) { bit = bitSize - 1 - bit buf[len(buf)-bit/8-1] |= (val) << (uint(bit) % 8) } func (d *decoder) readBit() byte { value := (d.buf[0] >> uint(7-d.bitCounter)) & 1 d.bitCounter++ if d.bitCounter >= 8 { d.buf = d.buf[1:] d.bitCounter -= 8 } return value } func (d *decoder) readBits(f field, outBuf []byte) { var decodedBits int // Determine encoded size in bits. if d.bitSize == 0 { decodedBits = 8 * len(outBuf) } else { decodedBits = int(d.bitSize) } // Crop output buffer to relevant bytes only. outBuf = outBuf[len(outBuf)-(decodedBits+7)/8:] if d.bitCounter == 0 && decodedBits%8 == 0 { // Fast path: we are fully byte-aligned. copy(outBuf, d.buf) d.buf = d.buf[len(outBuf):] } else { // Slow path: work bit-by-bit. // TODO: This needs to be optimized in a way that can be easily // understood; the previous optimized version was simply too hard to // reason about. for i := 0; i < decodedBits; i++ { putBit(outBuf, decodedBits, i, d.readBit()) } } } func (d *decoder) read8(f field) uint8 { b := make([]byte, 1) d.readBits(f, b) return uint8(b[0]) } func (d *decoder) read16(f field) uint16 { b := make([]byte, 2) d.readBits(f, b) return d.order.Uint16(b) } func (d *decoder) read32(f field) uint32 { b := make([]byte, 4) d.readBits(f, b) return d.order.Uint32(b) } func (d *decoder) read64(f field) uint64 { b := make([]byte, 8) d.readBits(f, b) return d.order.Uint64(b) } func (d *decoder) readS8(f field) int8 { return int8(d.read8(f)) } func (d *decoder) readS16(f field) int16 { return int16(d.read16(f)) } func (d *decoder) readS32(f field) int32 { return int32(d.read32(f)) } func (d *decoder) readS64(f field) int64 { return int64(d.read64(f)) } func (d *decoder) readBytes(count int) []byte { x := d.buf[0:count] d.buf = d.buf[count:] return x } func (d *decoder) skipBits(count int) { d.bitCounter += uint8(count % 8) if d.bitCounter > 8 { d.bitCounter -= 8 count += 8 } d.buf = d.buf[count/8:] } func (d *decoder) skip(f field, v reflect.Value) { d.skipBits(d.fieldbits(f, v)) } func (d *decoder) unpacker(v reflect.Value) (Unpacker, bool) { if s, ok := v.Interface().(Unpacker); ok { return s, true } if !v.CanAddr() { return nil, false } if s, ok := v.Addr().Interface().(Unpacker); ok { return s, true } return nil, false } func (d *decoder) setUint(f field, v reflect.Value, x uint64) { switch v.Kind() { case reflect.Bool: b := x != 0 if f.Flags&InvertedBoolFlag == InvertedBoolFlag { b = !b } v.SetBool(b) default: v.SetUint(x) } } func (d *decoder) setInt(f field, v reflect.Value, x int64) { switch v.Kind() { case reflect.Bool: b := x != 0 if f.Flags&InvertedBoolFlag == InvertedBoolFlag { b = !b } v.SetBool(b) default: v.SetInt(x) } } func (d *decoder) switc(f field, v reflect.Value, on interface{}) { var def *switchcase if v.Kind() != reflect.Struct { panic(fmt.Errorf("%s: only switches on structs are valid", f.Name)) } sfields := cachedFieldsFromStruct(f.BinaryType) l := len(sfields) // Zero out values for decoding. for i := 0; i < l; i++ { v := v.Field(f.Index) v.Set(reflect.Zero(v.Type())) } for i := 0; i < l; i++ { f := sfields[i] v := v.Field(f.Index) if f.Flags&DefaultFlag != 0 { if def != nil { panic(fmt.Errorf("%s: only one default case is allowed", f.Name)) } def = &switchcase{f, v} continue } if f.CaseExpr == nil { panic(fmt.Errorf("%s: only cases are valid inside switches", f.Name)) } if d.evalExpr(f.CaseExpr) == on { d.read(f, v) return } } if def != nil { d.read(def.f, def.v) } } func (d *decoder) read(f field, v reflect.Value) { if f.Flags&RootFlag == RootFlag { d.setancestor(f, v, d.root()) return } if f.Flags&ParentFlag == ParentFlag { for i := 1; i < len(d.stack); i++ { if d.setancestor(f, v, d.ancestor(i)) { break } } return } if f.SwitchExpr != nil { d.switc(f, v, d.evalExpr(f.SwitchExpr)) return } struc := d.ancestor(0) if f.Name != "_" { if s, ok := d.unpacker(v); ok { var err error d.buf, err = s.Unpack(d.buf, d.order) if err != nil { panic(err) } return } } else { d.skipBits(d.fieldbits(f, v)) return } if !d.evalIf(f) { return } sfields := d.sfields order := d.order if f.Order != nil { d.order = f.Order defer func() { d.order = order }() } if f.Skip != 0 { d.skipBits(f.Skip * 8) } d.bitSize = d.evalBits(f) alen := d.evalSize(f) if alen == 0 && f.SIndex != -1 { sv := struc.Field(f.SIndex) l := len(sfields) for i := 0; i < l; i++ { if sfields[i].Index != f.SIndex { continue } sf := sfields[i] // Must use different codepath for signed/unsigned. switch sf.BinaryType.Kind() { case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: alen = int(sv.Int()) case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: alen = int(sv.Uint()) default: panic(fmt.Errorf("unsupported size type %s: %s", sf.BinaryType.String(), sf.Name)) } break } } switch f.BinaryType.Kind() { case reflect.Array: l := f.BinaryType.Len() // If the underlying value is a slice, initialize it. if f.NativeType.Kind() == reflect.Slice { v.Set(reflect.MakeSlice(reflect.SliceOf(f.NativeType.Elem()), l, l)) } switch f.NativeType.Kind() { case reflect.String: // When using strings, treat as C string. str := string(d.readBytes(d.fieldbytes(f, v))) nul := strings.IndexByte(str, 0) if nul != -1 { str = str[0:nul] } v.SetString(str) case reflect.Slice, reflect.Array: ef := f.Elem() for i := 0; i < l; i++ { d.read(ef, v.Index(i)) } default: panic(fmt.Errorf("invalid array cast type: %s", f.NativeType.String())) } case reflect.Struct: d.push(v) d.sfields = cachedFieldsFromStruct(f.BinaryType) l := len(d.sfields) for i := 0; i < l; i++ { f := d.sfields[i] v := v.Field(f.Index) if v.CanSet() { d.read(f, v) } else { d.skip(f, v) } } d.sfields = sfields d.pop(v) case reflect.Ptr: v.Set(reflect.New(v.Type().Elem())) d.read(f.Elem(), v.Elem()) case reflect.Slice, reflect.String: fixed := func() { switch f.NativeType.Elem().Kind() { case reflect.Uint8: v.SetBytes(d.readBytes(d.fieldbytes(f, v))) default: ef := f.Elem() for i := 0; i < alen; i++ { d.read(ef, v.Index(i)) } } } switch f.NativeType.Kind() { case reflect.String: v.SetString(string(d.readBytes(alen))) case reflect.Array: if f.WhileExpr != nil { i := 0 ef := f.Elem() for d.evalWhile(f) { d.read(ef, v.Index(i)) i++ } } else { fixed() } case reflect.Slice: if f.WhileExpr != nil { switch f.NativeType.Kind() { case reflect.Slice: ef := f.Elem() for d.evalWhile(f) { nv := reflect.New(ef.NativeType).Elem() d.read(ef, nv) v.Set(reflect.Append(v, nv)) } } } else { v.Set(reflect.MakeSlice(f.NativeType, alen, alen)) fixed() } default: panic(fmt.Errorf("invalid array cast type: %s", f.NativeType.String())) } case reflect.Int8: d.setInt(f, v, int64(d.readS8(f))) case reflect.Int16: d.setInt(f, v, int64(d.readS16(f))) case reflect.Int32: d.setInt(f, v, int64(d.readS32(f))) case reflect.Int64: d.setInt(f, v, d.readS64(f)) case reflect.Uint8, reflect.Bool: d.setUint(f, v, uint64(d.read8(f))) case reflect.Uint16: d.setUint(f, v, uint64(d.read16(f))) case reflect.Uint32: d.setUint(f, v, uint64(d.read32(f))) case reflect.Uint64: d.setUint(f, v, d.read64(f)) case reflect.Float32: v.SetFloat(float64(math.Float32frombits(d.read32(f)))) case reflect.Float64: v.SetFloat(math.Float64frombits(d.read64(f))) case reflect.Complex64: v.SetComplex(complex( float64(math.Float32frombits(d.read32(f))), float64(math.Float32frombits(d.read32(f))), )) case reflect.Complex128: v.SetComplex(complex( math.Float64frombits(d.read64(f)), math.Float64frombits(d.read64(f)), )) } if f.InExpr != nil { v.Set(reflect.ValueOf(d.evalExpr(f.InExpr))) } } golang-github-go-restruct-restruct-1.2.0-alpha/encoder.go000066400000000000000000000174241412231745000234260ustar00rootroot00000000000000package restruct import ( "encoding/binary" "fmt" "math" "reflect" ) // Packer is a type capable of packing a native value into a binary // representation. The Pack function is expected to overwrite a number of // bytes in buf then return a slice of the remaining buffer. Note that you // must also implement SizeOf, and returning an incorrect SizeOf will cause // the encoder to crash. The SizeOf should be equal to the number of bytes // consumed from the buffer slice in Pack. You may use a pointer receiver even // if the type is used by value. type Packer interface { Sizer Pack(buf []byte, order binary.ByteOrder) ([]byte, error) } type encoder struct { structstack order binary.ByteOrder sfields []field bitCounter int bitSize int } func getBit(buf []byte, bitSize int, bit int) byte { bit = bitSize - 1 - bit return (buf[len(buf)-bit/8-1] >> (uint(bit) % 8)) & 1 } func (e *encoder) writeBit(value byte) { e.buf[0] |= (value & 1) << uint(7-e.bitCounter) e.bitCounter++ if e.bitCounter >= 8 { e.buf = e.buf[1:] e.bitCounter -= 8 } } func (e *encoder) writeBits(f field, inBuf []byte) { var encodedBits int // Determine encoded size in bits. if e.bitSize == 0 { encodedBits = 8 * len(inBuf) } else { encodedBits = int(e.bitSize) } // Crop input buffer to relevant bytes only. inBuf = inBuf[len(inBuf)-(encodedBits+7)/8:] if e.bitCounter == 0 && encodedBits%8 == 0 { // Fast path: we are fully byte-aligned. copy(e.buf, inBuf) e.buf = e.buf[len(inBuf):] } else { // Slow path: work bit-by-bit. // TODO: This needs to be optimized in a way that can be easily // understood; the previous optimized version was simply too hard to // reason about. for i := 0; i < encodedBits; i++ { e.writeBit(getBit(inBuf, encodedBits, i)) } } } func (e *encoder) write8(f field, x uint8) { b := make([]byte, 1) b[0] = x e.writeBits(f, b) } func (e *encoder) write16(f field, x uint16) { b := make([]byte, 2) e.order.PutUint16(b, x) e.writeBits(f, b) } func (e *encoder) write32(f field, x uint32) { b := make([]byte, 4) e.order.PutUint32(b, x) e.writeBits(f, b) } func (e *encoder) write64(f field, x uint64) { b := make([]byte, 8) e.order.PutUint64(b, x) e.writeBits(f, b) } func (e *encoder) writeS8(f field, x int8) { e.write8(f, uint8(x)) } func (e *encoder) writeS16(f field, x int16) { e.write16(f, uint16(x)) } func (e *encoder) writeS32(f field, x int32) { e.write32(f, uint32(x)) } func (e *encoder) writeS64(f field, x int64) { e.write64(f, uint64(x)) } func (e *encoder) skipBits(count int) { e.bitCounter += count % 8 if e.bitCounter > 8 { e.bitCounter -= 8 count += 8 } e.buf = e.buf[count/8:] } func (e *encoder) skip(f field, v reflect.Value) { e.skipBits(e.fieldbits(f, v)) } func (e *encoder) packer(v reflect.Value) (Packer, bool) { if s, ok := v.Interface().(Packer); ok { return s, true } if !v.CanAddr() { return nil, false } if s, ok := v.Addr().Interface().(Packer); ok { return s, true } return nil, false } func (e *encoder) intFromField(f field, v reflect.Value) int64 { switch v.Kind() { case reflect.Bool: b := v.Bool() if f.Flags&InvertedBoolFlag == InvertedBoolFlag { b = !b } if b { if f.Flags&VariantBoolFlag == VariantBoolFlag { return -1 } return 1 } return 0 default: return v.Int() } } func (e *encoder) uintFromField(f field, v reflect.Value) uint64 { switch v.Kind() { case reflect.Bool: b := v.Bool() if f.Flags&InvertedBoolFlag == InvertedBoolFlag { b = !b } if b { if f.Flags&VariantBoolFlag == VariantBoolFlag { return ^uint64(0) } return 1 } return 0 default: return v.Uint() } } func (e *encoder) switc(f field, v reflect.Value, on interface{}) { var def *switchcase if v.Kind() != reflect.Struct { panic(fmt.Errorf("%s: only switches on structs are valid", f.Name)) } sfields := cachedFieldsFromStruct(f.BinaryType) l := len(sfields) for i := 0; i < l; i++ { f := sfields[i] v := v.Field(f.Index) if f.Flags&DefaultFlag != 0 { if def != nil { panic(fmt.Errorf("%s: only one default case is allowed", f.Name)) } def = &switchcase{f, v} continue } if f.CaseExpr == nil { panic(fmt.Errorf("%s: only cases are valid inside switches", f.Name)) } if e.evalExpr(f.CaseExpr) == on { e.write(f, v) return } } if def != nil { e.write(def.f, def.v) } } func (e *encoder) write(f field, v reflect.Value) { if f.Flags&RootFlag == RootFlag { e.setancestor(f, v, e.root()) return } if f.Flags&ParentFlag == ParentFlag { for i := 1; i < len(e.stack); i++ { if e.setancestor(f, v, e.ancestor(i)) { break } } return } if f.SwitchExpr != nil { e.switc(f, v, e.evalExpr(f.SwitchExpr)) return } struc := e.ancestor(0) if f.Name != "_" { if s, ok := e.packer(v); ok { var err error e.buf, err = s.Pack(e.buf, e.order) if err != nil { panic(err) } return } } else { e.skipBits(e.fieldbits(f, v)) return } if !e.evalIf(f) { return } sfields := e.sfields order := e.order if f.Order != nil { e.order = f.Order defer func() { e.order = order }() } if f.Skip != 0 { e.skipBits(f.Skip * 8) } e.bitSize = e.evalBits(f) // If this is a sizeof field, pull the current slice length into it. if f.TIndex != -1 { sv := struc.Field(f.TIndex) switch f.BinaryType.Kind() { case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: v.SetInt(int64(sv.Len())) case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: v.SetUint(uint64(sv.Len())) default: panic(fmt.Errorf("unsupported size type %s: %s", f.BinaryType.String(), f.Name)) } } ov := v if f.OutExpr != nil { ov = reflect.ValueOf(e.evalExpr(f.OutExpr)) } switch f.BinaryType.Kind() { case reflect.Ptr: // Skip if pointer is nil. if v.IsNil() { return } e.write(f.Elem(), v.Elem()) case reflect.Array, reflect.Slice, reflect.String: switch f.NativeType.Kind() { case reflect.Slice, reflect.String: if f.SizeExpr != nil { if l := e.evalSize(f); l != ov.Len() { panic(fmt.Errorf("length does not match size expression (%d != %d)", ov.Len(), l)) } } fallthrough case reflect.Array: ef := f.Elem() len := ov.Len() cap := len if f.BinaryType.Kind() == reflect.Array { cap = f.BinaryType.Len() } for i := 0; i < len; i++ { e.write(ef, ov.Index(i)) } for i := len; i < cap; i++ { e.write(ef, reflect.New(f.BinaryType.Elem()).Elem()) } default: panic(fmt.Errorf("invalid array cast type: %s", f.NativeType.String())) } case reflect.Struct: e.push(ov) e.sfields = cachedFieldsFromStruct(f.BinaryType) l := len(e.sfields) for i := 0; i < l; i++ { sf := e.sfields[i] sv := ov.Field(sf.Index) if sv.CanSet() { e.write(sf, sv) } else { e.skip(sf, sv) } } e.sfields = sfields e.pop(ov) case reflect.Int8: e.writeS8(f, int8(e.intFromField(f, ov))) case reflect.Int16: e.writeS16(f, int16(e.intFromField(f, ov))) case reflect.Int32: e.writeS32(f, int32(e.intFromField(f, ov))) case reflect.Int64: e.writeS64(f, int64(e.intFromField(f, ov))) case reflect.Uint8, reflect.Bool: e.write8(f, uint8(e.uintFromField(f, ov))) case reflect.Uint16: e.write16(f, uint16(e.uintFromField(f, ov))) case reflect.Uint32: e.write32(f, uint32(e.uintFromField(f, ov))) case reflect.Uint64: e.write64(f, uint64(e.uintFromField(f, ov))) case reflect.Float32: e.write32(f, math.Float32bits(float32(ov.Float()))) case reflect.Float64: e.write64(f, math.Float64bits(float64(ov.Float()))) case reflect.Complex64: x := ov.Complex() e.write32(f, math.Float32bits(float32(real(x)))) e.write32(f, math.Float32bits(float32(imag(x)))) case reflect.Complex128: x := ov.Complex() e.write64(f, math.Float64bits(float64(real(x)))) e.write64(f, math.Float64bits(float64(imag(x)))) } } golang-github-go-restruct-restruct-1.2.0-alpha/expr.go000066400000000000000000000006071412231745000227600ustar00rootroot00000000000000package restruct import ( "github.com/go-restruct/restruct/expr" ) var ( expressionsEnabled = false stdLibResolver = expr.NewMapResolver(exprStdLib) ) // EnableExprBeta enables you to use restruct expr while it is still in beta. // Use at your own risk. Functionality may change in unforeseen, incompatible // ways at any time. func EnableExprBeta() { expressionsEnabled = true } golang-github-go-restruct-restruct-1.2.0-alpha/expr/000077500000000000000000000000001412231745000224265ustar00rootroot00000000000000golang-github-go-restruct-restruct-1.2.0-alpha/expr/ast.go000066400000000000000000000075721412231745000235570ustar00rootroot00000000000000package expr import ( "fmt" "strconv" ) type node interface { source() string } type unaryop int const ( unaryplus unaryop = iota unarynegate unarynot unarybitnot unaryderef unaryref ) type binaryop int const ( binarylogicalor binaryop = iota binarylogicaland binaryequal binarynotequal binarylesser binarylesserequal binarygreater binarygreaterequal binaryadd binarysub binaryor binaryxor binarymul binarydiv binaryrem binarylsh binaryrsh binaryand binaryandnot binarymember binarycall binarysubscript binarygroup ) // Identifier node. type identnode struct { pos int ident string } func newidentnode(t token) identnode { return identnode{t.pos, t.sval} } func (n identnode) source() string { return n.ident } // Integer literal node. type intnode struct { pos int uval uint64 ival int64 sign bool } func newintnode(t token) intnode { return intnode{pos: t.pos, uval: t.uval, ival: t.ival, sign: t.sign} } func (n intnode) source() string { if n.sign { return strconv.FormatInt(n.ival, 10) } return strconv.FormatUint(n.uval, 10) } // Float literal node. type floatnode struct { pos int fval float64 } func newfloatnode(t token) floatnode { return floatnode{pos: t.pos, fval: t.fval} } func (n floatnode) source() string { return strconv.FormatFloat(n.fval, 'f', -1, 64) } // Bool literal node. type boolnode struct { pos int val bool } func newboolnode(t token) boolnode { return boolnode{t.pos, t.bval} } func (n boolnode) source() string { if n.val { return "true" } return "false" } // String literal node. type strnode struct { pos int val string } func newstrnode(t token) strnode { return strnode{t.pos, t.sval} } func (n strnode) source() string { return fmt.Sprintf("%q", n.val) } // Rune literal node. type runenode struct { pos int val rune } func newrunenode(t token) runenode { return runenode{t.pos, rune(t.ival)} } func (n runenode) source() string { return fmt.Sprintf("%q", n.val) } // Nil node. type nilnode struct { pos int } func newnilnode(t token) nilnode { return nilnode{t.pos} } func (nilnode) source() string { return "nil" } // Unary expression node. type unaryexpr struct { op unaryop n node } func (n unaryexpr) source() string { operand := n.n.source() switch n.op { case unaryplus: return "+" + operand case unarynegate: return "-" + operand case unarynot: return "!" + operand case unarybitnot: return "^" + operand case unaryderef: return "*" + operand case unaryref: return "&" + operand } panic("invalid unary expr?") } // Binary expression node. type binaryexpr struct { op binaryop a, b node } func (n binaryexpr) source() string { a, b := n.a.source(), n.b.source() switch n.op { case binarylogicalor: return a + " || " + b case binarylogicaland: return a + " && " + b case binaryequal: return a + " == " + b case binarynotequal: return a + " != " + b case binarylesser: return a + " < " + b case binarylesserequal: return a + " <= " + b case binarygreater: return a + " > " + b case binarygreaterequal: return a + " >= " + b case binaryadd: return a + " + " + b case binarysub: return a + " - " + b case binaryor: return a + " | " + b case binaryxor: return a + " ^ " + b case binarymul: return a + " * " + b case binarydiv: return a + " / " + b case binaryrem: return a + " % " + b case binarylsh: return a + " << " + b case binaryrsh: return a + " >> " + b case binaryand: return a + " & " + b case binaryandnot: return a + " &^ " + b case binarymember: return a + "." + b case binarycall: return a + "(" + b + ")" case binarysubscript: return a + "[" + b + "]" case binarygroup: return a + ", " + b } panic("invalid binary expr?") } // Ternary expression node. type ternaryexpr struct { a, b, c node } func (n ternaryexpr) source() string { return n.a.source() + " ? " + n.b.source() + " : " + n.c.source() } golang-github-go-restruct-restruct-1.2.0-alpha/expr/ast_test.go000066400000000000000000000016551412231745000246120ustar00rootroot00000000000000package expr import ( "testing" "github.com/stretchr/testify/assert" ) func TestSource(t *testing.T) { tests := []struct { input node output string }{ { binaryexpr{ binaryadd, identnode{0, "a"}, binaryexpr{ binarymul, identnode{4, "b"}, identnode{8, "c"}, }, }, "a + b * c", }, { ternaryexpr{ binaryexpr{ binaryequal, identnode{0, "a"}, intnode{5, 1, 1, false}, }, binaryexpr{ binaryadd, identnode{9, "b"}, intnode{13, 1, 1, false}, }, binaryexpr{ binarymul, identnode{17, "c"}, intnode{21, 1, 1, false}, }, }, "a == 1 ? b + 1 : c * 1", }, { binaryexpr{ binarycall, identnode{0, "a"}, binaryexpr{ binarygroup, identnode{2, "b"}, identnode{5, "c"}, }, }, "a(b, c)", }, } for _, test := range tests { assert.Equal(t, test.output, test.input.source()) } } golang-github-go-restruct-restruct-1.2.0-alpha/expr/env.go000066400000000000000000000073721412231745000235560ustar00rootroot00000000000000package expr import "reflect" // Assertions. var ( _ = TypeResolver(&TypeResolverAdapter{}) _ = TypeResolver(&MetaTypeResolver{}) _ = Resolver(&MetaResolver{}) _ = TypeResolver(&StructTypeResolver{}) _ = Resolver(&StructResolver{}) _ = TypeResolver(&MapTypeResolver{}) _ = Resolver(&MapResolver{}) ) // TypeResolver resolves types. type TypeResolver interface { TypeResolve(ident string) Type } // Resolver resolves runtime values. type Resolver interface { Resolve(ident string) Value } // TypeResolverAdapter adapts a runtime resolver to a type resolver by taking // types of values retrieve from Resolve. type TypeResolverAdapter struct { Resolver } // NewTypeResolverAdapter creates a new TypeResolverAdapter from a resolver. func NewTypeResolverAdapter(r Resolver) *TypeResolverAdapter { return &TypeResolverAdapter{r} } // TypeResolve implements TypeResolver. func (r *TypeResolverAdapter) TypeResolve(ident string) Type { return r.Resolve(ident).Type() } // MetaTypeResolver runs multiple type resolvers serially. type MetaTypeResolver struct { resolvers []TypeResolver } // NewMetaTypeResolver creates a new meta type resolver. func NewMetaTypeResolver() *MetaTypeResolver { return &MetaTypeResolver{} } // AddResolver adds a new resolver below other resolvers. func (r *MetaTypeResolver) AddResolver(n TypeResolver) { r.resolvers = append(r.resolvers, n) } // TypeResolve implements TypeResolver. func (r *MetaTypeResolver) TypeResolve(ident string) Type { for _, resolver := range r.resolvers { if t := resolver.TypeResolve(ident); t != nil { return t } } return nil } // MetaResolver runs multiple resolvers serially. type MetaResolver struct { resolvers []Resolver } // NewMetaResolver creates a new meta resolver. func NewMetaResolver() *MetaResolver { return &MetaResolver{} } // AddResolver adds a new resolver below other resolvers. func (r *MetaResolver) AddResolver(n Resolver) { r.resolvers = append(r.resolvers, n) } // Resolve implements Resolver. func (r *MetaResolver) Resolve(ident string) Value { for _, resolver := range r.resolvers { if t := resolver.Resolve(ident); t != nil { return t } } return nil } // StructTypeResolver resolves types of struct fields. type StructTypeResolver struct { struc *StructType } // NewStructTypeResolver creates a new struct type resolver. func NewStructTypeResolver(s interface{}) *StructTypeResolver { return &StructTypeResolver{TypeOf(s).(*StructType)} } // TypeResolve implements TypeResolver. func (r *StructTypeResolver) TypeResolve(ident string) Type { if f, ok := r.struc.FieldByName(ident); ok { return f.Type } return nil } // StructResolver resolves struct fields. type StructResolver struct { struc reflect.Value } // NewStructResolver creates a new struct resolver. func NewStructResolver(s reflect.Value) *StructResolver { return &StructResolver{s} } // Resolve implements Resolver. func (r *StructResolver) Resolve(ident string) Value { if sv := r.struc.FieldByName(ident); sv.IsValid() { return ValueOf(sv.Interface()) } return nil } // MapTypeResolver resolves map keys. type MapTypeResolver struct { m map[string]Type } // NewMapTypeResolver creates a new struct resolver. func NewMapTypeResolver(m map[string]Type) *MapTypeResolver { return &MapTypeResolver{m} } // TypeResolve implements TypeResolver. func (r *MapTypeResolver) TypeResolve(ident string) Type { if t, ok := r.m[ident]; ok { return t } return nil } // MapResolver resolves map keys. type MapResolver struct { m map[string]Value } // NewMapResolver creates a new struct resolver. func NewMapResolver(m map[string]Value) *MapResolver { return &MapResolver{m} } // Resolve implements Resolver. func (r *MapResolver) Resolve(ident string) Value { if v, ok := r.m[ident]; ok { return v } return nil } golang-github-go-restruct-restruct-1.2.0-alpha/expr/eval.go000066400000000000000000000067161412231745000237160ustar00rootroot00000000000000package expr import ( "fmt" ) // EvalProgram returns the result of executing the program with the given resolver. func EvalProgram(resolver Resolver, program *Program) (v interface{}, err error) { defer func() { if r := recover(); r != nil { if rerr, ok := r.(error); ok { err = rerr } else { panic(r) } } }() v = evalnode(resolver, program.root).RawValue() return } // Eval returns the result of evaluating the provided expression. func Eval(resolver Resolver, expr string) (interface{}, error) { return EvalProgram(resolver, ParseString(expr)) } func evalnode(resolver Resolver, node node) Value { switch n := node.(type) { case identnode: v := resolver.Resolve(n.ident) if v == nil { panic(fmt.Errorf("unresolved name %s", n.ident)) } return v case intnode: if n.sign { return literalintval(n.ival) } return literaluintval(n.uval) case floatnode: return literalfloatval(n.fval) case boolnode: return literalboolval(n.val) case strnode: return literalstrval(n.val) case runenode: return literalintval(int64(n.val)) case nilnode: return literalnilval() case unaryexpr: return evalunary(resolver, n) case binaryexpr: return evalbinary(resolver, n) case ternaryexpr: return evalternary(resolver, n) default: panic("invalid node") } } func evalunary(resolver Resolver, node unaryexpr) Value { n := evalnode(resolver, node.n) switch node.op { case unaryplus: return n case unarynegate: return n.Negate() case unarynot: return n.Not() case unarybitnot: return n.BitNot() case unaryderef: return n.Deref() case unaryref: return n.Ref() default: panic("invalid unary expression") } } func flattengroup(n node) []node { if n, ok := n.(binaryexpr); ok { if n.op == binarygroup { return append(flattengroup(n.a), flattengroup(n.b)...) } } return []node{n} } func evalbinary(resolver Resolver, node binaryexpr) Value { a := evalnode(resolver, node.a) switch node.op { case binarymember: if id, ok := node.b.(identnode); ok { return a.Dot(id.ident) } panic(fmt.Errorf("expected ident node, got %T", node.b)) case binarycall: in := []Value{} for _, n := range flattengroup(node.b) { in = append(in, evalnode(resolver, n)) } return a.Call(in) case binarygroup: return evalnode(resolver, node.b) } b := evalnode(resolver, node.b) switch node.op { case binarylogicalor: return a.LogicalOr(b) case binarylogicaland: return a.LogicalAnd(b) case binaryequal: return a.Equal(b) case binarynotequal: return a.NotEqual(b) case binarylesser: return a.Lesser(b) case binarylesserequal: return a.LesserEqual(b) case binarygreater: return a.Greater(b) case binarygreaterequal: return a.GreaterEqual(b) case binaryadd: return a.Add(b) case binarysub: return a.Sub(b) case binaryor: return a.Or(b) case binaryxor: return a.Xor(b) case binarymul: return a.Mul(b) case binarydiv: return a.Div(b) case binaryrem: return a.Rem(b) case binarylsh: return a.Lsh(b) case binaryrsh: return a.Rsh(b) case binaryand: return a.And(b) case binaryandnot: return a.AndNot(b) case binarysubscript: return a.Index(b) default: panic("invalid binary expression") } } func evalternary(resolver Resolver, node ternaryexpr) Value { a := evalnode(resolver, node.a).Value().Interface() cond, ok := a.(bool) if !ok { panic(fmt.Errorf("unexpected type %T for ternary", cond)) } if cond { return evalnode(resolver, node.b) } return evalnode(resolver, node.c) } golang-github-go-restruct-restruct-1.2.0-alpha/expr/eval_test.go000066400000000000000000000041641412231745000247500ustar00rootroot00000000000000package expr import ( "reflect" "testing" "github.com/stretchr/testify/assert" ) type TestStruct1 struct { A int B float64 } func TestEvalSimple(t *testing.T) { tests := []struct { struc interface{} expr string result interface{} }{ { TestStruct1{A: 42}, "A", 42, }, { TestStruct1{A: 42}, "A * 2", 84, }, { TestStruct1{B: 10.5}, "B * 2", 21.0, }, { TestStruct1{B: 10.5}, "-(B * 2)", -21.0, }, { TestStruct1{A: 0xf0}, "^0xf0 | A", -1, }, { TestStruct1{}, "2 << 2", 8, }, { TestStruct1{}, "true", true, }, { TestStruct1{}, "false", false, }, { TestStruct1{}, "true ? 1.0 : 0.0", 1.0, }, { TestStruct1{}, "false ? 1.0 : 0.0", 0.0, }, { TestStruct1{}, `"string value!"`, "string value!", }, { TestStruct1{}, `"equal" == "equal"`, true, }, { TestStruct1{}, `"equal" == "not equal"`, false, }, { TestStruct1{}, `"equal" != "not equal"`, true, }, { TestStruct1{}, `"equal" != "equal"`, false, }, { TestStruct1{}, `"equal"[1] == 'q'`, true, }, } for _, test := range tests { resolver := NewStructResolver(reflect.ValueOf(test.struc)) result, err := Eval(resolver, test.expr) assert.Nil(t, err) assert.Equal(t, test.result, result) } } func TestError(t *testing.T) { tests := []struct { struc interface{} expr string err string }{ { TestStruct1{A: 42}, "!A", "invalid operation: operator ! not defined for 42 (int)", }, { TestStruct1{}, "!42", "invalid operation: operator ! not defined for 42 (untyped int constant)", }, { TestStruct1{A: 1, B: 1.0}, "A == B", "cannot convert int to float64", }, { TestStruct1{A: 1, B: 1.0}, "A == true", "cannot convert int to untyped bool constant", }, { TestStruct1{A: 1, B: 1.0}, "A > true", "cannot convert int to untyped bool constant", }, } for _, test := range tests { resolver := NewStructResolver(reflect.ValueOf(test.struc)) _, err := Eval(resolver, test.expr) assert.EqualError(t, err, test.err) } } golang-github-go-restruct-restruct-1.2.0-alpha/expr/lex.go000066400000000000000000000240211412231745000235440ustar00rootroot00000000000000package expr //go:generate stringer -type=tokenkind import ( "fmt" "io" "strconv" "unicode" "unicode/utf8" ) func lower(ch rune) rune { return ('a' - 'A') | ch } func isdecimal(ch rune) bool { return '0' <= ch && ch <= '9' } func isoctal(ch rune) bool { return '0' <= ch && ch <= '7' } func ishex(ch rune) bool { return '0' <= ch && ch <= '9' || 'a' <= lower(ch) && lower(ch) <= 'f' } func isletter(c rune) bool { return 'a' <= lower(c) && lower(c) <= 'z' || c == '_' || c >= utf8.RuneSelf && unicode.IsLetter(c) } func isdigit(c rune) bool { return isdecimal(c) || c >= utf8.RuneSelf && unicode.IsDigit(c) } func isnumber(c rune) bool { return isdigit(c) || ishex(c) || c == '.' || lower(c) == 'x' } func isident(c rune) bool { return isletter(c) || isdigit(c) } func iswhitespace(c rune) bool { return c == ' ' || c == '\t' } // tokenkind is an enumeration of different kinds of tokens. type tokenkind int // This is a definition of all possible token kinds. const ( niltoken tokenkind = iota errtoken eoftoken identtoken inttoken floattoken booltoken strtoken runetoken addtoken subtoken multoken quotoken remtoken andtoken nottoken ortoken xortoken shltoken shrtoken andnottoken logicalandtoken logicalortoken equaltoken lessertoken greatertoken notequaltoken lesserequaltoken greaterequaltoken leftparentoken leftbrackettoken commatoken periodtoken rightparentoken rightbrackettoken colontoken ternarytoken boolkeyword bytekeyword float32keyword float64keyword intkeyword int8keyword int16keyword int32keyword int64keyword uintkeyword uint8keyword uint16keyword uint32keyword uint64keyword uintptrkeyword nilkeyword ) var keywordmap = map[string]tokenkind{ "bool": boolkeyword, "byte": bytekeyword, "float32": float32keyword, "float64": float64keyword, "int": intkeyword, "int8": int8keyword, "int16": int16keyword, "int32": int32keyword, "int64": int64keyword, "uint": uintkeyword, "uint8": uint8keyword, "uint16": uint16keyword, "uint32": uint32keyword, "uint64": uint64keyword, "uintptr": uintptrkeyword, "nil": nilkeyword, } const eof = utf8.MaxRune + 0x0001 // token contains information for a single lexical token. type token struct { kind tokenkind pos int sval string ival int64 uval uint64 fval float64 bval bool sign bool eval error } // scanner scans lexical tokens from the expression. type scanner struct { r io.RuneScanner p int eof bool } func newscanner(r io.RuneScanner) *scanner { return &scanner{r: r} } func (s *scanner) readrune() rune { if s.eof { return eof } c, _, err := s.r.ReadRune() if err == io.EOF { s.eof = true return eof } else if err != nil { panic(err) } s.p++ return c } func (s *scanner) unreadrune() { if s.eof { return } if err := s.r.UnreadRune(); err != nil { panic(err) } s.p-- } func (s *scanner) skipws() { for { c := s.readrune() if !iswhitespace(c) { s.unreadrune() return } } } func (s *scanner) accept(c rune) bool { if s.readrune() == c { return true } s.unreadrune() return false } func (s *scanner) expect(c rune) { r := s.readrune() if r != c { panic(fmt.Errorf("expected %c", r)) } } func (s *scanner) peekmatch(f func(rune) bool) bool { c := s.readrune() s.unreadrune() return f(c) } func (s *scanner) acceptfn(f func(rune) bool) (rune, bool) { r := s.readrune() if f(r) { return r, true } s.unreadrune() return r, false } func (s *scanner) expectfn(f func(rune) bool) rune { r, ok := s.acceptfn(f) if !ok { panic(fmt.Errorf("unexpected %c", r)) } return r } func (s *scanner) tokensym(k tokenkind, src string) token { return token{kind: k, sval: src} } func (s *scanner) errsymf(format string, a ...interface{}) token { return token{kind: errtoken, eval: fmt.Errorf(format, a...)} } func (s *scanner) scanident() token { t := token{kind: identtoken} if r, ok := s.acceptfn(isletter); ok { t.sval = string(r) } else { return s.errsymf("unexpected ident start token: %c", r) } for { if r, ok := s.acceptfn(isident); ok { t.sval += string(r) continue } break } // Handle boolean constant. if t.sval == "true" { t.kind = booltoken t.bval = true } if t.sval == "false" { t.kind = booltoken t.bval = false } // Handle keywords. if k, ok := keywordmap[t.sval]; ok { t.kind = k } return t } func (s *scanner) scannumber(t token) token { if r, ok := s.acceptfn(isnumber); ok { t.sval += string(r) } else { return s.errsymf("unexpected int start token: %c", r) } for { if r, ok := s.acceptfn(isnumber); ok { t.sval += string(r) continue } break } var err error if t.uval, err = strconv.ParseUint(t.sval, 0, 64); err == nil { t.ival = int64(t.uval) t.fval = float64(t.ival) t.kind = inttoken t.sign = false } else if t.ival, err = strconv.ParseInt(t.sval, 0, 64); err == nil { t.uval = uint64(t.ival) t.fval = float64(t.ival) t.kind = inttoken t.sign = true } else if t.fval, err = strconv.ParseFloat(t.sval, 64); err == nil { t.ival = int64(t.fval) t.uval = uint64(t.fval) t.kind = floattoken } else { return token{kind: errtoken, eval: err} } return t } func runebytes(r rune) []byte { runebuf := [4]byte{} l := utf8.EncodeRune(runebuf[:], rune(r)) return runebuf[:l] } func (s *scanner) scanescape(quote byte) []byte { switch { case s.accept('a'): return []byte{'\a'} case s.accept('b'): return []byte{'\b'} case s.accept('f'): return []byte{'\f'} case s.accept('n'): return []byte{'\n'} case s.accept('r'): return []byte{'\r'} case s.accept('t'): return []byte{'\t'} case s.accept('v'): return []byte{'\v'} case s.accept('\\'): return []byte{'\\'} case s.accept(rune(quote)): return []byte{quote} case s.peekmatch(isoctal): octal := string([]rune{s.expectfn(isoctal), s.expectfn(isoctal), s.expectfn(isoctal)}) code, err := strconv.ParseUint(octal, 8, 8) if err != nil { panic(err) } return []byte{byte(code)} case s.accept('x'): hex := string([]rune{s.expectfn(ishex), s.expectfn(ishex)}) code, err := strconv.ParseUint(hex, 16, 8) if err != nil { panic(err) } return []byte{byte(code)} case s.accept('u'): hex := string([]rune{ s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), }) code, err := strconv.ParseUint(hex, 16, 16) if err != nil { panic(err) } return runebytes(rune(code)) case s.accept('U'): hex := string([]rune{ s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), s.expectfn(ishex), }) code, err := strconv.ParseUint(hex, 16, 32) if err != nil { panic(err) } return runebytes(rune(code)) default: panic(fmt.Errorf("unexpected escape code %c", s.readrune())) } } func (s *scanner) scanstring(quote byte) token { str := []byte{} for { switch { case s.accept(rune(quote)): return token{kind: strtoken, sval: string(str)} case s.accept('\\'): str = append(str, s.scanescape(quote)...) default: str = append(str, runebytes(s.readrune())...) } } } func (s *scanner) scanrune() token { defer s.expect('\'') switch { case s.accept('\\'): r := []rune(string(s.scanescape('\''))) return token{kind: runetoken, ival: int64(r[0])} default: return token{kind: runetoken, ival: int64(s.readrune())} } } func (s *scanner) scan() (t token) { defer func() { if r := recover(); r != nil { if err, ok := r.(error); ok { t = token{kind: errtoken, pos: s.p, eval: err} } else { panic(r) } } }() s.skipws() p := s.p defer func() { t.pos = p }() switch { case s.accept(eof): p = s.p return token{kind: eoftoken} case s.peekmatch(isletter): return s.scanident() case s.peekmatch(isdigit): return s.scannumber(token{}) case s.accept('"'): return s.scanstring('"') case s.accept('\''): return s.scanrune() case s.accept('$'): s.expect('\'') return s.scanstring('\'') case s.accept('+'): return s.tokensym(addtoken, "+") case s.accept('-'): switch { default: return s.tokensym(subtoken, "-") case s.peekmatch(isdigit): return s.scannumber(token{sval: "-"}) } case s.accept('*'): return s.tokensym(multoken, "*") case s.accept('/'): return s.tokensym(quotoken, "/") case s.accept('%'): return s.tokensym(remtoken, "%") case s.accept('&'): switch { default: return s.tokensym(andtoken, "&") case s.accept('&'): return s.tokensym(logicalandtoken, "&&") case s.accept('^'): return s.tokensym(andnottoken, "&^") } case s.accept('|'): switch { default: return s.tokensym(ortoken, "|") case s.accept('|'): return s.tokensym(logicalortoken, "||") } case s.accept('^'): switch { default: return s.tokensym(xortoken, "^") } case s.accept('<'): switch { default: return s.tokensym(lessertoken, "<") case s.accept('='): return s.tokensym(lesserequaltoken, "<=") case s.accept('<'): return s.tokensym(shltoken, "<<") } case s.accept('>'): switch { default: return s.tokensym(greatertoken, ">") case s.accept('='): return s.tokensym(greaterequaltoken, ">=") case s.accept('>'): return s.tokensym(shrtoken, ">>") } case s.accept('='): switch { case s.accept('='): return s.tokensym(equaltoken, "==") default: return s.errsymf("unexpected rune %c", s.readrune()) } case s.accept('!'): switch { case s.accept('='): return s.tokensym(notequaltoken, "!=") default: return s.tokensym(nottoken, "!") } case s.accept('('): return s.tokensym(leftparentoken, "(") case s.accept('['): return s.tokensym(leftbrackettoken, "[") case s.accept(','): return s.tokensym(commatoken, ",") case s.accept('.'): switch { default: return s.tokensym(periodtoken, ".") case s.peekmatch(isdigit): return s.scannumber(token{sval: "."}) } case s.accept(')'): return s.tokensym(rightparentoken, ")") case s.accept(']'): return s.tokensym(rightbrackettoken, "]") case s.accept(':'): return s.tokensym(colontoken, ":") case s.accept('?'): return s.tokensym(ternarytoken, "?") default: return s.errsymf("unexpected rune %c", s.readrune()) } } golang-github-go-restruct-restruct-1.2.0-alpha/expr/lex_test.go000066400000000000000000000113511412231745000246050ustar00rootroot00000000000000package expr import ( "bytes" "testing" "github.com/stretchr/testify/assert" ) func TestScanValid(t *testing.T) { tests := []struct { input string expected []token }{ { input: "a + b - c * d / e ^ f | g & h &^ i % k", expected: []token{ {kind: identtoken, sval: "a", pos: 0}, {kind: addtoken, sval: "+", pos: 2}, {kind: identtoken, sval: "b", pos: 4}, {kind: subtoken, sval: "-", pos: 6}, {kind: identtoken, sval: "c", pos: 8}, {kind: multoken, sval: "*", pos: 10}, {kind: identtoken, sval: "d", pos: 12}, {kind: quotoken, sval: "/", pos: 14}, {kind: identtoken, sval: "e", pos: 16}, {kind: xortoken, sval: "^", pos: 18}, {kind: identtoken, sval: "f", pos: 20}, {kind: ortoken, sval: "|", pos: 22}, {kind: identtoken, sval: "g", pos: 24}, {kind: andtoken, sval: "&", pos: 26}, {kind: identtoken, sval: "h", pos: 28}, {kind: andnottoken, sval: "&^", pos: 30}, {kind: identtoken, sval: "i", pos: 33}, {kind: remtoken, sval: "%", pos: 35}, {kind: identtoken, sval: "k", pos: 37}, {kind: eoftoken, pos: 38}, }, }, { input: "l > m < n >= o <= p == q != r >> s << t || u && v", expected: []token{ {kind: identtoken, sval: "l", pos: 0}, {kind: greatertoken, sval: ">", pos: 2}, {kind: identtoken, sval: "m", pos: 4}, {kind: lessertoken, sval: "<", pos: 6}, {kind: identtoken, sval: "n", pos: 8}, {kind: greaterequaltoken, sval: ">=", pos: 10}, {kind: identtoken, sval: "o", pos: 13}, {kind: lesserequaltoken, sval: "<=", pos: 15}, {kind: identtoken, sval: "p", pos: 18}, {kind: equaltoken, sval: "==", pos: 20}, {kind: identtoken, sval: "q", pos: 23}, {kind: notequaltoken, sval: "!=", pos: 25}, {kind: identtoken, sval: "r", pos: 28}, {kind: shrtoken, sval: ">>", pos: 30}, {kind: identtoken, sval: "s", pos: 33}, {kind: shltoken, sval: "<<", pos: 35}, {kind: identtoken, sval: "t", pos: 38}, {kind: logicalortoken, sval: "||", pos: 40}, {kind: identtoken, sval: "u", pos: 43}, {kind: logicalandtoken, sval: "&&", pos: 45}, {kind: identtoken, sval: "v", pos: 48}, {kind: eoftoken, pos: 49}, }, }, { input: "(A + Test) % C[0]", expected: []token{ {kind: leftparentoken, pos: 0, sval: "("}, {kind: identtoken, pos: 1, sval: "A"}, {kind: addtoken, pos: 3, sval: "+"}, {kind: identtoken, pos: 5, sval: "Test"}, {kind: rightparentoken, pos: 9, sval: ")"}, {kind: remtoken, pos: 11, sval: "%"}, {kind: identtoken, pos: 13, sval: "C"}, {kind: leftbrackettoken, pos: 14, sval: "["}, {kind: inttoken, pos: 15, sval: "0"}, {kind: rightbrackettoken, pos: 16, sval: "]"}, {kind: eoftoken, pos: 17}, }, }, { input: "0x80000000 + 0.1", expected: []token{ {kind: inttoken, pos: 0, sval: "0x80000000", ival: 0x80000000, uval: 0x80000000, fval: 0x80000000}, {kind: addtoken, pos: 11, sval: "+"}, {kind: floattoken, pos: 13, sval: "0.1", ival: 0, uval: 0, fval: 0.1}, {kind: eoftoken, pos: 16}, }, }, { input: "0x80000000 + 0.1", expected: []token{ {kind: inttoken, pos: 0, sval: "0x80000000", ival: 0x80000000, uval: 0x80000000, fval: 0x80000000}, {kind: addtoken, pos: 11, sval: "+"}, {kind: floattoken, pos: 13, sval: "0.1", ival: 0, uval: 0, fval: 0.1}, {kind: eoftoken, pos: 16}, }, }, { input: "-0x80000000 - -0.1", expected: []token{ {kind: inttoken, pos: 0, sval: "-0x80000000", ival: -0x80000000, uval: 0xFFFFFFFF80000000, fval: -0x80000000, sign: true}, {kind: subtoken, pos: 12, sval: "-"}, {kind: floattoken, pos: 14, sval: "-0.1", ival: 0, uval: 0, fval: -0.1}, {kind: eoftoken, pos: 18}, }, }, { input: `"a b c" + " d e f"`, expected: []token{ {kind: strtoken, pos: 0, sval: "a b c"}, {kind: addtoken, pos: 8, sval: "+"}, {kind: strtoken, pos: 10, sval: " d e f"}, {kind: eoftoken, pos: 18}, }, }, { input: `'a' + 0`, expected: []token{ {kind: runetoken, pos: 0, ival: 'a'}, {kind: addtoken, pos: 4, sval: "+"}, {kind: inttoken, pos: 6, sval: "0", ival: 0, uval: 0, fval: 0}, {kind: eoftoken, pos: 7}, }, }, { input: `"aä本\t\000\007\377\x07\xff\u12e4\U00101234\""`, expected: []token{ {kind: strtoken, pos: 0, sval: "aä本\t\000\007\377\x07\xff\u12e4\U00101234\""}, {kind: eoftoken, pos: 45}, }, }, } for _, test := range tests { t.Run(test.input, func(t *testing.T) { actual := []token{} s := newscanner(bytes.NewBufferString(test.input)) for { t := s.scan() actual = append(actual, t) if t.kind == eoftoken || t.kind == errtoken { break } if len(actual) > 500 { panic("Maximum test token limit exceeded.") } } assert.Equal(t, test.expected, actual) }) } } golang-github-go-restruct-restruct-1.2.0-alpha/expr/package.go000066400000000000000000000012241412231745000243470ustar00rootroot00000000000000package expr // Package represents a package value. type Package struct { types map[string]Type symbols map[string]Value } // NewPackage creates a new package. func NewPackage(symbols map[string]Value) Package { pkg := Package{symbols: symbols, types: map[string]Type{}} for key := range symbols { pkg.types[key] = pkg.symbols[key].Type() } return pkg } // Symbol returns a symbol, or nil if the symbol doesn't exist. func (p Package) Symbol(ident string) Value { if symbol, ok := p.symbols[ident]; ok { return symbol } return nil } // Type returns the type for this package. func (p Package) Type() Type { return NewPackageType(p.types) } golang-github-go-restruct-restruct-1.2.0-alpha/expr/parse.go000066400000000000000000000106021412231745000240660ustar00rootroot00000000000000package expr import ( "bytes" "fmt" "io" ) // Program represents a parsed expression. type Program struct { root node } // Parse parses an expression into a program. func Parse(r io.RuneScanner) *Program { return &Program{newparser(newscanner(r)).parse()} } // ParseString parses an expression from a string. func ParseString(s string) *Program { return Parse(bytes.NewBufferString(s)) } type parser struct { s *scanner a bool t token } func newparser(s *scanner) *parser { return &parser{s: s} } func (p *parser) readtoken() *token { if !p.a { p.a = true p.t = p.s.scan() } return &p.t } func (p *parser) consume() { p.a = false } func (p *parser) accept(k tokenkind) bool { if p.readtoken().kind == k { p.consume() return true } return false } func (p *parser) expect(k tokenkind) { if p.readtoken().kind != k { panic(fmt.Errorf("expected %s token, got %s", k, p.t.kind)) } p.consume() } // This parser is strongly based on byuu's modified recursive-descent algorithm // (particularly the 'depth' parameter.) // https://github.com/byuu/bsnes/blob/master/nall/string/eval/parser.hpp func (p *parser) parseexpr(depth int) node { var n node unary := func(op unaryop, depth int) { n = unaryexpr{op: op, n: p.parseexpr(depth)} } binary := func(op binaryop, depth int) { if n == nil { panic("unexpected binary op") } n = binaryexpr{op: op, a: n, b: p.parseexpr(depth)} } ternary := func(depth int) { t := ternaryexpr{} t.a = n t.b = p.parseexpr(depth) p.expect(colontoken) t.c = p.parseexpr(depth) n = t } switch { case p.accept(identtoken): n = newidentnode(p.t) case p.accept(inttoken): n = newintnode(p.t) case p.accept(floattoken): n = newfloatnode(p.t) case p.accept(booltoken): n = newboolnode(p.t) case p.accept(strtoken): n = newstrnode(p.t) case p.accept(runetoken): n = newrunenode(p.t) case p.accept(nilkeyword): n = newnilnode(p.t) case p.accept(leftparentoken): n = p.parseexpr(1) default: } for { if depth >= 8 { break } if n != nil && p.accept(periodtoken) { binary(binarymember, 8) continue } if n != nil && p.accept(leftparentoken) { binary(binarycall, 1) continue } if n != nil && p.accept(leftbrackettoken) { binary(binarysubscript, 1) continue } if n == nil && p.accept(addtoken) { unary(unaryplus, 7) } if n == nil && p.accept(subtoken) { unary(unarynegate, 7) } if n == nil && p.accept(nottoken) { unary(unarynot, 7) } if n == nil && p.accept(xortoken) { unary(unarybitnot, 7) } if n == nil && p.accept(multoken) { unary(unaryderef, 7) } if n == nil && p.accept(andtoken) { unary(unaryref, 7) } if depth >= 7 { break } if p.accept(multoken) { binary(binarymul, 7) continue } if p.accept(quotoken) { binary(binarydiv, 7) continue } if p.accept(remtoken) { binary(binaryrem, 7) continue } if p.accept(shltoken) { binary(binarylsh, 7) continue } if p.accept(shrtoken) { binary(binaryrsh, 7) continue } if p.accept(andtoken) { binary(binaryand, 7) continue } if depth >= 6 { break } if p.accept(addtoken) { binary(binaryadd, 6) continue } if p.accept(subtoken) { binary(binarysub, 6) continue } if p.accept(ortoken) { binary(binaryor, 6) continue } if p.accept(xortoken) { binary(binaryxor, 6) continue } if depth >= 5 { break } if p.accept(equaltoken) { binary(binaryequal, 5) continue } if p.accept(notequaltoken) { binary(binarynotequal, 5) continue } if p.accept(lessertoken) { binary(binarylesser, 5) continue } if p.accept(lesserequaltoken) { binary(binarylesserequal, 5) continue } if p.accept(greatertoken) { binary(binarygreater, 5) continue } if p.accept(greaterequaltoken) { binary(binarygreaterequal, 5) continue } if depth >= 4 { break } if p.accept(logicalandtoken) { binary(binarylogicaland, 4) continue } if depth >= 3 { break } if p.accept(logicalortoken) { binary(binarylogicalor, 3) continue } if p.accept(ternarytoken) { ternary(3) continue } if depth >= 2 { break } if p.accept(commatoken) { binary(binarygroup, 2) continue } if depth >= 1 && (p.accept(rightparentoken) || p.accept(rightbrackettoken)) { break } p.expect(eoftoken) break } return n } func (p *parser) parse() node { return p.parseexpr(0) } golang-github-go-restruct-restruct-1.2.0-alpha/expr/parse_test.go000066400000000000000000000030561412231745000251320ustar00rootroot00000000000000package expr import ( "bytes" "testing" "github.com/stretchr/testify/assert" ) func TestParseBasic(t *testing.T) { tests := []struct { input string output node }{ { "a + b * c", binaryexpr{ binaryadd, identnode{0, "a"}, binaryexpr{ binarymul, identnode{4, "b"}, identnode{8, "c"}, }, }, }, { "a * b + c", binaryexpr{ binaryadd, binaryexpr{ binarymul, identnode{0, "a"}, identnode{4, "b"}, }, identnode{8, "c"}, }, }, { "a * (b + c)", binaryexpr{ binarymul, identnode{0, "a"}, binaryexpr{ binaryadd, identnode{5, "b"}, identnode{9, "c"}, }, }, }, { "a ? b : c", ternaryexpr{ identnode{0, "a"}, identnode{4, "b"}, identnode{8, "c"}, }, }, { "a == 1 ? b + 1 : c * 1", ternaryexpr{ binaryexpr{ binaryequal, identnode{0, "a"}, intnode{5, 1, 1, false}, }, binaryexpr{ binaryadd, identnode{9, "b"}, intnode{13, 1, 1, false}, }, binaryexpr{ binarymul, identnode{17, "c"}, intnode{21, 1, 1, false}, }, }, }, { "a(b, c)", binaryexpr{ binarycall, identnode{0, "a"}, binaryexpr{ binarygroup, identnode{2, "b"}, identnode{5, "c"}, }, }, }, { "a[1]", binaryexpr{ binarysubscript, identnode{0, "a"}, intnode{2, 1, 1, false}, }, }, } for _, test := range tests { p := newparser(newscanner(bytes.NewBufferString(test.input))) assert.Equal(t, test.output, p.parse()) } } golang-github-go-restruct-restruct-1.2.0-alpha/expr/tokenkind_string.go000066400000000000000000000050651412231745000263370ustar00rootroot00000000000000// Code generated by "stringer -type=tokenkind"; DO NOT EDIT. package expr import "strconv" func _() { // An "invalid array index" compiler error signifies that the constant values have changed. // Re-run the stringer command to generate them again. var x [1]struct{} _ = x[niltoken-0] _ = x[errtoken-1] _ = x[eoftoken-2] _ = x[identtoken-3] _ = x[inttoken-4] _ = x[floattoken-5] _ = x[booltoken-6] _ = x[strtoken-7] _ = x[runetoken-8] _ = x[addtoken-9] _ = x[subtoken-10] _ = x[multoken-11] _ = x[quotoken-12] _ = x[remtoken-13] _ = x[andtoken-14] _ = x[nottoken-15] _ = x[ortoken-16] _ = x[xortoken-17] _ = x[shltoken-18] _ = x[shrtoken-19] _ = x[andnottoken-20] _ = x[logicalandtoken-21] _ = x[logicalortoken-22] _ = x[equaltoken-23] _ = x[lessertoken-24] _ = x[greatertoken-25] _ = x[notequaltoken-26] _ = x[lesserequaltoken-27] _ = x[greaterequaltoken-28] _ = x[leftparentoken-29] _ = x[leftbrackettoken-30] _ = x[commatoken-31] _ = x[periodtoken-32] _ = x[rightparentoken-33] _ = x[rightbrackettoken-34] _ = x[colontoken-35] _ = x[ternarytoken-36] _ = x[boolkeyword-37] _ = x[bytekeyword-38] _ = x[float32keyword-39] _ = x[float64keyword-40] _ = x[intkeyword-41] _ = x[int8keyword-42] _ = x[int16keyword-43] _ = x[int32keyword-44] _ = x[int64keyword-45] _ = x[uintkeyword-46] _ = x[uint8keyword-47] _ = x[uint16keyword-48] _ = x[uint32keyword-49] _ = x[uint64keyword-50] _ = x[uintptrkeyword-51] _ = x[nilkeyword-52] } const _tokenkind_name = "niltokenerrtokeneoftokenidenttokeninttokenfloattokenbooltokenstrtokenrunetokenaddtokensubtokenmultokenquotokenremtokenandtokennottokenortokenxortokenshltokenshrtokenandnottokenlogicalandtokenlogicalortokenequaltokenlessertokengreatertokennotequaltokenlesserequaltokengreaterequaltokenleftparentokenleftbrackettokencommatokenperiodtokenrightparentokenrightbrackettokencolontokenternarytokenboolkeywordbytekeywordfloat32keywordfloat64keywordintkeywordint8keywordint16keywordint32keywordint64keyworduintkeyworduint8keyworduint16keyworduint32keyworduint64keyworduintptrkeywordnilkeyword" var _tokenkind_index = [...]uint16{0, 8, 16, 24, 34, 42, 52, 61, 69, 78, 86, 94, 102, 110, 118, 126, 134, 141, 149, 157, 165, 176, 191, 205, 215, 226, 238, 251, 267, 284, 298, 314, 324, 335, 350, 367, 377, 389, 400, 411, 425, 439, 449, 460, 472, 484, 496, 507, 519, 532, 545, 558, 572, 582} func (i tokenkind) String() string { if i < 0 || i >= tokenkind(len(_tokenkind_index)-1) { return "tokenkind(" + strconv.FormatInt(int64(i), 10) + ")" } return _tokenkind_name[_tokenkind_index[i]:_tokenkind_index[i+1]] } golang-github-go-restruct-restruct-1.2.0-alpha/expr/type.go000066400000000000000000000305561412231745000237470ustar00rootroot00000000000000package expr import ( "errors" "fmt" "reflect" "sync" ) var ( primType = map[reflect.Kind]Type{ reflect.Bool: NewPrimitiveType(Bool), reflect.Int: NewPrimitiveType(Int), reflect.Int8: NewPrimitiveType(Int8), reflect.Int16: NewPrimitiveType(Int16), reflect.Int32: NewPrimitiveType(Int32), reflect.Int64: NewPrimitiveType(Int64), reflect.Uint: NewPrimitiveType(Uint), reflect.Uint8: NewPrimitiveType(Uint8), reflect.Uint16: NewPrimitiveType(Uint16), reflect.Uint32: NewPrimitiveType(Uint32), reflect.Uint64: NewPrimitiveType(Uint64), reflect.Uintptr: NewPrimitiveType(Uintptr), reflect.Float32: NewPrimitiveType(Float32), reflect.Float64: NewPrimitiveType(Float64), reflect.String: NewPrimitiveType(String), } primRType = map[Kind]reflect.Type{ Bool: reflect.TypeOf(bool(false)), Int: reflect.TypeOf(int(0)), Int8: reflect.TypeOf(int8(0)), Int16: reflect.TypeOf(int16(0)), Int32: reflect.TypeOf(int32(0)), Int64: reflect.TypeOf(int64(0)), Uint: reflect.TypeOf(uint(0)), Uint8: reflect.TypeOf(uint8(0)), Uint16: reflect.TypeOf(uint16(0)), Uint32: reflect.TypeOf(uint32(0)), Uint64: reflect.TypeOf(uint64(0)), Uintptr: reflect.TypeOf(uintptr(0)), Float32: reflect.TypeOf(float32(0)), Float64: reflect.TypeOf(float64(0)), String: reflect.TypeOf(string("")), } // ErrInvalidKind occurs when you call an inappropriate method for a given kind. ErrInvalidKind = errors.New("invalid kind") // ErrNotRepresentable occurs when a type is encountered that is not supported by the language. ErrNotRepresentable = errors.New("type cannot be represented") // ErrUntypedNil occurs when an untyped nil is used inappropriately. ErrUntypedNil = errors.New("untyped nil value") ) // NoSuchFieldError is returned when an unknown field is accessed. type NoSuchFieldError struct { field string } func (err NoSuchFieldError) Error() string { return fmt.Sprintf("no such field: %s", err.field) } // Kind is the most basic type descriptor. type Kind int // Enumeration of valid kinds of types. const ( Invalid Kind = iota // Primitives Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 String // Untyped constants UntypedBool UntypedInt UntypedFloat UntypedNil // Composite types Array Slice Struct Map Ptr Func Pkg ) // Type is the representation of an expr type. type Type interface { Kind() Kind String() string } // PrimitiveType is the type of primitives. type PrimitiveType struct { kind Kind } // NewPrimitiveType returns a new primitive type. func NewPrimitiveType(k Kind) Type { if k < Bool || k > String { panic("not a primitive kind") } return &PrimitiveType{kind: k} } // String implements Type. func (t PrimitiveType) String() string { switch t.kind { case Bool: return "bool" case Int: return "int" case Int8: return "int8" case Int16: return "int16" case Int32: return "int32" case Int64: return "int64" case Uint: return "uint" case Uint8: return "uint8" case Uint16: return "uint16" case Uint32: return "uint32" case Uint64: return "uint64" case Uintptr: return "uintptr" case Float32: return "float32" case Float64: return "float64" case String: return "string" default: return "" } } // Kind implements Type. func (t PrimitiveType) Kind() Kind { return t.kind } // littype is the type of literals. type littype struct { kind Kind } // NewLiteralType returns a new primitive type. func NewLiteralType(k Kind) Type { if k < UntypedBool || k > UntypedNil { panic("not a primitive kind") } return &littype{kind: k} } // String implements Type. func (t littype) String() string { switch t.kind { case UntypedBool: return "untyped bool constant" case UntypedInt: return "untyped int constant" case UntypedFloat: return "untyped float constant" case UntypedNil: return "untyped nil value" default: return "" } } func (t littype) Kind() Kind { return t.kind } // PackageType is the type of a package. type PackageType struct { symbols map[string]Type } // NewPackageType returns a new package with the given symbols. func NewPackageType(symbols map[string]Type) *PackageType { return &PackageType{symbols} } // String implements Type. func (PackageType) String() string { return "package" } // Kind implements Type. func (PackageType) Kind() Kind { return Pkg } // Symbol returns a symbol by the given name, or nil if none could be found. func (t PackageType) Symbol(ident string) Type { if s, ok := t.symbols[ident]; ok { return s } return nil } // ArrayType is the type of array-like values. type ArrayType struct { count int elem Type } // NewArrayType returns a new array type. func NewArrayType(count int, elem Type) *ArrayType { return &ArrayType{count: count, elem: elem} } // String implements Type. func (t ArrayType) String() string { return fmt.Sprintf("[%d]%s", t.count, t.elem.String()) } // Kind implements Type. func (ArrayType) Kind() Kind { return Array } // Elem is the type of element in the array. func (t ArrayType) Elem() Type { return t.elem } // Len is the length of the array. func (t ArrayType) Len() int { return t.count } // SliceType is the type of array-like values. type SliceType struct { elem Type } // NewSliceType returns a new array type. func NewSliceType(elem Type) *SliceType { return &SliceType{elem: elem} } // String implements Type. func (t SliceType) String() string { return "[]" + t.elem.String() } // Kind implements Type. func (SliceType) Kind() Kind { return Slice } // Elem is the type of element in the slice. func (t SliceType) Elem() Type { return t.elem } // MapType is the type of maps. type MapType struct { key, val Type } // NewMapType returns a new map type. func NewMapType(key Type, val Type) Type { return MapType{key: key, val: val} } // String implements Type. func (t MapType) String() string { return "map[" + t.key.String() + "]" + t.val.String() } // Kind implements Type. func (MapType) Kind() Kind { return Map } // Key is the type of the map's keys. func (t MapType) Key() Type { return t.key } // Value is the type of the map's values. func (t MapType) Value() Type { return t.val } // Field represents a struct field. type Field struct { Name string Type Type } // StructType is the type of struct values. type StructType struct { fields []Field fieldMap map[string]Field } // NewStructType returns a new struct type. func NewStructType(fields []Field) *StructType { fieldMap := map[string]Field{} for _, field := range fields { fieldMap[field.Name] = field } return &StructType{fields: fields, fieldMap: fieldMap} } // String implements Type. func (t StructType) String() string { return "struct" } // Kind implements Type. func (StructType) Kind() Kind { return Struct } // NumFields returns the number of fields in the struct. func (t StructType) NumFields() int { return len(t.fields) } // Field returns the nth field in the struct. func (t StructType) Field(i int) Field { return t.fields[i] } // FieldByName returns the field with the given name. func (t StructType) FieldByName(name string) (Field, bool) { f, ok := t.fieldMap[name] return f, ok } // PtrType is the type of pointers. type PtrType struct { elem Type } // NewPtrType returns a new pointer type. func NewPtrType(elem Type) *PtrType { return &PtrType{elem: elem} } // String implements Type. func (t PtrType) String() string { return "*" + t.elem.String() } // Kind implements Type. func (PtrType) Kind() Kind { return Ptr } // Elem returns the element being pointed to by the pointer. func (t PtrType) Elem() Type { return t.elem } // FuncType is the type of function values. type FuncType struct { in []Type out []Type variadic bool } // NewFuncType returns a new function type. func NewFuncType(in []Type, out []Type, variadic bool) *FuncType { return &FuncType{in: in, out: out, variadic: variadic} } // String implements Type. func (t FuncType) String() string { return "func" } // Kind implements Type. func (FuncType) Kind() Kind { return Func } // NumIn returns the number of input parameters. func (t FuncType) NumIn() int { return len(t.in) } // In gets the nth input parameter. func (t FuncType) In(i int) Type { return t.in[i] } // IsVariadic returns true for variadic functions. func (t FuncType) IsVariadic() bool { return t.variadic } // NumOut returns the number of output parameters. func (t FuncType) NumOut() int { return len(t.out) } // Out gets the nth output parameter. func (t FuncType) Out(i int) Type { return t.out[i] } // TypeEqual returns true if the two types are equal. func TypeEqual(a, b Type) bool { // TODO: this could be a bit more precise. return reflect.DeepEqual(a, b) } // toreflecttype converts an expr type into a runtime type. func toreflecttype(t Type) reflect.Type { switch t := t.(type) { case *PrimitiveType: return primRType[t.Kind()] case *ArrayType: return reflect.ArrayOf(t.Len(), toreflecttype(t.Elem())) case *SliceType: return reflect.SliceOf(toreflecttype(t.Elem())) case *StructType: fields := make([]reflect.StructField, 0, t.NumFields()) for i := 0; i < t.NumFields(); i++ { field := t.Field(i) fields = append(fields, reflect.StructField{ Name: field.Name, Type: toreflecttype(field.Type), }) } return reflect.StructOf(fields) case *MapType: return reflect.MapOf(toreflecttype(t.Key()), toreflecttype(t.Value())) case *PtrType: return reflect.PtrTo(toreflecttype(t.Elem())) case *FuncType: nin := t.NumIn() in := make([]reflect.Type, 0, nin) for i := 0; i < nin; i++ { in = append(in, toreflecttype(t.In(i))) } nout := t.NumOut() out := make([]reflect.Type, 0, nout) for i := 0; i < nout; i++ { out = append(out, toreflecttype(t.Out(i))) } return reflect.FuncOf(in, out, t.IsVariadic()) default: panic(ErrNotRepresentable) } } var typemap = map[reflect.Type]Type{} var typemutex = sync.Mutex{} func savetype(reflect reflect.Type, expr Type) Type { typemutex.Lock() defer typemutex.Unlock() typemap[reflect] = expr return expr } func loadtype(reflect reflect.Type) (Type, bool) { typemutex.Lock() defer typemutex.Unlock() if expr, ok := typemap[reflect]; ok { return expr, true } return nil, false } // fromreflecttype converts a runtime type into an expr type. func fromreflecttype(t reflect.Type) Type { if et, ok := loadtype(t); ok { return et } switch t.Kind() { case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64, reflect.String: return primType[t.Kind()] case reflect.Array: return NewArrayType(t.Len(), fromreflecttype(t.Elem())) case reflect.Func: nin := t.NumIn() in := make([]Type, 0, nin) for i := 0; i < nin; i++ { in = append(in, fromreflecttype(t.In(i))) } nout := t.NumOut() out := make([]Type, 0, nout) for i := 0; i < nout; i++ { out = append(out, fromreflecttype(t.Out(i))) } return NewFuncType(in, out, t.IsVariadic()) case reflect.Map: return NewMapType(fromreflecttype(t.Key()), fromreflecttype(t.Elem())) case reflect.Ptr: et := &PtrType{} savetype(t, et) *et = *NewPtrType(fromreflecttype(t.Elem())) return et case reflect.Slice: et := &SliceType{} savetype(t, et) *et = *NewSliceType(fromreflecttype(t.Elem())) return et case reflect.Struct: fields := make([]Field, 0, t.NumField()) for i := 0; i < t.NumField(); i++ { field := t.Field(i) fields = append(fields, Field{ Name: field.Name, Type: fromreflecttype(field.Type), }) } return NewStructType(fields) default: panic(ErrNotRepresentable) } } func assignable(from Type, to Type) bool { if TypeEqual(from, to) { return true } switch from.Kind() { case UntypedNil: switch to.Kind() { case Ptr, Func, Slice, Map: return true } case UntypedBool: switch to.Kind() { case Bool: return true } case UntypedInt: // TODO: Range and overflow checks. switch to.Kind() { case Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr: return true case Float32, Float64: return true } case UntypedFloat: switch to.Kind() { case Float32, Float64: return true } } return false } // TypeOf returns the type of a runtime value. func TypeOf(i interface{}) Type { if pkg, ok := i.(Package); ok { return pkg.Type() } return fromreflecttype(reflect.TypeOf(i)) } golang-github-go-restruct-restruct-1.2.0-alpha/expr/value.go000066400000000000000000000710741412231745000241020ustar00rootroot00000000000000package expr import ( "fmt" "reflect" ) // InvalidOpError is returned when an attempt is made to perform an operation // on a type that is not supported. type InvalidOpError struct { Op string V Value } func (e InvalidOpError) Error() string { return fmt.Sprintf("invalid operation: operator %s not defined for %v (%s)", e.Op, e.V.Value(), e.V.Type()) } // ConversionError is returned when an invalid type conversion is attempted. type ConversionError struct { From Type To Type } func (e ConversionError) Error() string { return fmt.Sprintf("cannot convert %s to %s", e.From, e.To) } // ReferenceError is returned when it is not possible to take the address of a // value. type ReferenceError struct{} func (e ReferenceError) Error() string { return "could not take reference of value" } // Value represents a value at runtime. type Value interface { Type() Type Value() reflect.Value RawValue() interface{} Negate() Value Not() Value BitNot() Value Deref() Value Ref() Value Dot(ident string) Value LogicalOr(rhs Value) Value LogicalAnd(rhs Value) Value Equal(rhs Value) Value NotEqual(rhs Value) Value Lesser(rhs Value) Value LesserEqual(rhs Value) Value Greater(rhs Value) Value GreaterEqual(rhs Value) Value Add(rhs Value) Value Sub(rhs Value) Value Or(rhs Value) Value Xor(rhs Value) Value Mul(rhs Value) Value Div(rhs Value) Value Rem(rhs Value) Value Lsh(rhs Value) Value Rsh(rhs Value) Value And(rhs Value) Value AndNot(rhs Value) Value Index(rhs Value) Value Call(in []Value) Value } type val struct { v reflect.Value t Type } func promote(from Value, to Type) Value { if TypeEqual(from.Type(), to) { return from } ftype := from.Type() switch ftype.Kind() { case UntypedBool: switch to.Kind() { case Bool: return val{from.Value(), to} default: panic(ConversionError{From: ftype, To: to}) } case UntypedFloat: switch to.Kind() { case Float32: return val{reflect.ValueOf(float32(reflect.ValueOf(from.Value).Float())), to} case Float64: return val{reflect.ValueOf(float64(reflect.ValueOf(from.Value).Float())), to} default: panic(ConversionError{From: ftype, To: to}) } case UntypedInt: ival, uval, fval := int64(0), uint64(0), float64(0) switch n := from.RawValue().(type) { case int64: ival = int64(n) uval = uint64(n) fval = float64(n) case uint64: ival = int64(n) uval = uint64(n) fval = float64(n) } switch to.Kind() { case Int: return val{reflect.ValueOf(int(ival)), to} case Int8: return val{reflect.ValueOf(int8(ival)), to} case Int16: return val{reflect.ValueOf(int16(ival)), to} case Int32: return val{reflect.ValueOf(int32(ival)), to} case Int64: return val{reflect.ValueOf(int64(ival)), to} case Uint: return val{reflect.ValueOf(uint(uval)), to} case Uint8: return val{reflect.ValueOf(uint8(uval)), to} case Uint16: return val{reflect.ValueOf(uint16(uval)), to} case Uint32: return val{reflect.ValueOf(uint32(uval)), to} case Uint64: return val{reflect.ValueOf(uint64(uval)), to} case Uintptr: return val{reflect.ValueOf(uintptr(uval)), to} case Float32: return val{reflect.ValueOf(float32(fval)), to} case Float64: return val{reflect.ValueOf(float64(fval)), to} default: panic(ConversionError{From: ftype, To: to}) } case UntypedNil: return val{reflect.Zero(toreflecttype(to)), to} default: panic(ConversionError{From: ftype, To: to}) } } func coerce1(v Value) Value { if v.Type().Kind() == UntypedInt { switch n := v.RawValue().(type) { case uint64: return val{reflect.ValueOf(int(n)), NewPrimitiveType(Int)} case int64: return val{reflect.ValueOf(int(n)), NewPrimitiveType(Int)} } } return v } func coerce(lhs Value, rhs Value) (Value, Value) { if TypeEqual(lhs.Type(), rhs.Type()) { return coerce1(lhs), coerce1(rhs) } else if assignable(lhs.Type(), rhs.Type()) { return promote(lhs, rhs.Type()), rhs } else if assignable(rhs.Type(), lhs.Type()) { return lhs, promote(rhs, lhs.Type()) } panic(ConversionError{From: lhs.Type(), To: rhs.Type()}) } func (v val) Type() Type { return v.t } func (v val) Value() reflect.Value { return v.v } func (v val) RawValue() interface{} { return v.v.Interface() } func (v val) Negate() Value { switch n := v.RawValue().(type) { case int: return val{reflect.ValueOf(-n), v.t} case int8: return val{reflect.ValueOf(-n), v.t} case int16: return val{reflect.ValueOf(-n), v.t} case int32: return val{reflect.ValueOf(-n), v.t} case int64: return val{reflect.ValueOf(-n), v.t} case uint: return val{reflect.ValueOf(-n), v.t} case uint8: return val{reflect.ValueOf(-n), v.t} case uint16: return val{reflect.ValueOf(-n), v.t} case uint32: return val{reflect.ValueOf(-n), v.t} case uint64: return val{reflect.ValueOf(-n), v.t} case uintptr: return val{reflect.ValueOf(-n), v.t} case float32: return val{reflect.ValueOf(-n), v.t} case float64: return val{reflect.ValueOf(-n), v.t} default: panic(InvalidOpError{Op: "-", V: v}) } } func (v val) Not() Value { switch n := v.RawValue().(type) { case bool: return val{reflect.ValueOf(!n), v.t} default: panic(InvalidOpError{Op: "!", V: v}) } } func (v val) BitNot() Value { switch n := v.RawValue().(type) { case int: return val{reflect.ValueOf(^n), v.t} case int8: return val{reflect.ValueOf(^n), v.t} case int16: return val{reflect.ValueOf(^n), v.t} case int32: return val{reflect.ValueOf(^n), v.t} case int64: return val{reflect.ValueOf(^n), v.t} case uint: return val{reflect.ValueOf(^n), v.t} case uint8: return val{reflect.ValueOf(^n), v.t} case uint16: return val{reflect.ValueOf(^n), v.t} case uint32: return val{reflect.ValueOf(^n), v.t} case uint64: return val{reflect.ValueOf(^n), v.t} case uintptr: return val{reflect.ValueOf(^n), v.t} default: panic(InvalidOpError{Op: "^", V: v}) } } func (v val) Deref() Value { ptrtype, ok := v.t.(*PtrType) if !ok { panic(InvalidOpError{Op: "*", V: v}) } return val{v.v.Elem(), ptrtype.Elem()} } func (v val) Ref() Value { if !v.v.CanAddr() { panic(ReferenceError{}) } return val{v.v.Addr(), NewPtrType(v.t)} } func (v val) Dot(ident string) Value { switch v.t.(type) { case *PackageType: if sv := v.RawValue().(Package).Symbol(ident); sv != nil { return sv } case *StructType: if sv := v.v.FieldByName(ident); sv.IsValid() { return val{sv, TypeOf(sv.Interface())} } case *PtrType: return v.Deref().Dot(ident) } panic(InvalidOpError{Op: ".", V: v}) } func (v val) LogicalOr(rhs Value) Value { lv, ok := v.RawValue().(bool) if !ok { panic(InvalidOpError{Op: "||", V: v}) } rv, ok := rhs.RawValue().(bool) if !ok { panic(InvalidOpError{Op: "||", V: rhs}) } return val{reflect.ValueOf(lv || rv), NewPrimitiveType(Bool)} } func (v val) LogicalAnd(rhs Value) Value { lv, ok := v.RawValue().(bool) if !ok { panic(InvalidOpError{Op: "&&", V: v}) } rv, ok := rhs.RawValue().(bool) if !ok { panic(InvalidOpError{Op: "&&", V: rhs}) } return val{reflect.ValueOf(lv && rv), NewPrimitiveType(Bool)} } func (v val) Equal(rhs Value) Value { l, r := coerce(v, rhs) return val{reflect.ValueOf(l.RawValue() == r.RawValue()), NewPrimitiveType(Bool)} } func (v val) NotEqual(rhs Value) Value { l, r := coerce(v, rhs) return val{reflect.ValueOf(l.RawValue() != r.RawValue()), NewPrimitiveType(Bool)} } func (v val) Lesser(rhs Value) Value { l, r := coerce(v, rhs) switch lv := l.RawValue().(type) { case int: return val{reflect.ValueOf(lv < r.RawValue().(int)), NewPrimitiveType(Bool)} case int8: return val{reflect.ValueOf(lv < r.RawValue().(int8)), NewPrimitiveType(Bool)} case int16: return val{reflect.ValueOf(lv < r.RawValue().(int16)), NewPrimitiveType(Bool)} case int32: return val{reflect.ValueOf(lv < r.RawValue().(int32)), NewPrimitiveType(Bool)} case int64: return val{reflect.ValueOf(lv < r.RawValue().(int64)), NewPrimitiveType(Bool)} case uint: return val{reflect.ValueOf(lv < r.RawValue().(uint)), NewPrimitiveType(Bool)} case uint8: return val{reflect.ValueOf(lv < r.RawValue().(uint8)), NewPrimitiveType(Bool)} case uint16: return val{reflect.ValueOf(lv < r.RawValue().(uint16)), NewPrimitiveType(Bool)} case uint32: return val{reflect.ValueOf(lv < r.RawValue().(uint32)), NewPrimitiveType(Bool)} case uint64: return val{reflect.ValueOf(lv < r.RawValue().(uint64)), NewPrimitiveType(Bool)} case uintptr: return val{reflect.ValueOf(lv < r.RawValue().(uintptr)), NewPrimitiveType(Bool)} case float32: return val{reflect.ValueOf(lv < r.RawValue().(float32)), NewPrimitiveType(Bool)} case float64: return val{reflect.ValueOf(lv < r.RawValue().(float64)), NewPrimitiveType(Bool)} default: panic(InvalidOpError{Op: "<", V: l}) } } func (v val) LesserEqual(rhs Value) Value { l, r := coerce(v, rhs) switch lv := l.RawValue().(type) { case int: return val{reflect.ValueOf(lv <= r.RawValue().(int)), NewPrimitiveType(Bool)} case int8: return val{reflect.ValueOf(lv <= r.RawValue().(int8)), NewPrimitiveType(Bool)} case int16: return val{reflect.ValueOf(lv <= r.RawValue().(int16)), NewPrimitiveType(Bool)} case int32: return val{reflect.ValueOf(lv <= r.RawValue().(int32)), NewPrimitiveType(Bool)} case int64: return val{reflect.ValueOf(lv <= r.RawValue().(int64)), NewPrimitiveType(Bool)} case uint: return val{reflect.ValueOf(lv <= r.RawValue().(uint)), NewPrimitiveType(Bool)} case uint8: return val{reflect.ValueOf(lv <= r.RawValue().(uint8)), NewPrimitiveType(Bool)} case uint16: return val{reflect.ValueOf(lv <= r.RawValue().(uint16)), NewPrimitiveType(Bool)} case uint32: return val{reflect.ValueOf(lv <= r.RawValue().(uint32)), NewPrimitiveType(Bool)} case uint64: return val{reflect.ValueOf(lv <= r.RawValue().(uint64)), NewPrimitiveType(Bool)} case uintptr: return val{reflect.ValueOf(lv <= r.RawValue().(uintptr)), NewPrimitiveType(Bool)} case float32: return val{reflect.ValueOf(lv <= r.RawValue().(float32)), NewPrimitiveType(Bool)} case float64: return val{reflect.ValueOf(lv <= r.RawValue().(float64)), NewPrimitiveType(Bool)} default: panic(InvalidOpError{Op: "<=", V: l}) } } func (v val) Greater(rhs Value) Value { l, r := coerce(v, rhs) switch lv := l.RawValue().(type) { case int: return val{reflect.ValueOf(lv > r.RawValue().(int)), NewPrimitiveType(Bool)} case int8: return val{reflect.ValueOf(lv > r.RawValue().(int8)), NewPrimitiveType(Bool)} case int16: return val{reflect.ValueOf(lv > r.RawValue().(int16)), NewPrimitiveType(Bool)} case int32: return val{reflect.ValueOf(lv > r.RawValue().(int32)), NewPrimitiveType(Bool)} case int64: return val{reflect.ValueOf(lv > r.RawValue().(int64)), NewPrimitiveType(Bool)} case uint: return val{reflect.ValueOf(lv > r.RawValue().(uint)), NewPrimitiveType(Bool)} case uint8: return val{reflect.ValueOf(lv > r.RawValue().(uint8)), NewPrimitiveType(Bool)} case uint16: return val{reflect.ValueOf(lv > r.RawValue().(uint16)), NewPrimitiveType(Bool)} case uint32: return val{reflect.ValueOf(lv > r.RawValue().(uint32)), NewPrimitiveType(Bool)} case uint64: return val{reflect.ValueOf(lv > r.RawValue().(uint64)), NewPrimitiveType(Bool)} case uintptr: return val{reflect.ValueOf(lv > r.RawValue().(uintptr)), NewPrimitiveType(Bool)} case float32: return val{reflect.ValueOf(lv > r.RawValue().(float32)), NewPrimitiveType(Bool)} case float64: return val{reflect.ValueOf(lv > r.RawValue().(float64)), NewPrimitiveType(Bool)} default: panic(InvalidOpError{Op: ">", V: l}) } } func (v val) GreaterEqual(rhs Value) Value { l, r := coerce(v, rhs) switch lv := l.RawValue().(type) { case int: return val{reflect.ValueOf(lv >= r.RawValue().(int)), NewPrimitiveType(Bool)} case int8: return val{reflect.ValueOf(lv >= r.RawValue().(int8)), NewPrimitiveType(Bool)} case int16: return val{reflect.ValueOf(lv >= r.RawValue().(int16)), NewPrimitiveType(Bool)} case int32: return val{reflect.ValueOf(lv >= r.RawValue().(int32)), NewPrimitiveType(Bool)} case int64: return val{reflect.ValueOf(lv >= r.RawValue().(int64)), NewPrimitiveType(Bool)} case uint: return val{reflect.ValueOf(lv >= r.RawValue().(uint)), NewPrimitiveType(Bool)} case uint8: return val{reflect.ValueOf(lv >= r.RawValue().(uint8)), NewPrimitiveType(Bool)} case uint16: return val{reflect.ValueOf(lv >= r.RawValue().(uint16)), NewPrimitiveType(Bool)} case uint32: return val{reflect.ValueOf(lv >= r.RawValue().(uint32)), NewPrimitiveType(Bool)} case uint64: return val{reflect.ValueOf(lv >= r.RawValue().(uint64)), NewPrimitiveType(Bool)} case uintptr: return val{reflect.ValueOf(lv >= r.RawValue().(uintptr)), NewPrimitiveType(Bool)} case float32: return val{reflect.ValueOf(lv >= r.RawValue().(float32)), NewPrimitiveType(Bool)} case float64: return val{reflect.ValueOf(lv >= r.RawValue().(float64)), NewPrimitiveType(Bool)} default: panic(InvalidOpError{Op: ">=", V: l}) } } func (v val) Add(rhs Value) Value { l, r := coerce(v, rhs) switch lv := l.RawValue().(type) { case int: return val{reflect.ValueOf(lv + r.RawValue().(int)), NewPrimitiveType(Int)} case int8: return val{reflect.ValueOf(lv + r.RawValue().(int8)), NewPrimitiveType(Int8)} case int16: return val{reflect.ValueOf(lv + r.RawValue().(int16)), NewPrimitiveType(Int16)} case int32: return val{reflect.ValueOf(lv + r.RawValue().(int32)), NewPrimitiveType(Int32)} case int64: return val{reflect.ValueOf(lv + r.RawValue().(int64)), NewPrimitiveType(Int64)} case uint: return val{reflect.ValueOf(lv + r.RawValue().(uint)), NewPrimitiveType(Uint)} case uint8: return val{reflect.ValueOf(lv + r.RawValue().(uint8)), NewPrimitiveType(Uint8)} case uint16: return val{reflect.ValueOf(lv + r.RawValue().(uint16)), NewPrimitiveType(Uint16)} case uint32: return val{reflect.ValueOf(lv + r.RawValue().(uint32)), NewPrimitiveType(Uint32)} case uint64: return val{reflect.ValueOf(lv + r.RawValue().(uint64)), NewPrimitiveType(Uint64)} case uintptr: return val{reflect.ValueOf(lv + r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} case float32: return val{reflect.ValueOf(lv + r.RawValue().(float32)), NewPrimitiveType(Float32)} case float64: return val{reflect.ValueOf(lv + r.RawValue().(float64)), NewPrimitiveType(Float64)} case string: return val{reflect.ValueOf(lv + r.RawValue().(string)), NewPrimitiveType(String)} default: panic(InvalidOpError{Op: "+", V: l}) } } func (v val) Sub(rhs Value) Value { l, r := coerce(v, rhs) switch lv := l.RawValue().(type) { case int: return val{reflect.ValueOf(lv - r.RawValue().(int)), NewPrimitiveType(Int)} case int8: return val{reflect.ValueOf(lv - r.RawValue().(int8)), NewPrimitiveType(Int8)} case int16: return val{reflect.ValueOf(lv - r.RawValue().(int16)), NewPrimitiveType(Int16)} case int32: return val{reflect.ValueOf(lv - r.RawValue().(int32)), NewPrimitiveType(Int32)} case int64: return val{reflect.ValueOf(lv - r.RawValue().(int64)), NewPrimitiveType(Int64)} case uint: return val{reflect.ValueOf(lv - r.RawValue().(uint)), NewPrimitiveType(Uint)} case uint8: return val{reflect.ValueOf(lv - r.RawValue().(uint8)), NewPrimitiveType(Uint8)} case uint16: return val{reflect.ValueOf(lv - r.RawValue().(uint16)), NewPrimitiveType(Uint16)} case uint32: return val{reflect.ValueOf(lv - r.RawValue().(uint32)), NewPrimitiveType(Uint32)} case uint64: return val{reflect.ValueOf(lv - r.RawValue().(uint64)), NewPrimitiveType(Uint64)} case uintptr: return val{reflect.ValueOf(lv - r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} case float32: return val{reflect.ValueOf(lv - r.RawValue().(float32)), NewPrimitiveType(Float32)} case float64: return val{reflect.ValueOf(lv - r.RawValue().(float64)), NewPrimitiveType(Float64)} default: panic(InvalidOpError{Op: "-", V: l}) } } func (v val) Or(rhs Value) Value { l, r := coerce(v, rhs) switch lv := l.RawValue().(type) { case int: return val{reflect.ValueOf(lv | r.RawValue().(int)), NewPrimitiveType(Int)} case int8: return val{reflect.ValueOf(lv | r.RawValue().(int8)), NewPrimitiveType(Int8)} case int16: return val{reflect.ValueOf(lv | r.RawValue().(int16)), NewPrimitiveType(Int16)} case int32: return val{reflect.ValueOf(lv | r.RawValue().(int32)), NewPrimitiveType(Int32)} case int64: return val{reflect.ValueOf(lv | r.RawValue().(int64)), NewPrimitiveType(Int64)} case uint: return val{reflect.ValueOf(lv | r.RawValue().(uint)), NewPrimitiveType(Uint)} case uint8: return val{reflect.ValueOf(lv | r.RawValue().(uint8)), NewPrimitiveType(Uint8)} case uint16: return val{reflect.ValueOf(lv | r.RawValue().(uint16)), NewPrimitiveType(Uint16)} case uint32: return val{reflect.ValueOf(lv | r.RawValue().(uint32)), NewPrimitiveType(Uint32)} case uint64: return val{reflect.ValueOf(lv | r.RawValue().(uint64)), NewPrimitiveType(Uint64)} case uintptr: return val{reflect.ValueOf(lv | r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} default: panic(InvalidOpError{Op: "|", V: l}) } } func (v val) Xor(rhs Value) Value { l, r := coerce(v, rhs) switch lv := l.RawValue().(type) { case int: return val{reflect.ValueOf(lv ^ r.RawValue().(int)), NewPrimitiveType(Int)} case int8: return val{reflect.ValueOf(lv ^ r.RawValue().(int8)), NewPrimitiveType(Int8)} case int16: return val{reflect.ValueOf(lv ^ r.RawValue().(int16)), NewPrimitiveType(Int16)} case int32: return val{reflect.ValueOf(lv ^ r.RawValue().(int32)), NewPrimitiveType(Int32)} case int64: return val{reflect.ValueOf(lv ^ r.RawValue().(int64)), NewPrimitiveType(Int64)} case uint: return val{reflect.ValueOf(lv ^ r.RawValue().(uint)), NewPrimitiveType(Uint)} case uint8: return val{reflect.ValueOf(lv ^ r.RawValue().(uint8)), NewPrimitiveType(Uint8)} case uint16: return val{reflect.ValueOf(lv ^ r.RawValue().(uint16)), NewPrimitiveType(Uint16)} case uint32: return val{reflect.ValueOf(lv ^ r.RawValue().(uint32)), NewPrimitiveType(Uint32)} case uint64: return val{reflect.ValueOf(lv ^ r.RawValue().(uint64)), NewPrimitiveType(Uint64)} case uintptr: return val{reflect.ValueOf(lv ^ r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} default: panic(InvalidOpError{Op: "^", V: l}) } } func (v val) Mul(rhs Value) Value { l, r := coerce(v, rhs) switch lv := l.RawValue().(type) { case int: return val{reflect.ValueOf(lv * r.RawValue().(int)), NewPrimitiveType(Int)} case int8: return val{reflect.ValueOf(lv * r.RawValue().(int8)), NewPrimitiveType(Int8)} case int16: return val{reflect.ValueOf(lv * r.RawValue().(int16)), NewPrimitiveType(Int16)} case int32: return val{reflect.ValueOf(lv * r.RawValue().(int32)), NewPrimitiveType(Int32)} case int64: return val{reflect.ValueOf(lv * r.RawValue().(int64)), NewPrimitiveType(Int64)} case uint: return val{reflect.ValueOf(lv * r.RawValue().(uint)), NewPrimitiveType(Uint)} case uint8: return val{reflect.ValueOf(lv * r.RawValue().(uint8)), NewPrimitiveType(Uint8)} case uint16: return val{reflect.ValueOf(lv * r.RawValue().(uint16)), NewPrimitiveType(Uint16)} case uint32: return val{reflect.ValueOf(lv * r.RawValue().(uint32)), NewPrimitiveType(Uint32)} case uint64: return val{reflect.ValueOf(lv * r.RawValue().(uint64)), NewPrimitiveType(Uint64)} case uintptr: return val{reflect.ValueOf(lv * r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} case float32: return val{reflect.ValueOf(lv * r.RawValue().(float32)), NewPrimitiveType(Float32)} case float64: return val{reflect.ValueOf(lv * r.RawValue().(float64)), NewPrimitiveType(Float64)} default: panic(InvalidOpError{Op: "*", V: l}) } } func (v val) Div(rhs Value) Value { l, r := coerce(v, rhs) switch lv := l.RawValue().(type) { case int: return val{reflect.ValueOf(lv / r.RawValue().(int)), NewPrimitiveType(Int)} case int8: return val{reflect.ValueOf(lv / r.RawValue().(int8)), NewPrimitiveType(Int8)} case int16: return val{reflect.ValueOf(lv / r.RawValue().(int16)), NewPrimitiveType(Int16)} case int32: return val{reflect.ValueOf(lv / r.RawValue().(int32)), NewPrimitiveType(Int32)} case int64: return val{reflect.ValueOf(lv / r.RawValue().(int64)), NewPrimitiveType(Int64)} case uint: return val{reflect.ValueOf(lv / r.RawValue().(uint)), NewPrimitiveType(Uint)} case uint8: return val{reflect.ValueOf(lv / r.RawValue().(uint8)), NewPrimitiveType(Uint8)} case uint16: return val{reflect.ValueOf(lv / r.RawValue().(uint16)), NewPrimitiveType(Uint16)} case uint32: return val{reflect.ValueOf(lv / r.RawValue().(uint32)), NewPrimitiveType(Uint32)} case uint64: return val{reflect.ValueOf(lv / r.RawValue().(uint64)), NewPrimitiveType(Uint64)} case uintptr: return val{reflect.ValueOf(lv / r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} case float32: return val{reflect.ValueOf(lv / r.RawValue().(float32)), NewPrimitiveType(Float32)} case float64: return val{reflect.ValueOf(lv / r.RawValue().(float64)), NewPrimitiveType(Float64)} default: panic(InvalidOpError{Op: "/", V: l}) } } func (v val) Rem(rhs Value) Value { l, r := coerce(v, rhs) switch lv := l.RawValue().(type) { case int: return val{reflect.ValueOf(lv % r.RawValue().(int)), NewPrimitiveType(Int)} case int8: return val{reflect.ValueOf(lv % r.RawValue().(int8)), NewPrimitiveType(Int8)} case int16: return val{reflect.ValueOf(lv % r.RawValue().(int16)), NewPrimitiveType(Int16)} case int32: return val{reflect.ValueOf(lv % r.RawValue().(int32)), NewPrimitiveType(Int32)} case int64: return val{reflect.ValueOf(lv % r.RawValue().(int64)), NewPrimitiveType(Int64)} case uint: return val{reflect.ValueOf(lv % r.RawValue().(uint)), NewPrimitiveType(Uint)} case uint8: return val{reflect.ValueOf(lv % r.RawValue().(uint8)), NewPrimitiveType(Uint8)} case uint16: return val{reflect.ValueOf(lv % r.RawValue().(uint16)), NewPrimitiveType(Uint16)} case uint32: return val{reflect.ValueOf(lv % r.RawValue().(uint32)), NewPrimitiveType(Uint32)} case uint64: return val{reflect.ValueOf(lv % r.RawValue().(uint64)), NewPrimitiveType(Uint64)} case uintptr: return val{reflect.ValueOf(lv % r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} default: panic(InvalidOpError{Op: "%", V: l}) } } func (v val) Lsh(rhs Value) Value { l := coerce1(v) shift := uint64(0) switch rv := rhs.RawValue().(type) { case uint: shift = uint64(rv) case uint8: shift = uint64(rv) case uint16: shift = uint64(rv) case uint32: shift = uint64(rv) case uint64: shift = uint64(rv) case uintptr: shift = uint64(rv) default: panic(InvalidOpError{Op: "<<", V: rhs}) } switch lv := l.RawValue().(type) { case int: return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Int)} case int8: return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Int8)} case int16: return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Int16)} case int32: return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Int32)} case int64: return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Int64)} case uint: return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uint)} case uint8: return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uint8)} case uint16: return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uint16)} case uint32: return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uint32)} case uint64: return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uint64)} case uintptr: return val{reflect.ValueOf(lv << shift), NewPrimitiveType(Uintptr)} default: panic(InvalidOpError{Op: "<<", V: l}) } } func (v val) Rsh(rhs Value) Value { l := coerce1(v) shift := uint64(0) switch rv := rhs.RawValue().(type) { case uint: shift = uint64(rv) case uint8: shift = uint64(rv) case uint16: shift = uint64(rv) case uint32: shift = uint64(rv) case uint64: shift = uint64(rv) case uintptr: shift = uint64(rv) default: panic(InvalidOpError{Op: ">>", V: rhs}) } switch lv := l.RawValue().(type) { case int: return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Int)} case int8: return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Int8)} case int16: return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Int16)} case int32: return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Int32)} case int64: return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Int64)} case uint: return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uint)} case uint8: return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uint8)} case uint16: return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uint16)} case uint32: return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uint32)} case uint64: return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uint64)} case uintptr: return val{reflect.ValueOf(lv >> shift), NewPrimitiveType(Uintptr)} default: panic(InvalidOpError{Op: ">>", V: l}) } } func (v val) And(rhs Value) Value { l, r := coerce(v, rhs) switch lv := l.RawValue().(type) { case int: return val{reflect.ValueOf(lv & r.RawValue().(int)), NewPrimitiveType(Int)} case int8: return val{reflect.ValueOf(lv & r.RawValue().(int8)), NewPrimitiveType(Int8)} case int16: return val{reflect.ValueOf(lv & r.RawValue().(int16)), NewPrimitiveType(Int16)} case int32: return val{reflect.ValueOf(lv & r.RawValue().(int32)), NewPrimitiveType(Int32)} case int64: return val{reflect.ValueOf(lv & r.RawValue().(int64)), NewPrimitiveType(Int64)} case uint: return val{reflect.ValueOf(lv & r.RawValue().(uint)), NewPrimitiveType(Uint)} case uint8: return val{reflect.ValueOf(lv & r.RawValue().(uint8)), NewPrimitiveType(Uint8)} case uint16: return val{reflect.ValueOf(lv & r.RawValue().(uint16)), NewPrimitiveType(Uint16)} case uint32: return val{reflect.ValueOf(lv & r.RawValue().(uint32)), NewPrimitiveType(Uint32)} case uint64: return val{reflect.ValueOf(lv & r.RawValue().(uint64)), NewPrimitiveType(Uint64)} case uintptr: return val{reflect.ValueOf(lv & r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} default: panic(InvalidOpError{Op: "&", V: l}) } } func (v val) AndNot(rhs Value) Value { l, r := coerce(v, rhs) switch lv := l.RawValue().(type) { case int: return val{reflect.ValueOf(lv &^ r.RawValue().(int)), NewPrimitiveType(Int)} case int8: return val{reflect.ValueOf(lv &^ r.RawValue().(int8)), NewPrimitiveType(Int8)} case int16: return val{reflect.ValueOf(lv &^ r.RawValue().(int16)), NewPrimitiveType(Int16)} case int32: return val{reflect.ValueOf(lv &^ r.RawValue().(int32)), NewPrimitiveType(Int32)} case int64: return val{reflect.ValueOf(lv &^ r.RawValue().(int64)), NewPrimitiveType(Int64)} case uint: return val{reflect.ValueOf(lv &^ r.RawValue().(uint)), NewPrimitiveType(Uint)} case uint8: return val{reflect.ValueOf(lv &^ r.RawValue().(uint8)), NewPrimitiveType(Uint8)} case uint16: return val{reflect.ValueOf(lv &^ r.RawValue().(uint16)), NewPrimitiveType(Uint16)} case uint32: return val{reflect.ValueOf(lv &^ r.RawValue().(uint32)), NewPrimitiveType(Uint32)} case uint64: return val{reflect.ValueOf(lv &^ r.RawValue().(uint64)), NewPrimitiveType(Uint64)} case uintptr: return val{reflect.ValueOf(lv &^ r.RawValue().(uintptr)), NewPrimitiveType(Uintptr)} default: panic(InvalidOpError{Op: "&^", V: l}) } } func (v val) Index(rhs Value) Value { if v.t.Kind() == String { index := promote(rhs, NewPrimitiveType(Int)).RawValue().(int) return val{reflect.ValueOf(v.RawValue().(string)[index]), NewPrimitiveType(Uint8)} } switch t := v.t.(type) { case *ArrayType: return val{v.v.Index(promote(rhs, NewPrimitiveType(Int)).RawValue().(int)), t.Elem()} case *SliceType: return val{v.v.Index(promote(rhs, NewPrimitiveType(Int)).RawValue().(int)), t.Elem()} case *MapType: return val{v.v.MapIndex(promote(rhs, t.Key()).Value()), t.Value()} default: panic(InvalidOpError{Op: "[]", V: v}) } } func (v val) Call(in []Value) Value { ft, ok := v.t.(*FuncType) if !ok { panic("Call invoked on non-function") } if len(in) != ft.NumIn() { panic("invalid number of arguments to function") } inconv := []reflect.Value{} for i, n := range in { inconv = append(inconv, promote(n, ft.In(i)).Value()) } out := v.v.Call(inconv) if len(out) != 1 { panic("only functions returning 1 value are supported") } return val{out[0], ft.Out(0)} } // ValueOf returns a Value for the given runtime value. func ValueOf(i interface{}) Value { return val{reflect.ValueOf(i), TypeOf(i)} } func literalboolval(v bool) Value { return val{reflect.ValueOf(v), NewLiteralType(UntypedBool)} } func literalstrval(v string) Value { return val{reflect.ValueOf(v), NewPrimitiveType(String)} } func literalintval(v int64) Value { return val{reflect.ValueOf(v), NewLiteralType(UntypedInt)} } func literaluintval(v uint64) Value { return val{reflect.ValueOf(v), NewLiteralType(UntypedInt)} } func literalfloatval(v float64) Value { return val{reflect.ValueOf(v), NewLiteralType(UntypedFloat)} } func literalnilval() Value { return val{reflect.ValueOf(interface{}(nil)), NewLiteralType(UntypedNil)} } golang-github-go-restruct-restruct-1.2.0-alpha/expr/value_test.go000066400000000000000000000244661412231745000251440ustar00rootroot00000000000000package expr import ( "testing" "github.com/stretchr/testify/assert" ) func TestValueBasicCompare(t *testing.T) { assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int(10)).Add(ValueOf(int(20))).Equal(ValueOf(int(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int8(10)).Add(ValueOf(int8(20))).Equal(ValueOf(int8(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int16(10)).Add(ValueOf(int16(20))).Equal(ValueOf(int16(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int32(10)).Add(ValueOf(int32(20))).Equal(ValueOf(int32(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int64(10)).Add(ValueOf(int64(20))).Equal(ValueOf(int64(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint(10)).Add(ValueOf(uint(20))).Equal(ValueOf(uint(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint8(10)).Add(ValueOf(uint8(20))).Equal(ValueOf(uint8(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint16(10)).Add(ValueOf(uint16(20))).Equal(ValueOf(uint16(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint32(10)).Add(ValueOf(uint32(20))).Equal(ValueOf(uint32(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint64(10)).Add(ValueOf(uint64(20))).Equal(ValueOf(uint64(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uintptr(10)).Add(ValueOf(uintptr(20))).Equal(ValueOf(uintptr(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(float32(10)).Add(ValueOf(float32(20))).Equal(ValueOf(float32(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(float64(10)).Add(ValueOf(float64(20))).Equal(ValueOf(float64(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int(15)).Add(ValueOf(int(20))).Equal(ValueOf(int(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int8(15)).Add(ValueOf(int8(20))).Equal(ValueOf(int8(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int16(15)).Add(ValueOf(int16(20))).Equal(ValueOf(int16(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int32(15)).Add(ValueOf(int32(20))).Equal(ValueOf(int32(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int64(15)).Add(ValueOf(int64(20))).Equal(ValueOf(int64(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint(15)).Add(ValueOf(uint(20))).Equal(ValueOf(uint(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint8(15)).Add(ValueOf(uint8(20))).Equal(ValueOf(uint8(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint16(15)).Add(ValueOf(uint16(20))).Equal(ValueOf(uint16(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint32(15)).Add(ValueOf(uint32(20))).Equal(ValueOf(uint32(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint64(15)).Add(ValueOf(uint64(20))).Equal(ValueOf(uint64(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uintptr(15)).Add(ValueOf(uintptr(20))).Equal(ValueOf(uintptr(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(float32(15)).Add(ValueOf(float32(20))).Equal(ValueOf(float32(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(float64(15)).Add(ValueOf(float64(20))).Equal(ValueOf(float64(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int(10)).Add(ValueOf(int(20))).NotEqual(ValueOf(int(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int8(10)).Add(ValueOf(int8(20))).NotEqual(ValueOf(int8(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int16(10)).Add(ValueOf(int16(20))).NotEqual(ValueOf(int16(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int32(10)).Add(ValueOf(int32(20))).NotEqual(ValueOf(int32(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(int64(10)).Add(ValueOf(int64(20))).NotEqual(ValueOf(int64(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint(10)).Add(ValueOf(uint(20))).NotEqual(ValueOf(uint(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint8(10)).Add(ValueOf(uint8(20))).NotEqual(ValueOf(uint8(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint16(10)).Add(ValueOf(uint16(20))).NotEqual(ValueOf(uint16(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint32(10)).Add(ValueOf(uint32(20))).NotEqual(ValueOf(uint32(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uint64(10)).Add(ValueOf(uint64(20))).NotEqual(ValueOf(uint64(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(uintptr(10)).Add(ValueOf(uintptr(20))).NotEqual(ValueOf(uintptr(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(float32(10)).Add(ValueOf(float32(20))).NotEqual(ValueOf(float32(30))).RawValue()) assert.Equal(t, ValueOf(false).RawValue(), ValueOf(float64(10)).Add(ValueOf(float64(20))).NotEqual(ValueOf(float64(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int(15)).Add(ValueOf(int(20))).NotEqual(ValueOf(int(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int8(15)).Add(ValueOf(int8(20))).NotEqual(ValueOf(int8(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int16(15)).Add(ValueOf(int16(20))).NotEqual(ValueOf(int16(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int32(15)).Add(ValueOf(int32(20))).NotEqual(ValueOf(int32(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(int64(15)).Add(ValueOf(int64(20))).NotEqual(ValueOf(int64(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint(15)).Add(ValueOf(uint(20))).NotEqual(ValueOf(uint(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint8(15)).Add(ValueOf(uint8(20))).NotEqual(ValueOf(uint8(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint16(15)).Add(ValueOf(uint16(20))).NotEqual(ValueOf(uint16(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint32(15)).Add(ValueOf(uint32(20))).NotEqual(ValueOf(uint32(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uint64(15)).Add(ValueOf(uint64(20))).NotEqual(ValueOf(uint64(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(uintptr(15)).Add(ValueOf(uintptr(20))).NotEqual(ValueOf(uintptr(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(float32(15)).Add(ValueOf(float32(20))).NotEqual(ValueOf(float32(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), ValueOf(float64(15)).Add(ValueOf(float64(20))).NotEqual(ValueOf(float64(30))).RawValue()) } func TestCoerceUntyped(t *testing.T) { assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(int(20))).Equal(ValueOf(int(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(int8(20))).Equal(ValueOf(int8(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(int16(20))).Equal(ValueOf(int16(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(int32(20))).Equal(ValueOf(int32(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(int64(20))).Equal(ValueOf(int64(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(uint(20))).Equal(ValueOf(uint(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(uint8(20))).Equal(ValueOf(uint8(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(uint16(20))).Equal(ValueOf(uint16(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(uint32(20))).Equal(ValueOf(uint32(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(uint64(20))).Equal(ValueOf(uint64(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(uintptr(20))).Equal(ValueOf(uintptr(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(float32(20))).Equal(ValueOf(float32(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literalintval(10).Add(ValueOf(float64(20))).Equal(ValueOf(float64(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(int(20))).Equal(ValueOf(int(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(int8(20))).Equal(ValueOf(int8(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(int16(20))).Equal(ValueOf(int16(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(int32(20))).Equal(ValueOf(int32(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(int64(20))).Equal(ValueOf(int64(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(uint(20))).Equal(ValueOf(uint(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(uint8(20))).Equal(ValueOf(uint8(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(uint16(20))).Equal(ValueOf(uint16(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(uint32(20))).Equal(ValueOf(uint32(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(uint64(20))).Equal(ValueOf(uint64(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(uintptr(20))).Equal(ValueOf(uintptr(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(float32(20))).Equal(ValueOf(float32(30))).RawValue()) assert.Equal(t, ValueOf(true).RawValue(), literaluintval(10).Add(ValueOf(float64(20))).Equal(ValueOf(float64(30))).RawValue()) } func TestUnaryOps(t *testing.T) { i := 35 s := struct{ I int }{I: 35} assert.Equal(t, ValueOf(-15).RawValue(), ValueOf(15).Negate().RawValue()) assert.Equal(t, ValueOf(!true).RawValue(), ValueOf(true).Not().RawValue()) assert.Equal(t, ValueOf(!false).RawValue(), ValueOf(false).Not().RawValue()) assert.Equal(t, ValueOf(^25).RawValue(), ValueOf(25).BitNot().RawValue()) assert.Equal(t, ValueOf(35).RawValue(), ValueOf(&i).Deref().RawValue()) assert.Equal(t, ValueOf(35).RawValue(), ValueOf(&s).Dot("I").Ref().Deref().RawValue()) } golang-github-go-restruct-restruct-1.2.0-alpha/expr_18.go000066400000000000000000000002011412231745000232560ustar00rootroot00000000000000// +build !go1.9 package restruct import ( "github.com/go-restruct/restruct/expr" ) var exprStdLib = map[string]expr.Value{} golang-github-go-restruct-restruct-1.2.0-alpha/expr_19.go000066400000000000000000000035361412231745000232750ustar00rootroot00000000000000// +build go1.9 package restruct import ( "math/bits" "github.com/go-restruct/restruct/expr" ) var exprStdLib = map[string]expr.Value{ "bits": expr.ValueOf(expr.NewPackage(map[string]expr.Value{ "LeadingZeros": expr.ValueOf(bits.LeadingZeros), "LeadingZeros8": expr.ValueOf(bits.LeadingZeros8), "LeadingZeros16": expr.ValueOf(bits.LeadingZeros16), "LeadingZeros32": expr.ValueOf(bits.LeadingZeros32), "LeadingZeros64": expr.ValueOf(bits.LeadingZeros64), "Len": expr.ValueOf(bits.Len), "Len8": expr.ValueOf(bits.Len8), "Len16": expr.ValueOf(bits.Len16), "Len32": expr.ValueOf(bits.Len32), "Len64": expr.ValueOf(bits.Len64), "OnesCount": expr.ValueOf(bits.OnesCount), "OnesCount8": expr.ValueOf(bits.OnesCount8), "OnesCount16": expr.ValueOf(bits.OnesCount16), "OnesCount32": expr.ValueOf(bits.OnesCount32), "OnesCount64": expr.ValueOf(bits.OnesCount64), "Reverse": expr.ValueOf(bits.Reverse), "Reverse8": expr.ValueOf(bits.Reverse8), "Reverse16": expr.ValueOf(bits.Reverse16), "Reverse32": expr.ValueOf(bits.Reverse32), "Reverse64": expr.ValueOf(bits.Reverse64), "ReverseBytes": expr.ValueOf(bits.ReverseBytes), "ReverseBytes16": expr.ValueOf(bits.ReverseBytes16), "ReverseBytes32": expr.ValueOf(bits.ReverseBytes32), "ReverseBytes64": expr.ValueOf(bits.ReverseBytes64), "RotateLeft": expr.ValueOf(bits.RotateLeft), "RotateLeft8": expr.ValueOf(bits.RotateLeft8), "RotateLeft16": expr.ValueOf(bits.RotateLeft16), "RotateLeft32": expr.ValueOf(bits.RotateLeft32), "RotateLeft64": expr.ValueOf(bits.RotateLeft64), "TrailingZeros": expr.ValueOf(bits.TrailingZeros), "TrailingZeros8": expr.ValueOf(bits.TrailingZeros8), "TrailingZeros16": expr.ValueOf(bits.TrailingZeros16), "TrailingZeros32": expr.ValueOf(bits.TrailingZeros32), "TrailingZeros64": expr.ValueOf(bits.TrailingZeros64), })), } golang-github-go-restruct-restruct-1.2.0-alpha/field.go000066400000000000000000000214771412231745000230750ustar00rootroot00000000000000package restruct import ( "encoding/binary" "errors" "fmt" "reflect" "sync" "github.com/go-restruct/restruct/expr" ) // ErrInvalidSize is returned when sizefrom is used on an invalid type. var ErrInvalidSize = errors.New("size specified on fixed size type") // ErrInvalidSizeOf is returned when sizefrom is used on an invalid type. var ErrInvalidSizeOf = errors.New("sizeof specified on fixed size type") // ErrInvalidSizeFrom is returned when sizefrom is used on an invalid type. var ErrInvalidSizeFrom = errors.New("sizefrom specified on fixed size type") // ErrInvalidBits is returned when bits is used on an invalid type. var ErrInvalidBits = errors.New("bits specified on non-bitwise type") // FieldFlags is a type for flags that can be applied to fields individually. type FieldFlags uint64 const ( // VariantBoolFlag causes the true value of a boolean to be ~0 instead of // just 1 (all bits are set.) This emulates the behavior of VARIANT_BOOL. VariantBoolFlag FieldFlags = 1 << iota // InvertedBoolFlag causes the true and false states of a boolean to be // flipped in binary. InvertedBoolFlag // RootFlag is set when the field points to the root struct. RootFlag // ParentFlag is set when the field points to the parent struct. ParentFlag // DefaultFlag is set when the field is designated as a switch case default. DefaultFlag ) // Sizer is a type which has a defined size in binary. The SizeOf function // returns how many bytes the type will consume in memory. This is used during // encoding for allocation and therefore must equal the exact number of bytes // the encoded form needs. You may use a pointer receiver even if the type is // used by value. type Sizer interface { SizeOf() int } // BitSizer is an interface for types that need to specify their own size in // bit-level granularity. It has the same effect as Sizer. type BitSizer interface { BitSize() int } // field represents a structure field, similar to reflect.StructField. type field struct { Name string Index int BinaryType reflect.Type NativeType reflect.Type Order binary.ByteOrder SIndex int // Index of size field for a slice/string. TIndex int // Index of target of sizeof field. Skip int Trivial bool BitSize uint8 Flags FieldFlags IsRoot bool IsParent bool IfExpr *expr.Program SizeExpr *expr.Program BitsExpr *expr.Program InExpr *expr.Program OutExpr *expr.Program WhileExpr *expr.Program SwitchExpr *expr.Program CaseExpr *expr.Program } // fields represents a structure. type fields []field var fieldCache = map[reflect.Type][]field{} var cacheMutex = sync.RWMutex{} // Elem constructs a transient field representing an element of an array, slice, // or pointer. func (f *field) Elem() field { // Special cases for string types, grumble grumble. t := f.BinaryType if t.Kind() == reflect.String { t = reflect.TypeOf([]byte{}) } dt := f.NativeType if dt.Kind() == reflect.String { dt = reflect.TypeOf([]byte{}) } return field{ Name: "*" + f.Name, Index: -1, BinaryType: t.Elem(), NativeType: dt.Elem(), Order: f.Order, TIndex: -1, SIndex: -1, Skip: 0, Trivial: isTypeTrivial(t.Elem()), } } // fieldFromType returns a field from a reflected type. func fieldFromType(typ reflect.Type) field { return field{ Index: -1, BinaryType: typ, NativeType: typ, Order: nil, TIndex: -1, SIndex: -1, Skip: 0, Trivial: isTypeTrivial(typ), } } func validBitType(typ reflect.Type) bool { switch typ.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Complex64, reflect.Complex128: return true default: return false } } func validSizeType(typ reflect.Type) bool { switch typ.Kind() { case reflect.Slice, reflect.String: return true default: return false } } func parseExpr(sources ...string) *expr.Program { for _, s := range sources { if s != "" { return expr.ParseString(s) } } return nil } // fieldsFromStruct returns a slice of fields for binary packing and unpacking. func fieldsFromStruct(typ reflect.Type) (result fields) { if typ.Kind() != reflect.Struct { panic(fmt.Errorf("tried to get fields from non-struct type %s", typ.Kind().String())) } count := typ.NumField() sizeOfMap := map[string]int{} for i := 0; i < count; i++ { val := typ.Field(i) // Skip unexported names (except _) if val.PkgPath != "" && val.Name != "_" { continue } // Parse struct tag opts := mustParseTag(val.Tag.Get("struct")) if opts.Ignore { continue } if opts.RootFlag { result = append(result, field{ Name: val.Name, Index: i, Flags: RootFlag, }) continue } if opts.ParentFlag { result = append(result, field{ Name: val.Name, Index: i, Flags: ParentFlag, }) continue } // Derive type ftyp := val.Type if opts.Type != nil { ftyp = opts.Type } // SizeOf sindex := -1 tindex := -1 if j, ok := sizeOfMap[val.Name]; ok { if !validSizeType(val.Type) { panic(ErrInvalidSizeOf) } sindex = j result[sindex].TIndex = i delete(sizeOfMap, val.Name) } else if opts.SizeOf != "" { sizeOfMap[opts.SizeOf] = i } // SizeFrom if opts.SizeFrom != "" { if !validSizeType(val.Type) { panic(ErrInvalidSizeFrom) } for j := 0; j < i; j++ { val := result[j] if opts.SizeFrom == val.Name { sindex = j result[sindex].TIndex = i } } if sindex == -1 { panic(fmt.Errorf("couldn't find SizeFrom field %s", opts.SizeFrom)) } } // Expr ifExpr := parseExpr(opts.IfExpr, val.Tag.Get("struct-if")) sizeExpr := parseExpr(opts.SizeExpr, val.Tag.Get("struct-size")) bitsExpr := parseExpr(opts.BitsExpr, val.Tag.Get("struct-bits")) inExpr := parseExpr(opts.InExpr, val.Tag.Get("struct-in")) outExpr := parseExpr(opts.OutExpr, val.Tag.Get("struct-out")) whileExpr := parseExpr(opts.WhileExpr, val.Tag.Get("struct-while")) switchExpr := parseExpr(opts.SwitchExpr, val.Tag.Get("struct-switch")) caseExpr := parseExpr(opts.CaseExpr, val.Tag.Get("struct-case")) if sizeExpr != nil && !validSizeType(val.Type) { panic(ErrInvalidSize) } if bitsExpr != nil && !validBitType(ftyp) { panic(ErrInvalidBits) } // Flags flags := FieldFlags(0) if opts.VariantBoolFlag { flags |= VariantBoolFlag } if opts.InvertedBoolFlag { flags |= InvertedBoolFlag } if opts.DefaultFlag { flags |= DefaultFlag } result = append(result, field{ Name: val.Name, Index: i, BinaryType: ftyp, NativeType: val.Type, Order: opts.Order, SIndex: sindex, TIndex: tindex, Skip: opts.Skip, Trivial: isTypeTrivial(ftyp), BitSize: opts.BitSize, Flags: flags, IfExpr: ifExpr, SizeExpr: sizeExpr, BitsExpr: bitsExpr, InExpr: inExpr, OutExpr: outExpr, WhileExpr: whileExpr, SwitchExpr: switchExpr, CaseExpr: caseExpr, }) } for fieldName := range sizeOfMap { panic(fmt.Errorf("couldn't find SizeOf field %s", fieldName)) } return } func cachedFieldsFromStruct(typ reflect.Type) (result fields) { cacheMutex.RLock() result, ok := fieldCache[typ] cacheMutex.RUnlock() if ok { return } result = fieldsFromStruct(typ) cacheMutex.Lock() fieldCache[typ] = result cacheMutex.Unlock() return } // isTypeTrivial determines if a given type is constant-size. func isTypeTrivial(typ reflect.Type) bool { if typ == nil { return false } switch typ.Kind() { case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: return true case reflect.Array, reflect.Ptr: return isTypeTrivial(typ.Elem()) case reflect.Struct: for _, field := range cachedFieldsFromStruct(typ) { if !isTypeTrivial(field.BinaryType) { return false } } return true default: return false } } func (f *field) sizer(v reflect.Value) (Sizer, bool) { if s, ok := v.Interface().(Sizer); ok { return s, true } if !v.CanAddr() { return nil, false } if s, ok := v.Addr().Interface().(Sizer); ok { return s, true } return nil, false } func (f *field) bitSizer(v reflect.Value) (BitSizer, bool) { if s, ok := v.Interface().(BitSizer); ok { return s, true } if !v.CanAddr() { return nil, false } if s, ok := v.Addr().Interface().(BitSizer); ok { return s, true } return nil, false } func (f *field) bitSizeUsingInterface(val reflect.Value) (int, bool) { if s, ok := f.bitSizer(val); ok { return s.BitSize(), true } if s, ok := f.sizer(val); ok { return s.SizeOf() * 8, true } return 0, false } golang-github-go-restruct-restruct-1.2.0-alpha/field_test.go000066400000000000000000000135141412231745000241250ustar00rootroot00000000000000package restruct import ( "encoding/binary" "reflect" "testing" "github.com/stretchr/testify/assert" ) var intType = reflect.TypeOf(int(0)) var boolType = reflect.TypeOf(false) var strType = reflect.TypeOf(string("")) func TestFieldsFromStruct(t *testing.T) { tests := []struct { input interface{} fields fields }{ { struct { Simple int }{}, fields{ field{ Name: "Simple", Index: 0, BinaryType: intType, NativeType: intType, Order: nil, SIndex: -1, TIndex: -1, Skip: 0, Trivial: true, BitSize: 0, Flags: 0, }, }, }, { struct { Before int During string `struct:"-"` After bool }{}, fields{ field{ Name: "Before", Index: 0, BinaryType: intType, NativeType: intType, Order: nil, SIndex: -1, TIndex: -1, Skip: 0, Trivial: true, BitSize: 0, Flags: 0, }, field{ Name: "After", Index: 2, BinaryType: boolType, NativeType: boolType, Order: nil, SIndex: -1, TIndex: -1, Skip: 0, Trivial: true, BitSize: 0, Flags: 0, }, }, }, { struct { VariantBool bool `struct:"variantbool"` InvertedBool bool `struct:"invertedbool"` InvertedVariantBool bool `struct:"variantbool,invertedbool"` }{}, fields{ field{ Name: "VariantBool", Index: 0, BinaryType: boolType, NativeType: boolType, Order: nil, SIndex: -1, TIndex: -1, Skip: 0, Trivial: true, BitSize: 0, Flags: VariantBoolFlag, }, field{ Name: "InvertedBool", Index: 1, BinaryType: boolType, NativeType: boolType, Order: nil, SIndex: -1, TIndex: -1, Skip: 0, Trivial: true, BitSize: 0, Flags: InvertedBoolFlag, }, field{ Name: "InvertedVariantBool", Index: 2, BinaryType: boolType, NativeType: boolType, Order: nil, SIndex: -1, TIndex: -1, Skip: 0, Trivial: true, BitSize: 0, Flags: VariantBoolFlag | InvertedBoolFlag, }, }, }, { struct { FixedStr string `struct:"[64]byte,skip=4"` LSBInt int `struct:"uint32,little"` }{}, fields{ field{ Name: "FixedStr", Index: 0, BinaryType: reflect.TypeOf([64]byte{}), NativeType: strType, Order: nil, SIndex: -1, TIndex: -1, Skip: 4, Trivial: true, BitSize: 0, Flags: 0, }, field{ Name: "LSBInt", Index: 1, BinaryType: reflect.TypeOf(uint32(0)), NativeType: intType, Order: binary.LittleEndian, SIndex: -1, TIndex: -1, Skip: 0, Trivial: true, BitSize: 0, Flags: 0, }, }, }, { struct { NumColors int32 `struct:"sizeof=Colors"` Colors [][4]uint8 }{}, fields{ field{ Name: "NumColors", Index: 0, BinaryType: reflect.TypeOf(int32(0)), NativeType: reflect.TypeOf(int32(0)), SIndex: -1, TIndex: 1, Skip: 0, Trivial: true, }, field{ Name: "Colors", Index: 1, BinaryType: reflect.TypeOf([][4]uint8{}), NativeType: reflect.TypeOf([][4]uint8{}), SIndex: 0, TIndex: -1, Skip: 0, Trivial: false, }, }, }, { struct { NumColors int32 Colors [][4]uint8 `struct:"sizefrom=NumColors"` }{}, fields{ field{ Name: "NumColors", Index: 0, BinaryType: reflect.TypeOf(int32(0)), NativeType: reflect.TypeOf(int32(0)), SIndex: -1, TIndex: 1, Skip: 0, Trivial: true, }, field{ Name: "Colors", Index: 1, BinaryType: reflect.TypeOf([][4]uint8{}), NativeType: reflect.TypeOf([][4]uint8{}), SIndex: 0, TIndex: -1, Skip: 0, Trivial: false, }, }, }, } for _, test := range tests { fields := fieldsFromStruct(reflect.TypeOf(test.input)) assert.Equal(t, test.fields, fields) } } func TestFieldsFromNonStructPanics(t *testing.T) { defer func() { if r := recover(); r == nil { t.Error("Non-struct did not panic.") } }() fieldsFromStruct(reflect.TypeOf(0)) } func TestFieldsFromBrokenSizeOf(t *testing.T) { defer func() { r := recover() if r == nil { t.Error("Broken struct did not panic.") } assert.Equal(t, "couldn't find SizeOf field Nonexistant", r.(error).Error()) }() badSize := struct { Test int64 `struct:"sizeof=Nonexistant"` }{} fieldsFromStruct(reflect.TypeOf(badSize)) } func TestFieldsFromBrokenSizeFrom(t *testing.T) { defer func() { r := recover() if r == nil { t.Error("Broken struct did not panic.") } assert.Equal(t, "couldn't find SizeFrom field Nonexistant", r.(error).Error()) }() badSize := struct { Test string `struct:"sizefrom=Nonexistant"` }{} fieldsFromStruct(reflect.TypeOf(badSize)) } func TestIsTypeTrivial(t *testing.T) { tests := []struct { input interface{} trivial bool }{ {int8(0), true}, {int16(0), true}, {int32(0), true}, {int64(0), true}, {[0]int8{}, true}, {[]int8{}, false}, {struct{}{}, true}, {struct{ int8 }{}, true}, {struct{ A []int8 }{[]int8{}}, false}, {struct{ A [0]int8 }{[0]int8{}}, true}, {(*interface{})(nil), false}, } for _, test := range tests { assert.Equal(t, test.trivial, isTypeTrivial(reflect.TypeOf(test.input))) } } func BenchmarkFieldsFromStruct(b *testing.B) { for i := 0; i < b.N; i++ { fieldsFromStruct(reflect.TypeOf(TestStruct{})) } } golang-github-go-restruct-restruct-1.2.0-alpha/formats/000077500000000000000000000000001412231745000231235ustar00rootroot00000000000000golang-github-go-restruct-restruct-1.2.0-alpha/formats/png/000077500000000000000000000000001412231745000237075ustar00rootroot00000000000000golang-github-go-restruct-restruct-1.2.0-alpha/formats/png/png.go000066400000000000000000000031461412231745000250260ustar00rootroot00000000000000// Package png implements some of the PNG format using Restruct. package png // ColorType is used to specify the color format of a PNG. type ColorType byte // Enumeration of valid ColorTypes. const ( ColorGreyscale ColorType = 0 ColorTrueColor ColorType = 2 ColorIndexed ColorType = 3 ColorGreyscaleAlpha ColorType = 4 ColorTrueColorAlpha ColorType = 6 ) // File contains the data of an image. type File struct { Magic [8]byte Header Chunk Chunks []Chunk `struct-while:"!_eof"` } // Chunk contains the data of a single chunk. type Chunk struct { Len uint32 Type string `struct:"[4]byte"` Data struct { IHDR *ChunkIHDR `struct-case:"$'IHDR'" json:",omitempty"` IDAT *ChunkIDAT `struct-case:"$'IDAT'" json:",omitempty"` IEND *ChunkIEND `struct-case:"$'IEND'" json:",omitempty"` Raw *ChunkRaw `struct:"default" json:",omitempty"` } `struct-switch:"Type"` CRC uint32 } // ChunkIHDR contains the body of a IHDR chunk. type ChunkIHDR struct { Width uint32 Height uint32 BitDepth byte ColorType ColorType CompressionMethod byte FilterMethod byte InterlaceMethod byte } // ChunkIDAT contains the body of a IDAT chunk. type ChunkIDAT struct { Parent *Chunk `struct:"parent" json:"-"` Data []byte `struct-size:"Parent.Len"` } // ChunkRaw contains the body of an unrecognized chunk. type ChunkRaw struct { Parent *Chunk `struct:"parent" json:"-"` Data []byte `struct-size:"Parent.Len"` } // ChunkIEND contains the body of a IEND chunk. type ChunkIEND struct { } // ChunkPLTE contains the body of a PLTE chunk. type ChunkPLTE struct { } golang-github-go-restruct-restruct-1.2.0-alpha/formats_test.go000066400000000000000000000020731412231745000245130ustar00rootroot00000000000000package restruct import ( "encoding/binary" "encoding/json" "io/ioutil" "reflect" "testing" "github.com/go-restruct/restruct/formats/png" "github.com/stretchr/testify/assert" ) func readfile(fn string) []byte { if d, err := ioutil.ReadFile(fn); err == nil { return d } else { panic(err) } } func TestPNGGrad8RGB(t *testing.T) { EnableExprBeta() tests := []struct { format interface{} expectdata []byte expectjson []byte }{ { format: png.File{}, expectdata: readfile("testdata/pnggrad8rgb.png"), expectjson: readfile("testdata/pnggrad8rgb.json"), }, } for _, test := range tests { f := reflect.New(reflect.TypeOf(test.format)).Interface() assert.Nil(t, json.Unmarshal(test.expectjson, f)) data, err := Pack(binary.BigEndian, f) assert.Nil(t, err) assert.Equal(t, test.expectdata, data) f = reflect.New(reflect.TypeOf(test.format)).Interface() assert.Nil(t, Unpack(test.expectdata, binary.BigEndian, f)) data, err = json.Marshal(f) assert.Nil(t, err) assert.JSONEq(t, string(test.expectjson), string(data)) } } golang-github-go-restruct-restruct-1.2.0-alpha/go.mod000066400000000000000000000001771412231745000225630ustar00rootroot00000000000000module github.com/go-restruct/restruct go 1.12 require ( github.com/pkg/errors v0.8.1 github.com/stretchr/testify v1.4.0 ) golang-github-go-restruct-restruct-1.2.0-alpha/go.sum000066400000000000000000000020041412231745000225770ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= golang-github-go-restruct-restruct-1.2.0-alpha/packing.go000066400000000000000000000112001412231745000234050ustar00rootroot00000000000000/* Package restruct implements packing and unpacking of raw binary formats. Structures can be created with struct tags annotating the on-disk or in-memory layout of the structure, using the "struct" struct tag, like so: struct { Length int `struct:"int32,sizeof=Packets"` Packets []struct{ Source string `struct:"[16]byte"` Timestamp int `struct:"int32,big"` Data [256]byte `struct:"skip=8"` } } To unpack data in memory to this structure, simply use Unpack with a byte slice: msg := Message{} restruct.Unpack(data, binary.LittleEndian, &msg) */ package restruct import ( "encoding/binary" "reflect" ) func fieldFromIntf(v interface{}) (field, reflect.Value) { val := reflect.ValueOf(v) if val.Kind() == reflect.Ptr { val = val.Elem() } f := fieldFromType(val.Type()) return f, val } /* Unpack reads data from a byteslice into a value. Two types of values are directly supported here: Unpackers and structs. You can pass them by value or by pointer, although it is an error if Restruct is unable to set a value because it is unaddressable. For structs, each field will be read sequentially based on a straightforward interpretation of the type. For example, an int32 will be read as a 32-bit signed integer, taking 4 bytes of memory. Structures and arrays are laid out flat with no padding or metadata. Unexported fields are ignored, except for fields named _ - those fields will be treated purely as padding. Padding will not be preserved through packing and unpacking. The behavior of deserialization can be customized using struct tags. The following struct tag syntax is supported: `struct:"[flags...]"` Flags are comma-separated keys. The following are available: type A bare type name, e.g. int32 or []string. For integer types, it is possible to specify the number of bits, allowing the definition of bitfields, by appending a colon followed by the number of bits. For example, uint32:20 would specify a field that is 20 bits long. sizeof=[Field] Specifies that the field should be treated as a count of the number of elements in Field. sizefrom=[Field] Specifies that the field should determine the number of elements in itself by reading the counter in Field. skip=[Count] Skips Count bytes before the field. You can use this to e.g. emulate C structure alignment. big,msb Specifies big endian byte order. When applied to structs, this will apply to all fields under the struct. little,lsb Specifies little endian byte order. When applied to structs, this will apply to all fields under the struct. variantbool Specifies that the boolean `true` value should be encoded as -1 instead of 1. invertedbool Specifies that the `true` and `false` encodings for boolean should be swapped. */ func Unpack(data []byte, order binary.ByteOrder, v interface{}) (err error) { defer func() { if r := recover(); r != nil { var ok bool if err, ok = r.(error); !ok { panic(err) } } }() f, val := fieldFromIntf(v) ss := structstack{allowexpr: expressionsEnabled, buf: data} d := decoder{structstack: ss, order: order} d.read(f, val) return } /* SizeOf returns the binary encoded size of the given value, in bytes. */ func SizeOf(v interface{}) (size int, err error) { defer func() { if r := recover(); r != nil { err = r.(error) } }() ss := structstack{allowexpr: expressionsEnabled} f, val := fieldFromIntf(v) return ss.fieldbytes(f, val), nil } /* BitSize returns the binary encoded size of the given value, in bits. */ func BitSize(v interface{}) (size int, err error) { defer func() { if r := recover(); r != nil { err = r.(error) } }() ss := structstack{allowexpr: expressionsEnabled} f, val := fieldFromIntf(v) return ss.fieldbits(f, val), nil } /* Pack writes data from a datastructure into a byteslice. Two types of values are directly supported here: Packers and structs. You can pass them by value or by pointer. Each structure is serialized in the same way it would be deserialized with Unpack. See Unpack documentation for the struct tag format. */ func Pack(order binary.ByteOrder, v interface{}) (data []byte, err error) { defer func() { if r := recover(); r != nil { data = nil err = r.(error) } }() ss := structstack{allowexpr: expressionsEnabled, buf: []byte{}} f, val := fieldFromIntf(v) data = make([]byte, ss.fieldbytes(f, val)) ss.buf = data e := encoder{structstack: ss, order: order} e.write(f, val) return } golang-github-go-restruct-restruct-1.2.0-alpha/packing_test.go000066400000000000000000000420061412231745000244540ustar00rootroot00000000000000package restruct import ( "encoding/binary" "errors" "reflect" "testing" "github.com/stretchr/testify/assert" ) func TestUnpack(t *testing.T) { tests := []struct { data []byte bitsize int value interface{} }{ { data: []byte{ 0x12, 0x34, 0x56, 0x78, }, bitsize: 32, value: struct { Dd uint32 }{ Dd: 0x12345678, }, }, { data: []byte{ 0x55, 0x55, }, bitsize: 16, value: struct { A uint8 `struct:"uint8:3"` B uint8 `struct:"uint8:2"` C uint8 `struct:"uint8"` D uint8 `struct:"uint8:3"` }{ A: 0x02, B: 0x02, C: 0xAA, D: 0x05, }, }, { data: []byte{ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, }, bitsize: 96, value: struct { DefaultOrder uint32 BigEndian uint32 `struct:"big"` LittleEndian uint32 `struct:"little"` }{ DefaultOrder: 1, BigEndian: 2, LittleEndian: 3, }, }, { data: []byte{ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, }, bitsize: 96, value: struct { DefaultOrder uint32 BigSub struct { BigEndian uint32 } `struct:"big"` LittleSub struct { LittleEndian uint32 } `struct:"little"` }{ DefaultOrder: 1, BigSub: struct{ BigEndian uint32 }{2}, LittleSub: struct{ LittleEndian uint32 }{3}, }, }, { data: []byte{ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, }, bitsize: 160, value: struct { NumStructs int32 `struct:"sizeof=Structs"` Structs []struct{ V1, V2 uint32 } }{ NumStructs: 2, Structs: []struct{ V1, V2 uint32 }{ {V1: 1, V2: 2}, {V1: 3, V2: 4}, }, }, }, { data: []byte{ 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, }, bitsize: 64, value: struct { C64 complex64 }{ C64: complex(0.125, 1.0), }, }, { data: []byte{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x3f, 0x8c, 0xcc, 0xcd, 0x3f, 0x99, 0x99, 0x9a, 0x3f, 0xa6, 0x66, 0x66, 0x3f, 0xb3, 0x33, 0x33, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0xfc, 0xfd, 0xfe, 0xff, 0x00, 0x01, 0x02, 0x03, 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x82, 0x84, 0xe3, 0x81, 0xa3, 0xe3, 0x81, 0x9f, 0xef, 0xbc, 0x81, }, bitsize: 880, value: struct { NumStructs uint32 `struct:"uint64,sizeof=Structs"` Structs []struct{ V1, V2 float32 } Float64 float64 Complex64 complex64 Complex128 complex128 Complex complex128 `struct:"complex64"` SomeInt8s [8]int8 SomeUint8s [8]uint8 AUint16 uint16 AnInt64 int64 _ [8]byte Message string `struct:"[12]byte"` }{ NumStructs: 2, Structs: []struct{ V1, V2 float32 }{ {V1: 1.1, V2: 1.2}, {V1: 1.3, V2: 1.4}, }, Float64: 0.125, Complex64: complex(0.125, 1.0), Complex128: complex(0.125, 1.0), Complex: complex(0.125, 1.0), SomeInt8s: [8]int8{-4, -3, -2, -1, 0, 1, 2, 3}, SomeUint8s: [8]uint8{0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8}, AUint16: 0xfffe, AnInt64: -256, Message: "やった!", }, }, { data: []byte{ 0x00, 0x00, 0x00, 0x04, 0xf0, 0x9f, 0x91, 0x8c, }, bitsize: 64, value: struct { StrLen uint32 `struct:"uint32,sizeof=String"` String string }{ StrLen: 4, String: "👌", }, }, { data: []byte{ 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x9f, 0x91, 0x8c, }, bitsize: 96, value: struct { StrLen uint32 `struct:"uint32,sizeof=String"` String string `struct:"skip=4"` }{ StrLen: 4, String: "👌", }, }, { data: []byte{ 0xf0, 0x9f, 0x91, 0x8c, }, bitsize: 32, value: struct { String string `struct:"[4]byte"` }{ String: "👌", }, }, { data: []byte{ 0xf0, 0x9f, 0x91, 0x8c, 0x00, 0x00, 0x00, 0x01, }, bitsize: 64, value: struct { String string `struct:"[7]byte"` Value byte }{ String: "👌", Value: 1, }, }, { data: []byte{ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x22, 0x18, 0x00, 0x28, 0x12, }, bitsize: 88, value: struct { Length int32 `struct:"int16,sizeof=Slice,little,skip=1"` Slice []struct { Test int16 `struct:"skip=1"` } `struct:"skip=2,lsb"` }{ Length: 2, Slice: []struct { Test int16 `struct:"skip=1"` }{ {Test: 0x1822}, {Test: 0x1228}, }, }, }, { data: []byte{ 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, }, bitsize: 48, value: struct { Ints []uint16 `struct:"[3]uint16"` }{ Ints: []uint16{1, 2, 3}, }, }, { data: []byte{ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, }, bitsize: 64, value: struct { Size int `struct:"int32,sizeof=Array"` Array []int32 }{ Size: 1, Array: []int32{3}, }, }, { data: []byte{ 0x00, 0x00, 0x00, 0x03, }, bitsize: 32, value: struct { Array [1]int `struct:"[1]int32"` }{ Array: [1]int{3}, }, }, { data: []byte{ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, }, bitsize: 64, value: struct { Size int `struct:"int32,sizeof=Array"` Array []int `struct:"[]int32"` }{ Size: 1, Array: []int{3}, }, }, { data: []byte{ 0x00, 0x00, 0x00, 0x03, }, bitsize: 32, value: struct { Array []int `struct:"[1]int32"` }{ Array: []int{3}, }, }, { data: []byte{ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, }, bitsize: 64, value: struct { _ struct{} Size int `struct:"int32"` _ struct{} Array []int32 `struct:"sizefrom=Size"` _ struct{} }{ Size: 1, Array: []int32{3}, }, }, { data: []byte{ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, }, bitsize: 96, value: struct { _ struct{} Size int `struct:"int32"` _ struct{} Array1 []int32 `struct:"sizefrom=Size"` Array2 []int32 `struct:"sizefrom=Size"` _ struct{} }{ Size: 1, Array1: []int32{3}, Array2: []int32{4}, }, }, { data: []byte{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, bitsize: 64, value: struct { A uint64 `struct:"uint64:12"` B uint64 `struct:"uint64:12"` C uint64 `struct:"uint64:30"` D uint64 `struct:"uint64:1"` E uint64 `struct:"uint64:5"` F uint64 `struct:"uint64:1"` G uint64 `struct:"uint64:3"` }{ A: 0xfff, B: 0xfff, C: 0x3fffffff, D: 0x1, E: 0x1f, F: 0x1, G: 0x7, }, }, { data: []byte{ // nonvariant/variant 8-bit // false, false, true, true 0x00, 0x00, 0x01, 0xFF, // nonvariant/variant 8-bit inverted // false, false, true, true 0x01, 0xFF, 0x00, 0x00, // nonvariant/variant 32-bit // false, false, true, true 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, // nonvariant/variant 32-bit inverted // false, false, true, true 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, bitsize: 320, value: struct { NonVariant8BitFalse bool `struct:"bool"` Variant8BitFalse bool `struct:"bool,variantbool"` NonVariant8BitTrue bool `struct:"bool"` Variant8BitTrue bool `struct:"bool,variantbool"` NonVariant8BitFalseInverted bool `struct:"bool,invertedbool"` Variant8BitFalseInverted bool `struct:"bool,invertedbool,variantbool"` NonVariant8BitTrueInverted bool `struct:"bool,invertedbool"` Variant8BitTrueInverted bool `struct:"bool,invertedbool,variantbool"` NonVariant32BitFalse bool `struct:"int32"` Variant32BitFalse bool `struct:"uint32,variantbool"` NonVariant32BitTrue bool `struct:"uint32"` Variant32BitTrue bool `struct:"int32,variantbool"` NonVariant32BitFalseInverted bool `struct:"uint32,invertedbool"` Variant32BitFalseInverted bool `struct:"int32,invertedbool,variantbool"` NonVariant32BitTrueInverted bool `struct:"int32,invertedbool"` Variant32BitTrueInverted bool `struct:"uint32,invertedbool,variantbool"` }{ NonVariant8BitFalse: false, Variant8BitFalse: false, NonVariant8BitTrue: true, Variant8BitTrue: true, NonVariant8BitFalseInverted: false, Variant8BitFalseInverted: false, NonVariant8BitTrueInverted: true, Variant8BitTrueInverted: true, NonVariant32BitFalse: false, Variant32BitFalse: false, NonVariant32BitTrue: true, Variant32BitTrue: true, NonVariant32BitFalseInverted: false, Variant32BitFalseInverted: false, NonVariant32BitTrueInverted: true, Variant32BitTrueInverted: true, }, }, { data: []byte{0x80}, bitsize: 1, value: struct { Bit bool `struct:"uint8:1"` }{ Bit: true, }, }, { data: []byte{0x08, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F}, bitsize: 80, value: struct { Count uint8 `struct:"uint8,sizeof=List"` List []struct { A bool `struct:"uint8:1,variantbool"` B uint8 `struct:"uint8:4"` C uint8 `struct:"uint8:4"` } }{ Count: 8, List: []struct { A bool `struct:"uint8:1,variantbool"` B uint8 `struct:"uint8:4"` C uint8 `struct:"uint8:4"` }{ {A: false, B: 1, C: 14}, {A: false, B: 3, C: 12}, {A: false, B: 7, C: 8}, {A: false, B: 15, C: 0}, {A: true, B: 14, C: 1}, {A: true, B: 12, C: 3}, {A: true, B: 8, C: 7}, {A: true, B: 0, C: 15}, }, }, }, } for _, test := range tests { v := reflect.New(reflect.TypeOf(test.value)) // Test unpacking err := Unpack(test.data, binary.BigEndian, v.Interface()) assert.Nil(t, err) assert.Equal(t, test.value, v.Elem().Interface()) // Test packing data, err := Pack(binary.BigEndian, v.Interface()) assert.Nil(t, err) assert.Equal(t, test.data, data) // Test sizing size, err := SizeOf(v.Interface()) assert.Nil(t, err) assert.Equal(t, len(test.data), size) // Test bit sizing bits, err := BitSize(v.Interface()) assert.Nil(t, err) assert.Equal(t, test.bitsize, bits) } } func TestUnpackBrokenSizeOf(t *testing.T) { data := []byte{ 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x22, 0x18, 0x00, 0x28, 0x12, } s := struct { Length string `struct:"sizeof=Slice,skip=1"` Slice []struct { Test int16 `struct:"skip=1"` } `struct:"skip=2,lsb"` }{ Length: "no", Slice: []struct { Test int16 `struct:"skip=1"` }{ {Test: 0x1822}, {Test: 0x1228}, }, } // Test unpacking err := Unpack(data, binary.BigEndian, &s) assert.NotNil(t, err) assert.Equal(t, "unsupported size type string: Length", err.Error()) // Test packing _, err = Pack(binary.BigEndian, &s) assert.NotNil(t, err) assert.Equal(t, "unsupported size type string: Length", err.Error()) // Test unpacking sizeof to array fails. s2 := struct { Length int32 `struct:"sizeof=Array,skip=1"` Array [2]int16 `struct:"skip=2,lsb"` }{ Length: 2, Array: [2]int16{ 0x1822, 0x1228, }, } err = Unpack(data, binary.BigEndian, &s2) assert.NotNil(t, err) assert.Equal(t, "sizeof specified on fixed size type", err.Error()) } func TestUnpackBrokenArray(t *testing.T) { data := []byte{ 0x02, 0x00, } s := struct { Length int16 `struct:"[2]uint8"` }{ Length: 2, } // Test unpacking err := Unpack(data, binary.BigEndian, &s) assert.NotNil(t, err) assert.Equal(t, "invalid array cast type: int16", err.Error()) // Test packing _, err = Pack(binary.BigEndian, &s) assert.NotNil(t, err) assert.Equal(t, "invalid array cast type: int16", err.Error()) s2 := struct { Length int16 `struct:"[]uint8"` }{ Length: 2, } // Test unpacking err = Unpack(data, binary.BigEndian, &s2) assert.NotNil(t, err) assert.Equal(t, "invalid array cast type: int16", err.Error()) // Test packing _, err = Pack(binary.BigEndian, &s2) assert.NotNil(t, err) assert.Equal(t, "invalid array cast type: int16", err.Error()) } func TestUnpackFastPath(t *testing.T) { v := struct { Size uint8 `struct:"sizeof=Data"` Data []byte }{} assert.Nil(t, Unpack([]byte("\x04Data"), binary.LittleEndian, &v)) assert.Equal(t, 4, int(v.Size)) assert.Equal(t, "Data", string(v.Data)) } func BenchmarkFastPath(b *testing.B) { v := struct { Size uint8 `struct:"sizeof=Data"` Data []byte }{} data := []byte(" @?>=<;:9876543210/.-,+*)('&%$#\"! ") for i := 0; i < b.N; i++ { _ = Unpack(data, binary.LittleEndian, &v) } } // Test custom packing type CString string func (s *CString) SizeOf() int { return len(*s) + 1 } func (s *CString) Unpack(buf []byte, order binary.ByteOrder) ([]byte, error) { for i, l := 0, len(buf); i < l; i++ { if buf[i] == 0 { *s = CString(buf[:i]) return buf[i+1:], nil } } return []byte{}, errors.New("unterminated string") } func (s *CString) Pack(buf []byte, order binary.ByteOrder) ([]byte, error) { l := len(*s) for i := 0; i < l; i++ { buf[i] = (*s)[i] } buf[l] = 0 return buf[l+1:], nil } func TestCustomPacking(t *testing.T) { x := CString("Test string! テスト。") b, err := Pack(binary.LittleEndian, &x) assert.Nil(t, err) assert.Equal(t, []byte{ 0x54, 0x65, 0x73, 0x74, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x21, 0x20, 0xe3, 0x83, 0x86, 0xe3, 0x82, 0xb9, 0xe3, 0x83, 0x88, 0xe3, 0x80, 0x82, 0x0, }, b) y := CString("") err = Unpack(b, binary.LittleEndian, &y) assert.Nil(t, err) assert.Equal(t, "Test string! テスト。", string(y)) } // Test custom packing with non-pointer receiver type Custom struct { A *int } func (s Custom) SizeOf() int { return 4 } func (s Custom) Unpack(buf []byte, order binary.ByteOrder) ([]byte, error) { *s.A = int(order.Uint32(buf[0:4])) return buf[4:], nil } func (s Custom) Pack(buf []byte, order binary.ByteOrder) ([]byte, error) { order.PutUint32(buf[0:4], uint32(*s.A)) return buf[4:], nil } func TestCustomPackingNonPointer(t *testing.T) { c := Custom{new(int)} *c.A = 32 b, err := Pack(binary.LittleEndian, c) assert.Nil(t, err) assert.Equal(t, []byte{0x20, 0x00, 0x00, 0x00}, b) d := Custom{new(int)} err = Unpack(b, binary.LittleEndian, d) assert.Nil(t, err) assert.Equal(t, 32, *d.A) } func TestSizeExpr(t *testing.T) { EnableExprBeta() type sizeStruct struct { Len byte Data []byte `struct:"size=Len*2"` } expectStruct := sizeStruct{ 2, []byte{0, 1, 2, 3}, } expectData := []byte{2, 0, 1, 2, 3} var actualStruct sizeStruct err := Unpack(expectData, binary.LittleEndian, &actualStruct) assert.Nil(t, err) assert.Equal(t, expectStruct, actualStruct) actualData, err := Pack(binary.LittleEndian, &expectStruct) assert.Nil(t, err) assert.Equal(t, expectData, actualData) } func TestBitsExpr(t *testing.T) { EnableExprBeta() type dynamicBits struct { BitLen byte Int uint64 `struct:"bits=BitLen"` } expectStruct := dynamicBits{5, 0x1f} expectData := []byte{5, 0xf8} var actualStruct dynamicBits err := Unpack(expectData, binary.BigEndian, &actualStruct) assert.Nil(t, err) assert.Equal(t, expectStruct, actualStruct) actualData, err := Pack(binary.BigEndian, &expectStruct) assert.Nil(t, err) assert.Equal(t, expectData, actualData) } func TestIfExpr(t *testing.T) { EnableExprBeta() type ifExpr struct { HasByte bool Byte byte `struct:"if=HasByte"` } { expectStruct := ifExpr{false, 0} expectData := []byte{0} var actualStruct ifExpr err := Unpack(expectData, binary.BigEndian, &actualStruct) assert.Nil(t, err) assert.Equal(t, expectStruct, actualStruct) actualData, err := Pack(binary.BigEndian, &expectStruct) assert.Nil(t, err) assert.Equal(t, expectData, actualData) } { expectStruct := ifExpr{true, 255} expectData := []byte{1, 255} var actualStruct ifExpr err := Unpack(expectData, binary.BigEndian, &actualStruct) assert.Nil(t, err) assert.Equal(t, expectStruct, actualStruct) actualData, err := Pack(binary.BigEndian, &expectStruct) assert.Nil(t, err) assert.Equal(t, expectData, actualData) } } func TestInOutExpr(t *testing.T) { EnableExprBeta() type inoutStruct struct { Value byte `struct:"in=Value/2,out=Value*2"` } expectStruct := inoutStruct{20} expectData := []byte{40} var actualStruct inoutStruct err := Unpack(expectData, binary.LittleEndian, &actualStruct) assert.Nil(t, err) assert.Equal(t, expectStruct, actualStruct) actualData, err := Pack(binary.LittleEndian, &expectStruct) assert.Nil(t, err) assert.Equal(t, expectData, actualData) } golang-github-go-restruct-restruct-1.2.0-alpha/structstack.go000066400000000000000000000141771412231745000243630ustar00rootroot00000000000000package restruct import ( "fmt" "reflect" "github.com/go-restruct/restruct/expr" ) type switchcase struct { f field v reflect.Value } type structstack struct { buf []byte stack []reflect.Value allowexpr bool } func (s *structstack) Resolve(ident string) expr.Value { switch ident { case "_eof": return expr.ValueOf(len(s.buf) == 0) default: if t := stdLibResolver.Resolve(ident); t != nil { return t } if len(s.stack) > 0 { if sv := s.stack[len(s.stack)-1].FieldByName(ident); sv.IsValid() { return expr.ValueOf(sv.Interface()) } } return nil } } func (s *structstack) evalBits(f field) int { bits := 0 if f.BitSize != 0 { bits = int(f.BitSize) } if f.BitsExpr != nil { bits = reflect.ValueOf(s.evalExpr(f.BitsExpr)).Convert(reflect.TypeOf(int(0))).Interface().(int) } return bits } func (s *structstack) evalSize(f field) int { size := 0 if f.SizeExpr != nil { size = reflect.ValueOf(s.evalExpr(f.SizeExpr)).Convert(reflect.TypeOf(int(0))).Interface().(int) } return size } func (s *structstack) evalIf(f field) bool { if f.IfExpr == nil { return true } if b, ok := s.evalExpr(f.IfExpr).(bool); ok { return b } panic("expected bool value for if expr") } func (s *structstack) evalWhile(f field) bool { if b, ok := s.evalExpr(f.WhileExpr).(bool); ok { return b } panic("expected bool value for while expr") } func (s *structstack) switcbits(f field, v reflect.Value, on interface{}) (size int) { var def *switchcase if v.Kind() != reflect.Struct { panic(fmt.Errorf("%s: only switches on structs are valid", f.Name)) } sfields := cachedFieldsFromStruct(f.BinaryType) l := len(sfields) for i := 0; i < l; i++ { f := sfields[i] v := v.Field(f.Index) if f.Flags&DefaultFlag != 0 { if def != nil { panic(fmt.Errorf("%s: only one default case is allowed", f.Name)) } def = &switchcase{f, v} continue } if f.CaseExpr == nil { panic(fmt.Errorf("%s: only cases are valid inside switches", f.Name)) } if s.evalExpr(f.CaseExpr) == on { return s.fieldbits(f, v) } } if def != nil { return s.fieldbits(def.f, def.v) } return 0 } // fieldbits determines the encoded size of a field in bits. func (s *structstack) fieldbits(f field, val reflect.Value) (size int) { skipBits := f.Skip * 8 if f.Flags&RootFlag == RootFlag { s.setancestor(f, val, s.root()) return 0 } if f.Flags&ParentFlag == ParentFlag { for i := 1; i < len(s.stack); i++ { if s.setancestor(f, val, s.ancestor(i)) { break } } return 0 } if f.SwitchExpr != nil { return s.switcbits(f, val, s.evalExpr(f.SwitchExpr)) } if f.Name != "_" { if s, ok := f.bitSizeUsingInterface(val); ok { return s } } else { // Non-trivial, unnamed fields do not make sense. You can't set a field // with no name, so the elements can't possibly differ. // N.B.: Though skip will still work, use struct{} instead for skip. if !isTypeTrivial(val.Type()) { return skipBits } } if !s.evalIf(f) { return 0 } if b := s.evalBits(f); b != 0 { return b } alen := 1 switch f.BinaryType.Kind() { case reflect.Int8, reflect.Uint8, reflect.Bool: return 8 + skipBits case reflect.Int16, reflect.Uint16: return 16 + skipBits case reflect.Int, reflect.Int32, reflect.Uint, reflect.Uint32, reflect.Float32: return 32 + skipBits case reflect.Int64, reflect.Uint64, reflect.Float64, reflect.Complex64: return 64 + skipBits case reflect.Complex128: return 128 + skipBits case reflect.Slice, reflect.String: switch f.NativeType.Kind() { case reflect.Slice, reflect.String, reflect.Array, reflect.Ptr: alen = val.Len() default: return 0 } fallthrough case reflect.Array, reflect.Ptr: size += skipBits // If array type, get length from type. if f.BinaryType.Kind() == reflect.Array { alen = f.BinaryType.Len() } // Optimization: if the array/slice is empty, bail now. if alen == 0 { return size } switch f.NativeType.Kind() { case reflect.Ptr: return s.fieldbits(f.Elem(), val.Elem()) case reflect.Slice, reflect.String, reflect.Array: // Optimization: if the element type is trivial, we can derive the // length from a single element. elem := f.Elem() if elem.Trivial { size += s.fieldbits(elem, reflect.Zero(elem.BinaryType)) * alen } else { for i := 0; i < alen; i++ { size += s.fieldbits(elem, val.Index(i)) } } } return size case reflect.Struct: size += skipBits s.push(val) for _, field := range cachedFieldsFromStruct(f.BinaryType) { if field.BitSize != 0 { size += int(field.BitSize) } else { size += s.fieldbits(field, val.Field(field.Index)) } } s.pop(val) return size default: return 0 } } // fieldbytes returns the effective size in bytes, for the few cases where // byte sizes are needed. func (s *structstack) fieldbytes(f field, val reflect.Value) (size int) { return (s.fieldbits(f, val) + 7) / 8 } func (s *structstack) fieldsbits(fields fields, val reflect.Value) (size int) { for _, field := range fields { size += s.fieldbits(field, val.Field(field.Index)) } return } func (s *structstack) evalExpr(program *expr.Program) interface{} { if !s.allowexpr { panic("call restruct.EnableExprBeta() to eanble expressions beta") } v, err := expr.EvalProgram(s, program) if err != nil { panic(err) } return v } func (s *structstack) push(v reflect.Value) { s.stack = append(s.stack, v) } func (s *structstack) pop(v reflect.Value) { var p reflect.Value s.stack, p = s.stack[:len(s.stack)-1], s.stack[len(s.stack)-1] if p != v { panic("struct stack misaligned") } } func (s *structstack) setancestor(f field, v reflect.Value, ancestor reflect.Value) bool { if ancestor.Kind() != reflect.Ptr { if !ancestor.CanAddr() { return false } ancestor = ancestor.Addr() } if ancestor.Type().AssignableTo(v.Type()) { v.Set(ancestor) return true } return false } func (s *structstack) root() reflect.Value { if len(s.stack) > 0 { return s.stack[0] } return reflect.ValueOf(nil) } func (s *structstack) ancestor(generation int) reflect.Value { if len(s.stack) > generation { return s.stack[len(s.stack)-generation-1] } return reflect.ValueOf(nil) } golang-github-go-restruct-restruct-1.2.0-alpha/structstack_test.go000066400000000000000000000054571412231745000254230ustar00rootroot00000000000000package restruct import ( "reflect" "testing" "github.com/stretchr/testify/assert" ) type TestElem struct { Test1 int64 Test2 int8 } type TestStruct struct { Sub [10]struct { Sub2 struct { Size int `struct:"uint32,sizeof=Elems"` Elems []TestElem } `struct:"skip=4"` } `struct:"skip=2"` Numbers [128]int64 Numbers2 []float64 `struct:"[256]float32"` } func TestSizeOf(t *testing.T) { tests := []struct { input interface{} size int }{ {int8(0), 8}, {int16(0), 16}, {int32(0), 32}, {int64(0), 64}, {uint8(0), 8}, {uint16(0), 16}, {uint32(0), 32}, {uint64(0), 64}, {float32(0), 32}, {float64(0), 64}, {complex64(0), 64}, {complex128(0), 128}, {[0]int8{}, 0}, {[1]int8{1}, 8}, {[]int8{1, 2}, 16}, {[]int32{1, 2}, 64}, {[2][3]int8{}, 48}, {struct{}{}, 0}, {struct{ A int8 }{}, 8}, {struct{ A []int8 }{[]int8{}}, 0}, {struct{ A [0]int8 }{[0]int8{}}, 0}, {struct{ A []int8 }{[]int8{1}}, 8}, {struct{ A [1]int8 }{[1]int8{1}}, 8}, {TestStruct{}, 17040}, {interface{}(struct{}{}), 0}, {struct{ Test interface{} }{}, 0}, // Unexported fields test {struct{ a int8 }{}, 0}, {struct{ a []int8 }{[]int8{}}, 0}, {struct{ a [0]int8 }{[0]int8{}}, 0}, {struct{ a []int8 }{[]int8{1}}, 0}, {struct{ a [1]int8 }{[1]int8{1}}, 0}, // Trivial unnamed fields test {struct{ _ [1]int8 }{}, 8}, {struct { _ [1]int8 `struct:"skip=4"` }{}, 40}, // Non-trivial unnamed fields test {struct{ _ []interface{} }{}, 0}, {struct{ _ [1]interface{} }{}, 0}, {struct { _ [1]interface{} `struct:"skip=4"` }{}, 32}, {struct { _ [4]struct { _ [4]struct{} `struct:"skip=4"` } `struct:"skip=4"` }{}, 160}, {struct{ T string }{"yeehaw"}, 48}, // Byte-misaligned structures {[10]struct { _ int8 `struct:"uint8:1"` }{}, 10}, {[4]struct { _ bool `struct:"uint8:1,variantbool"` _ int8 `struct:"uint8:4"` _ int8 `struct:"uint8:4"` }{}, 36}, } ss := structstack{} for _, test := range tests { field := fieldFromType(reflect.TypeOf(test.input)) assert.Equal(t, test.size, ss.fieldbits(field, reflect.ValueOf(test.input)), "bad size for input: %#v", test.input) } } var ( simpleFields = fieldsFromStruct(reflect.TypeOf(TestElem{})) complexFields = fieldsFromStruct(reflect.TypeOf(TestStruct{})) ) func TestSizeOfFields(t *testing.T) { ss := structstack{} assert.Equal(t, 72, ss.fieldsbits(simpleFields, reflect.ValueOf(TestElem{}))) assert.Equal(t, 17040, ss.fieldsbits(complexFields, reflect.ValueOf(TestStruct{}))) } func BenchmarkSizeOfSimple(b *testing.B) { ss := structstack{} for i := 0; i < b.N; i++ { ss.fieldsbits(simpleFields, reflect.ValueOf(TestElem{})) } } func BenchmarkSizeOfComplex(b *testing.B) { ss := structstack{} for i := 0; i < b.N; i++ { ss.fieldsbits(complexFields, reflect.ValueOf(TestStruct{})) } } golang-github-go-restruct-restruct-1.2.0-alpha/tag.go000066400000000000000000000142521412231745000225560ustar00rootroot00000000000000package restruct import ( "encoding/binary" "errors" "fmt" "reflect" "strconv" "strings" "unicode" "unicode/utf8" ) func lower(ch rune) rune { return ('a' - 'A') | ch } func isdecimal(ch rune) bool { return '0' <= ch && ch <= '9' } func ishex(ch rune) bool { return '0' <= ch && ch <= '9' || 'a' <= lower(ch) && lower(ch) <= 'f' } func isletter(c rune) bool { return 'a' <= lower(c) && lower(c) <= 'z' || c == '_' || c >= utf8.RuneSelf && unicode.IsLetter(c) } func isdigit(c rune) bool { return isdecimal(c) } func isident(c rune) bool { return isletter(c) || isdigit(c) } func isint(c rune) bool { return isdigit(c) || ishex(c) || lower(c) == 'x' } // tagOptions represents a parsed struct tag. type tagOptions struct { Ignore bool Type reflect.Type SizeOf string SizeFrom string Skip int Order binary.ByteOrder BitSize uint8 VariantBoolFlag bool InvertedBoolFlag bool RootFlag bool ParentFlag bool DefaultFlag bool IfExpr string SizeExpr string BitsExpr string InExpr string OutExpr string WhileExpr string SwitchExpr string CaseExpr string } func (opts *tagOptions) parse(tag string) error { // Empty tag if len(tag) == 0 { return nil } else if tag == "-" { opts.Ignore = true return nil } tag += "\x00" accept := func(v string) bool { if strings.HasPrefix(tag, v) { tag = tag[len(v):] return true } return false } acceptIdent := func() (string, error) { var ( i int r rune ) for i, r = range tag { if r == ',' || r == 0 { break } if i == 0 && !isletter(r) || !isident(r) { return "", fmt.Errorf("invalid identifier character %c", r) } } result := tag[:i] tag = tag[i:] return result, nil } acceptInt := func() (int, error) { var ( i int r rune ) for i, r = range tag { if r == ',' || r == 0 { break } if !isint(r) { return 0, fmt.Errorf("invalid integer character %c", r) } } result := tag[:i] tag = tag[i:] d, err := strconv.ParseInt(result, 0, 64) return int(d), err } acceptExpr := func() (string, error) { stack := []byte{0} current := func() byte { return stack[len(stack)-1] } push := func(r byte) { stack = append(stack, r) } pop := func() { stack = stack[:len(stack)-1] } var i int expr: for i = 0; i < len(tag); i++ { switch tag[i] { case ',': if len(stack) == 1 { break expr } case '(': push(')') case '[': push(']') case '{': push('}') case '"', '\'': term := tag[i] i++ lit: for { if i >= len(tag) { return "", errors.New("unexpected eof in literal") } switch tag[i] { case term: break lit case '\\': i++ } i++ } case current(): pop() if len(stack) == 0 { break expr } default: if tag[i] == 0 { return "", errors.New("unexpected eof in expr") } } } result := tag[:i] tag = tag[i:] return result, nil } var err error for { switch { case accept("lsb"), accept("little"): opts.Order = binary.LittleEndian case accept("msb"), accept("big"), accept("network"): opts.Order = binary.BigEndian case accept("variantbool"): opts.VariantBoolFlag = true case accept("invertedbool"): opts.InvertedBoolFlag = true case accept("root"): opts.RootFlag = true case accept("parent"): opts.ParentFlag = true case accept("default"): opts.DefaultFlag = true case accept("sizeof="): if opts.SizeOf, err = acceptIdent(); err != nil { return fmt.Errorf("sizeof: %v", err) } case accept("sizefrom="): if opts.SizeFrom, err = acceptIdent(); err != nil { return fmt.Errorf("sizefrom: %v", err) } case accept("skip="): if opts.Skip, err = acceptInt(); err != nil { return fmt.Errorf("skip: %v", err) } case accept("if="): if opts.IfExpr, err = acceptExpr(); err != nil { return fmt.Errorf("if: %v", err) } case accept("size="): if opts.SizeExpr, err = acceptExpr(); err != nil { return fmt.Errorf("size: %v", err) } case accept("bits="): if opts.BitsExpr, err = acceptExpr(); err != nil { return fmt.Errorf("bits: %v", err) } case accept("in="): if opts.InExpr, err = acceptExpr(); err != nil { return fmt.Errorf("in: %v", err) } case accept("out="): if opts.OutExpr, err = acceptExpr(); err != nil { return fmt.Errorf("out: %v", err) } case accept("while="): if opts.WhileExpr, err = acceptExpr(); err != nil { return fmt.Errorf("while: %v", err) } case accept("switch="): if opts.SwitchExpr, err = acceptExpr(); err != nil { return fmt.Errorf("switch: %v", err) } case accept("case="): if opts.CaseExpr, err = acceptExpr(); err != nil { return fmt.Errorf("case: %v", err) } case accept("-"): return errors.New("extra options on ignored field") default: typeexpr, err := acceptExpr() if err != nil { return fmt.Errorf("struct type: %v", err) } parts := strings.SplitN(typeexpr, ":", 2) opts.Type, err = parseType(parts[0]) if err != nil { return fmt.Errorf("struct type: %v", err) } if len(parts) < 2 { break } if !validBitType(opts.Type) { return fmt.Errorf("struct type bits specified on non-bitwise type %s", opts.Type) } bits, err := strconv.ParseUint(parts[1], 0, 8) if err != nil { return errors.New("struct type bits: invalid integer syntax") } opts.BitSize = uint8(bits) if opts.BitSize >= uint8(opts.Type.Bits()) || opts.BitSize == 0 { return fmt.Errorf("bit size %d out of range (%d to %d)", opts.BitSize, 1, opts.Type.Bits()-1) } } if accept("\x00") { return nil } if !accept(",") { return errors.New("tag: expected comma") } } } // mustParseTag calls ParseTag but panics if there is an error, to help make // sure programming errors surface quickly. func mustParseTag(tag string) tagOptions { opt, err := parseTag(tag) if err != nil { panic(err) } return opt } // parseTag parses a struct tag into a TagOptions structure. func parseTag(tag string) (tagOptions, error) { opts := tagOptions{} if err := opts.parse(tag); err != nil { return tagOptions{}, err } return opts, nil } golang-github-go-restruct-restruct-1.2.0-alpha/tag_test.go000066400000000000000000000166701412231745000236230ustar00rootroot00000000000000package restruct import ( "encoding/binary" "reflect" "testing" "github.com/stretchr/testify/assert" ) func TestParseTag(t *testing.T) { tests := []struct { input string opts tagOptions errstr string }{ // Blank {"", tagOptions{}, ""}, // Gibberish {"!#%,1245^#df,little,&~@~@~@~@", tagOptions{}, "parsing error"}, {"&paREZysLu&@,83D9I!,9OsQ56BLD", tagOptions{}, "parsing error"}, {"B7~,H0IDSxDlJ,#xa$kgDEL%Ts,88", tagOptions{}, "parsing error"}, {"fio&eQ8xwbhAWR*!CRlL2XBDG$45s", tagOptions{}, "parsing error"}, {"IcPyRJ#EV@a4QAb9wENk4Zq9MpX$p", tagOptions{}, "parsing error"}, // Conflicting byte order {"little,big", tagOptions{Order: binary.BigEndian}, ""}, {"big,little", tagOptions{Order: binary.LittleEndian}, ""}, // Byte order {"msb", tagOptions{Order: binary.BigEndian}, ""}, {"lsb", tagOptions{Order: binary.LittleEndian}, ""}, {"network", tagOptions{Order: binary.BigEndian}, ""}, {"big little", tagOptions{}, "tag: expected comma"}, // Ignore {"-", tagOptions{Ignore: true}, ""}, {"-,test", tagOptions{}, "extra options on ignored field"}, // Bad types {"invalid", tagOptions{}, "unknown type invalid"}, {"chan int8", tagOptions{}, "channel type not allowed"}, {"map[byte]byte", tagOptions{}, "map type not allowed"}, {`map[`, tagOptions{}, "struct type: unexpected eof in expr"}, {`map[]`, tagOptions{}, "struct type: parsing error"}, // Types {"uint8", tagOptions{Type: reflect.TypeOf(uint8(0))}, ""}, {"uint16", tagOptions{Type: reflect.TypeOf(uint16(0))}, ""}, {"uint32", tagOptions{Type: reflect.TypeOf(uint32(0))}, ""}, {"int8", tagOptions{Type: reflect.TypeOf(int8(0))}, ""}, {"int16", tagOptions{Type: reflect.TypeOf(int16(0))}, ""}, {"int32", tagOptions{Type: reflect.TypeOf(int32(0))}, ""}, // Bitfields {"uint8:3", tagOptions{Type: reflect.TypeOf(uint8(0)), BitSize: 3}, ""}, {"uint16:15", tagOptions{Type: reflect.TypeOf(uint16(0)), BitSize: 15}, ""}, {"uint32:31", tagOptions{Type: reflect.TypeOf(uint32(0)), BitSize: 31}, ""}, {"uint64:63", tagOptions{Type: reflect.TypeOf(uint64(0)), BitSize: 63}, ""}, {"uint8:1", tagOptions{Type: reflect.TypeOf(uint8(0)), BitSize: 1}, ""}, {"uint16:1", tagOptions{Type: reflect.TypeOf(uint16(0)), BitSize: 1}, ""}, {"uint32:1", tagOptions{Type: reflect.TypeOf(uint32(0)), BitSize: 1}, ""}, {"uint64:1", tagOptions{Type: reflect.TypeOf(uint64(0)), BitSize: 1}, ""}, {"[]uint8:1", tagOptions{}, "struct type bits specified on non-bitwise type []uint8"}, // Wrong bitfields {"uint8:0", tagOptions{}, "bit size 0 out of range (1 to 7)"}, {"uint16:0", tagOptions{}, "bit size 0 out of range (1 to 15)"}, {"uint32:0", tagOptions{}, "bit size 0 out of range (1 to 31)"}, {"uint64:0", tagOptions{}, "bit size 0 out of range (1 to 63)"}, {"int8:0", tagOptions{}, "bit size 0 out of range (1 to 7)"}, {"int16:0", tagOptions{}, "bit size 0 out of range (1 to 15)"}, {"int32:0", tagOptions{}, "bit size 0 out of range (1 to 31)"}, {"int64:0", tagOptions{}, "bit size 0 out of range (1 to 63)"}, {"uint8:8", tagOptions{BitSize: 0}, "bit size 8 out of range (1 to 7)"}, {"uint16:16", tagOptions{BitSize: 0}, "bit size 16 out of range (1 to 15)"}, {"uint32:32", tagOptions{BitSize: 0}, "bit size 32 out of range (1 to 31)"}, {"uint64:64", tagOptions{BitSize: 0}, "bit size 64 out of range (1 to 63)"}, {"int8:8", tagOptions{BitSize: 0}, "bit size 8 out of range (1 to 7)"}, {"int16:16", tagOptions{BitSize: 0}, "bit size 16 out of range (1 to 15)"}, {"int32:32", tagOptions{BitSize: 0}, "bit size 32 out of range (1 to 31)"}, {"int64:64", tagOptions{BitSize: 0}, "bit size 64 out of range (1 to 63)"}, {"uint8:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, {"uint16:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, {"uint32:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, {"uint64:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, {"int8:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, {"int16:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, {"int32:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, {"int64:XX", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, {"uint8:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, {"uint16:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, {"uint32:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, {"uint64:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, {"int8:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, {"int16:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, {"int32:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, {"int64:X:X", tagOptions{BitSize: 0}, "struct type bits: invalid integer syntax"}, // Sizeof {"sizefrom=OtherField", tagOptions{SizeFrom: "OtherField"}, ""}, {"sizefrom=日本", tagOptions{SizeFrom: "日本"}, ""}, {"sizefrom=日本,variantbool", tagOptions{SizeFrom: "日本", VariantBoolFlag: true}, ""}, {"sizefrom=0", tagOptions{}, "sizefrom: invalid identifier character 0"}, // Sizeof {"sizeof=OtherField", tagOptions{SizeOf: "OtherField"}, ""}, {"sizeof=日本", tagOptions{SizeOf: "日本"}, ""}, {"sizeof=日本,variantbool", tagOptions{SizeOf: "日本", VariantBoolFlag: true}, ""}, {"sizeof=0", tagOptions{}, "sizeof: invalid identifier character 0"}, // Skip {"skip=4", tagOptions{Skip: 4}, ""}, {"skip=字", tagOptions{}, "skip: invalid integer character 字"}, // Expressions {"if=true", tagOptions{IfExpr: "true"}, ""}, {"if=call(0,1)", tagOptions{IfExpr: "call(0,1)"}, ""}, {`if=call(")Test)"),sizeof=Test`, tagOptions{IfExpr: `call(")Test)")`, SizeOf: "Test"}, ""}, {"size=4", tagOptions{SizeExpr: "4"}, ""}, {"size={,", tagOptions{}, "size: unexpected eof in expr"}, {"bits=4", tagOptions{BitsExpr: "4"}, ""}, {"bits={,", tagOptions{}, "bits: unexpected eof in expr"}, {"in=42", tagOptions{InExpr: "42"}, ""}, {"out=struct{}{}", tagOptions{OutExpr: "struct{}{}"}, ""}, {"out=struct{}{},variantbool", tagOptions{OutExpr: "struct{}{}", VariantBoolFlag: true}, ""}, {"while=true", tagOptions{WhileExpr: "true"}, ""}, {`if="`, tagOptions{}, "if: unexpected eof in literal"}, {`while="\"`, tagOptions{}, "while: unexpected eof in literal"}, {`in="\"\"""`, tagOptions{}, "in: unexpected eof in literal"}, {`out="\"test`, tagOptions{}, "out: unexpected eof in literal"}, // Root {"root", tagOptions{RootFlag: true}, ""}, // Parent {"parent", tagOptions{ParentFlag: true}, ""}, // Composite {"uint16,little,sizeof=test,skip=5", tagOptions{ Type: reflect.TypeOf(uint16(0)), Order: binary.LittleEndian, SizeOf: "test", Skip: 5, }, "", }, } for _, test := range tests { opts, err := parseTag(test.input) assert.Equal(t, test.opts, opts) if err != nil { assert.NotEmpty(t, test.errstr) assert.Contains(t, err.Error(), test.errstr) } } } func TestMustParseTagPanicsOnError(t *testing.T) { defer func() { if r := recover(); r == nil { t.Error("Invalid tag did not panic.") } }() mustParseTag("???") } func TestMustParseTagReturnsOnSuccess(t *testing.T) { defer func() { if r := recover(); r != nil { t.Error("Valid tag panicked.") } }() mustParseTag("[128]byte,little,sizeof=Test") } golang-github-go-restruct-restruct-1.2.0-alpha/testdata/000077500000000000000000000000001412231745000232615ustar00rootroot00000000000000golang-github-go-restruct-restruct-1.2.0-alpha/testdata/pnggrad8rgb.json000066400000000000000000000041361412231745000263650ustar00rootroot00000000000000{ "Magic": [ 137, 80, 78, 71, 13, 10, 26, 10 ], "Header": { "Len": 13, "Type": "IHDR", "Data": { "IHDR": { "Width": 300, "Height": 300, "BitDepth": 8, "ColorType": 2, "CompressionMethod": 0, "FilterMethod": 0, "InterlaceMethod": 0 } }, "CRC": 4129233186 }, "Chunks": [ { "Len": 919, "Type": "IDAT", "Data": { "IDAT": { "Data": "eJzt2TGKw0AURMEe4/tfWYqdCRy8QFVstCBw8miYf7Zru87v37bz6J/zrW99++e3nwGp7079E+DdRAgxEUJMhBATIcS8jkLMEkJMhBATIcRECDERQkyEEHOigJglhJgIISZCiIkQYiKEmAgh5kQBMUsIMRFCTIQQEyHERAgxr6MQs4QQEyHERAgxEUJMhBATIcScKCBmCSEmQoiJEGIihJgIISZCiDlRQMwSQkyEEBMhxEQIMRFCzOsoxCwhxEQIMRFCTIQQEyHERAgxJwqIWUKIiRBiIoSYCCEmQoiJEGJOFBCzhBATIcRECDERQkyEEPM6CjFLCDERQkyEEBMhxEQIMRFCzIkCYpYQYiKEmAghJkKIiRBiIoSYEwXELCHERAgxEUJMhBATIcS8jkLMEkJMhBATIcRECDERQkyEEHOigJglhJgIISZCiIkQYiKEmAgh5kQBMUsIMRFCTIQQEyHERAgxr6MQs4QQEyHERAgxEUJMhBATIcScKCBmCSEmQoiJEGIihJgIISZCiDlRQMwSQkyEEBMhxEQIMRFCzOsoxCwhxEQIMRFCTIQQEyHERAgxJwqIWUKIiRBiIoSYCCEmQoiJEGJOFBCzhBATIcRECDERQkyEEPM6CjFLCDERQkyEEBMhxEQIMRFCzIkCYpYQYiKEmAghJkKIiRBiIoSYEwXELCHERAgxEUJMhBATIcS8jkLMEkJMhBATIcRECDERQkyEEHOigJglhJgIISZCiIkQYiKEmAgh5kQBMUsIMRFCTIQQEyHERAgxr6MQs4QQEyHERAgxEUJMhBATIcScKCBmCSEmQoiJEGIihJgIISZCiDlRQMwSQkyEEBMhxEQIMRFCzOsoxCwhxEQIMRFCTIQQEyHERAgxJwqIWUKIiRBiIoSYCCEmQoiJEGJOFBCzhBATIcRECDERQkyEEPM6CjFLCDERQkyEEBMhxEQIMRFCzIkCYpYQYiKEmAghJkKIiRBiIoSYEwXELCHERAgxEUJMhBATIcS8jkLMEkJMhBATIcRECDERQkyEEHOigJglhJgIISZCiIkQYiKEmAgh5kQBMUsIMRFCTIQQEyHERAgxr6MQs4QQEyHERAgxEUJMhBATIcScKCBmCSEmQoiJEGIihJgIISZCiDlRQMwSQkyEEBMhxEQIMRFCzOsoxCwhxEQIMRFCTIQQEyHERAgxJwqIWUKIiRBiIoSYCCEmQojdB7QFXw==" } }, "CRC": 566973649 }, { "Len": 0, "Type": "IEND", "Data": { "IEND": {} }, "CRC": 2923585666 } ] }golang-github-go-restruct-restruct-1.2.0-alpha/testdata/pnggrad8rgb.png000066400000000000000000000017201412231745000261740ustar00rootroot00000000000000PNG  IHDR,,"IDATx1@D_Y @Ul phk߶o}緟ND1BL!ļBBL!D1BLs%!&Bb"!D1K1BL!D1!D1BL!Ĝ( f !&Bb"!&B9Q@BL!D1B(,!D1BL!D1' YBb"!&BbN!D1BL: 1K1BL!D1B̉bb"!&Bb",!D1BL!ļBBL!D1BLs%!&Bb"!D1K1BL!D1!D1BL!Ĝ( f !&Bb"!&B9Q@BL!D1B(,!D1BL!D1' YBb"!&BbN!D1BL: 1K1BL!D1B̉bb"!&Bb",!D1BL!ļBBL!D1BLs%!&Bb"!D1K1BL!D1!D1BL!Ĝ( f !&Bb"!&B9Q@BL!D1B(,!D1BL!D1' YBb"!&BbN!D1BL: 1K1BL!D1B̉bb"!&Bb",!D1BL!ļBBL!D1BLs%!&Bb"!D1K1BL!D1!D1BL!Ĝ( f !&Bb"!&B9Q@BL!D1B(,!D1BL!D1' YBb"!&B_!TIENDB`golang-github-go-restruct-restruct-1.2.0-alpha/typestr.go000066400000000000000000000047741412231745000235250ustar00rootroot00000000000000package restruct import ( "fmt" "go/ast" "go/parser" "go/token" "reflect" "strconv" "github.com/pkg/errors" ) // typeMap maps identifiers to reflect.Types. var typeMap = map[string]reflect.Type{ "bool": reflect.TypeOf(bool(false)), "uint8": reflect.TypeOf(uint8(0)), "uint16": reflect.TypeOf(uint16(0)), "uint32": reflect.TypeOf(uint32(0)), "uint64": reflect.TypeOf(uint64(0)), "int8": reflect.TypeOf(int8(0)), "int16": reflect.TypeOf(int16(0)), "int32": reflect.TypeOf(int32(0)), "int64": reflect.TypeOf(int64(0)), "float32": reflect.TypeOf(float32(0)), "float64": reflect.TypeOf(float64(0)), "complex64": reflect.TypeOf(complex64(0)), "complex128": reflect.TypeOf(complex128(0)), "byte": reflect.TypeOf(uint8(0)), "rune": reflect.TypeOf(int32(0)), "uint": reflect.TypeOf(uint(0)), "int": reflect.TypeOf(int(0)), "uintptr": reflect.TypeOf(uintptr(0)), "string": reflect.SliceOf(reflect.TypeOf(uint8(0))), } // typeOfExpr gets a type corresponding to an expression. func typeOfExpr(expr ast.Expr) (reflect.Type, error) { switch expr := expr.(type) { default: return nil, fmt.Errorf("unexpected expression: %T", expr) case *ast.ArrayType: switch expr.Len { case ast.Expr(nil): // Slice sub, err := typeOfExpr(expr.Elt) if err != nil { return nil, err } return reflect.SliceOf(sub), nil default: // Parse length expression lexpr, ok := expr.Len.(*ast.BasicLit) if !ok { return nil, fmt.Errorf("invalid array size expression") } if lexpr.Kind != token.INT { return nil, fmt.Errorf("invalid array size type") } len, err := strconv.Atoi(lexpr.Value) if err != nil { return nil, err } // Parse elem type expression sub, err := typeOfExpr(expr.Elt) if err != nil { return nil, err } return reflect.ArrayOf(len, sub), nil } case *ast.Ident: // Primitive types typ, ok := typeMap[expr.Name] if !ok { return nil, fmt.Errorf("unknown type %s", expr.Name) } return typ, nil case *ast.StarExpr: // Pointer sub, err := typeOfExpr(expr.X) if err != nil { return nil, err } return reflect.PtrTo(sub), nil case *ast.ChanType: return nil, fmt.Errorf("channel type not allowed") case *ast.MapType: return nil, fmt.Errorf("map type not allowed") } } // parseType parses a Golang type string and returns a reflect.Type. func parseType(typ string) (reflect.Type, error) { expr, err := parser.ParseExpr(typ) if err != nil { return nil, errors.Wrap(err, "parsing error") } return typeOfExpr(expr) } golang-github-go-restruct-restruct-1.2.0-alpha/typestr_test.go000066400000000000000000000060331412231745000245520ustar00rootroot00000000000000package restruct import ( "go/ast" "go/token" "reflect" "testing" "github.com/stretchr/testify/assert" ) func TestParseType(t *testing.T) { RegisterArrayType([5]*float32{}) tests := []struct { input string typ reflect.Type errstr string }{ // Bad code {"", nil, "parsing error"}, {"Invalid", nil, "unknown type Invalid"}, {"[][435w5[43]]]**//!!!!!!!", nil, "parsing error"}, {"日本語ですか?", nil, "parsing error"}, // Containers {"float32", reflect.TypeOf(float32(0)), ""}, {"*float32", reflect.TypeOf((*float32)(nil)), ""}, {"[5]*float32", reflect.TypeOf([5]*float32{}), ""}, {"[5]*invalid", nil, "unknown type invalid"}, {"[][][]*float32", reflect.TypeOf([][][]*float32{}), ""}, {"[][][]*invalid", nil, "unknown type invalid"}, // Types {"bool", reflect.TypeOf(false), ""}, {"uint8", reflect.TypeOf(uint8(0)), ""}, {"uint16", reflect.TypeOf(uint16(0)), ""}, {"uint32", reflect.TypeOf(uint32(0)), ""}, {"uint64", reflect.TypeOf(uint64(0)), ""}, {"int8", reflect.TypeOf(int8(0)), ""}, {"int16", reflect.TypeOf(int16(0)), ""}, {"int32", reflect.TypeOf(int32(0)), ""}, {"int64", reflect.TypeOf(int64(0)), ""}, {"complex64", reflect.TypeOf(complex64(0)), ""}, {"complex128", reflect.TypeOf(complex128(0)), ""}, {"byte", reflect.TypeOf(byte(0)), ""}, {"rune", reflect.TypeOf(rune(0)), ""}, {"uint", reflect.TypeOf(uint(0)), ""}, {"int", reflect.TypeOf(int(0)), ""}, {"uintptr", reflect.TypeOf(uintptr(0)), ""}, {"string", reflect.TypeOf([]byte{}), ""}, // Illegal types {"chan int", nil, "channel type not allowed"}, {"*chan int", nil, "channel type not allowed"}, {"map[string]string", nil, "map type not allowed"}, {"map[interface{}]interface{}", nil, "map type not allowed"}, // Disallowed expressions {"i + 1", nil, "unexpected expression: *ast.BinaryExpr"}, {"i()", nil, "unexpected expression: *ast.CallExpr"}, } for _, test := range tests { typ, err := parseType(test.input) if typ != nil { assert.Equal(t, test.typ.String(), typ.String()) } if err != nil { assert.Contains(t, err.Error(), test.errstr) } } } func TestBadAst(t *testing.T) { // typeOfExpr should gracefully handle broken AST structures. Let's // construct some. // Array with bad length descriptor. // [Bad]int32 badArr := ast.ArrayType{ Len: ast.NewIdent("Bad"), Elt: ast.NewIdent("int32"), } typ, err := typeOfExpr(&badArr) assert.Equal(t, typ, nil) assert.Equal(t, err.Error(), "invalid array size expression") // Array with bad length descriptor. // ["How about that!"]int32 badArr = ast.ArrayType{ Len: &ast.BasicLit{Kind: token.STRING, Value: `"How about that!"`}, Elt: ast.NewIdent("int32"), } typ, err = typeOfExpr(&badArr) assert.Equal(t, typ, nil) assert.Equal(t, err.Error(), "invalid array size type") // Array with bad length descriptor. // [10ii0]int32 badArr = ast.ArrayType{ Len: &ast.BasicLit{Kind: token.INT, Value: "10ii0"}, Elt: ast.NewIdent("int32"), } typ, err = typeOfExpr(&badArr) assert.Equal(t, typ, nil) assert.NotNil(t, err) }