Skip to content

Commit

Permalink
JSON tag AST fields + use bitset for tracking required.
Browse files Browse the repository at this point in the history
Fixes samuel#62.
  • Loading branch information
alecthomas committed Apr 7, 2016
1 parent 0e6d91c commit 301b1af
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 59 deletions.
93 changes: 47 additions & 46 deletions parser/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,90 +7,91 @@ package parser
import "fmt"

type Type struct {
Name string
KeyType *Type // If map
ValueType *Type // If map, list, or set
Annotations []*Annotation
Name string `json:"name,omitempty"`
KeyType *Type `json:"key_type,omitempty"` // If map
ValueType *Type `json:"value_type,omitempty"` // If map, list, or set
Annotations []*Annotation `json:"annotations,omitempty"`
}

type Typedef struct {
*Type

Alias string
Annotations []*Annotation
Alias string `json:"alias"`
Annotations []*Annotation `json:"annotations,omitempty"`
}

type EnumValue struct {
Name string
Value int
Annotations []*Annotation
Name string `json:"name"`
Value int `json:"value"`
Annotations []*Annotation `json:"annotations,omitempty"`
}

type Enum struct {
Name string
Values map[string]*EnumValue
Annotations []*Annotation
Name string `json:"name"`
Values map[string]*EnumValue `json:"values"`
Annotations []*Annotation `json:"annotations,omitempty"`
}

type Constant struct {
Name string
Type *Type
Name string `json:"name"`
Type *Type `json:"type"`
Value interface{}
}

type Field struct {
ID int
Name string
Optional bool
Type *Type
Default interface{}
Annotations []*Annotation
ID int `json:"id"`
Name string `json:"name"`
Optional bool `json:"optional"`
Type *Type `json:"type"`
Default interface{} `json:"default,omitempty"`
Annotations []*Annotation `json:"annotations,omitempty"`
}

type Struct struct {
Name string
Fields []*Field
Annotations []*Annotation
Name string `json:"name"`
Fields []*Field `json:"fields"`
Annotations []*Annotation `json:"annotations,omitempty"`
}

type Method struct {
Comment string
Name string
Oneway bool
ReturnType *Type
Arguments []*Field
Exceptions []*Field
Annotations []*Annotation
Comment string `json:"comment"`
Name string `json:"name"`
Oneway bool `json:"one_way"`
ReturnType *Type `json:"return_type"`
Arguments []*Field `json:"arguments"`
Exceptions []*Field `json:"exceptions,omitempty"`
Annotations []*Annotation `json:"annotations,omitempty"`
}

type Service struct {
Name string
Extends string
Methods map[string]*Method
Annotations []*Annotation
Name string `json:"name"`
Extends string `json:"extends,omitempty"`
Methods map[string]*Method `json:"methods"`
Annotations []*Annotation `json:"annotations,omitempty"`
}

type Thrift struct {
Includes map[string]string // name -> unique identifier (absolute path generally)
Typedefs map[string]*Typedef
Namespaces map[string]string
Constants map[string]*Constant
Enums map[string]*Enum
Structs map[string]*Struct
Exceptions map[string]*Struct
Unions map[string]*Struct
Services map[string]*Service
Includes map[string]string `json:"includes,omitempty"` // name -> unique identifier (absolute path generally)
Typedefs map[string]*Typedef `json:"typedefs,omitempty"`
Namespaces map[string]string `json:"namespaces,omitempty"`
Constants map[string]*Constant `json:"constants,omitempty"`
Enums map[string]*Enum `json:"enums,omitempty"`
Structs map[string]*Struct `json:"structs,omitempty"`
Exceptions map[string]*Struct `json:"exceptions,omitempty"`
Unions map[string]*Struct `json:"unions,omitempty"`
Services map[string]*Service `json:"services,omitempty"`
}

type Identifier string

type KeyValue struct {
Key, Value interface{}
Key interface{} `json:"key"`
Value interface{} `json:"value"`
}

type Annotation struct {
Name string
Value string
Name string `json:"name"`
Value string `json:"value"`
}

func (t *Type) String() string {
Expand Down
18 changes: 8 additions & 10 deletions thrift/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func (d *decoder) readValue(thriftType byte, rf reflect.Value) {
}

meta := encodeFields(v.Type())
req := meta.required
req := meta.required.Clone()
for {
ftype, id, err := d.r.ReadFieldBegin()
if err != nil {
Expand All @@ -156,7 +156,7 @@ func (d *decoder) readValue(thriftType byte, rf reflect.Value) {
if !ok {
SkipValue(d.r, ftype)
} else {
req &= ^(uint64(1) << uint64(id))
req.Clear(uint(id))
fieldValue := v.Field(ef.i)
if ftype != ef.fieldType {
d.error(&UnsupportedValueError{Value: fieldValue, Str: "type mismatch"})
Expand All @@ -173,14 +173,12 @@ func (d *decoder) readValue(thriftType byte, rf reflect.Value) {
d.error(err)
}

if req != 0 {
for i := 0; req != 0; i, req = i+1, req>>1 {
if req&1 != 0 {
d.error(&MissingRequiredField{
StructName: v.Type().Name(),
FieldName: meta.fields[i].name,
})
}
if req.Count() > 0 {
for i, e := req.NextSet(0); e; i, e = req.NextSet(i + 1) {
d.error(&MissingRequiredField{
StructName: v.Type().Name(),
FieldName: meta.fields[int(i)].name,
})
}
}
case TypeMap:
Expand Down
8 changes: 5 additions & 3 deletions thrift/thrift.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"reflect"
"sort"
"sync"

"github.com/willf/bitset"
)

// Type identifiers for serialized Thrift
Expand Down Expand Up @@ -201,7 +203,7 @@ type encodeField struct {
}

type structMeta struct {
required uint64 // bitmap of required fields
required *bitset.BitSet // bitmap of required fields
orderedIds []int
fields map[int]encodeField
}
Expand Down Expand Up @@ -229,7 +231,7 @@ func encodeFields(t reflect.Type) structMeta {
}

fs := make(map[int]encodeField)
m = structMeta{fields: fs}
m = structMeta{fields: fs, required: bitset.New(64)}
v := reflect.Zero(t)
n := v.NumField()
for i := 0; i < n; i++ {
Expand Down Expand Up @@ -260,7 +262,7 @@ func encodeFields(t reflect.Type) structMeta {
ef.name = f.Name
ef.required = opts.Contains("required")
if ef.required {
m.required |= 1 << byte(id)
m.required.Set(uint(id))
}
ef.keepEmpty = opts.Contains("keepempty")
if opts.Contains("set") {
Expand Down

0 comments on commit 301b1af

Please sign in to comment.