blob: 31d9b891a53533406a095d3ae9a064451569f11e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package thrift
import (
"sort"
)
/**
* Helper class that encapsulates field metadata.
*
*/
type TField interface {
Name() string
TypeId() TType
Id() int
String() string
CompareTo(other interface{}) (int, bool)
Equals(other interface{}) bool
}
type tField struct {
name string
typeId TType
id int
}
func NewTFieldDefault() TField {
return ANONYMOUS_FIELD
}
func NewTField(n string, t TType, i int) TField {
return &tField{name: n, typeId: t, id: i}
}
func (p *tField) Name() string {
if p == nil {
return ""
}
return p.name
}
func (p *tField) TypeId() TType {
if p == nil {
return TType(VOID)
}
return p.typeId
}
func (p *tField) Id() int {
if p == nil {
return -1
}
return p.id
}
func (p *tField) String() string {
if p == nil {
return "<nil>"
}
return "<TField name:'" + p.name + "' type:" + string(p.typeId) + " field-id:" + string(p.id) + ">"
}
func (p *tField) CompareTo(other interface{}) (int, bool) {
if other == nil {
return 1, true
}
if data, ok := other.(TField); ok {
if p.Id() != data.Id() {
return CompareInt(p.Id(), data.Id()), true
}
if p.TypeId() != data.TypeId() {
return CompareByte(byte(p.TypeId()), byte(data.TypeId())), true
}
return CompareString(p.Name(), data.Name()), true
}
return 0, false
}
func (p *tField) Equals(other interface{}) bool {
if p == nil {
return other == nil
}
if other == nil {
return false
}
if data, ok := other.(TField); ok {
return p.TypeId() == data.TypeId() && p.Id() == data.Id()
}
return false
}
var ANONYMOUS_FIELD TField
type tFieldArray []TField
func (p tFieldArray) Len() int {
return len(p)
}
func (p tFieldArray) Less(i, j int) bool {
return p[i].Id() < p[j].Id()
}
func (p tFieldArray) Swap(i, j int) {
p[i], p[j] = p[j], p[i]
}
type TFieldContainer interface {
TContainer
FieldNameFromFieldId(id int) string
FieldIdFromFieldName(name string) int
FieldFromFieldId(id int) TField
FieldFromFieldName(name string) TField
At(i int) TField
Iter() <-chan TField
}
type tFieldContainer struct {
fields []TField
nameToFieldMap map[string]TField
idToFieldMap map[int]TField
}
func NewTFieldContainer(fields []TField) TFieldContainer {
sortedFields := make([]TField, len(fields))
nameToFieldMap := make(map[string]TField)
idToFieldMap := make(map[int]TField)
for i, field := range fields {
sortedFields[i] = field
idToFieldMap[field.Id()] = field
if field.Name() != "" {
nameToFieldMap[field.Name()] = field
}
}
sort.Sort(tFieldArray(sortedFields))
return &tFieldContainer{
fields: fields,
nameToFieldMap: nameToFieldMap,
idToFieldMap: idToFieldMap,
}
}
func (p *tFieldContainer) FieldNameFromFieldId(id int) string {
if field, ok := p.idToFieldMap[id]; ok {
return field.Name()
}
return ""
}
func (p *tFieldContainer) FieldIdFromFieldName(name string) int {
if field, ok := p.nameToFieldMap[name]; ok {
return field.Id()
}
return -1
}
func (p *tFieldContainer) FieldFromFieldId(id int) TField {
if field, ok := p.idToFieldMap[id]; ok {
return field
}
return ANONYMOUS_FIELD
}
func (p *tFieldContainer) FieldFromFieldName(name string) TField {
if field, ok := p.nameToFieldMap[name]; ok {
return field
}
return ANONYMOUS_FIELD
}
func (p *tFieldContainer) Len() int {
return len(p.fields)
}
func (p *tFieldContainer) At(i int) TField {
return p.FieldFromFieldId(i)
}
func (p *tFieldContainer) Contains(data interface{}) bool {
if i, ok := data.(int); ok {
for _, field := range p.fields {
if field.Id() == i {
return true
}
}
} else if i, ok := data.(int16); ok {
for _, field := range p.fields {
if field.Id() == int(i) {
return true
}
}
} else if s, ok := data.(string); ok {
for _, field := range p.fields {
if field.Name() == s {
return true
}
}
} else if f, ok := data.(TField); ok {
for _, field := range p.fields {
if field.Equals(f) {
return true
}
}
}
return false
}
func (p *tFieldContainer) Equals(other interface{}) bool {
if other == nil {
return false
}
if data, ok := other.(TFieldContainer); ok {
if p.Len() != data.Len() {
return false
}
for _, field := range p.fields {
if !data.Contains(field) {
return false
}
}
return true
}
return false
}
func (p *tFieldContainer) CompareTo(other interface{}) (int, bool) {
if other == nil {
return 1, true
}
if data, ok := other.(TFieldContainer); ok {
cont, ok2 := data.(*tFieldContainer)
if ok2 && p == cont {
return 0, true
}
if cmp := CompareInt(p.Len(), data.Len()); cmp != 0 {
return cmp, true
}
for _, field := range p.fields {
if cmp, ok3 := field.CompareTo(data.At(field.Id())); !ok3 || cmp != 0 {
return cmp, ok3
}
}
return 0, true
}
return 0, false
}
func (p *tFieldContainer) Iter() <-chan TField {
c := make(chan TField)
go p.iterate(c)
return c
}
func (p *tFieldContainer) iterate(c chan<- TField) {
for _, v := range p.fields {
c <- v
}
close(c)
}
func init() {
ANONYMOUS_FIELD = NewTField("", STOP, 0)
}