diff --git a/parser/types.go b/parser/types.go index e5d7937..9e67eaa 100644 --- a/parser/types.go +++ b/parser/types.go @@ -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 { diff --git a/thrift/decoder.go b/thrift/decoder.go index 3ccd88e..90bef85 100644 --- a/thrift/decoder.go +++ b/thrift/decoder.go @@ -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 { @@ -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"}) @@ -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: diff --git a/thrift/thrift.go b/thrift/thrift.go index 8a15f93..9936b9b 100644 --- a/thrift/thrift.go +++ b/thrift/thrift.go @@ -10,6 +10,8 @@ import ( "reflect" "sort" "sync" + + "github.com/willf/bitset" ) // Type identifiers for serialized Thrift @@ -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 } @@ -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++ { @@ -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") {