go.uber.org/cadence@v1.2.9/internal/common/thrift_util.go (about)

     1  // Copyright (c) 2017 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package common
    22  
    23  import (
    24  	"context"
    25  	"reflect"
    26  
    27  	"github.com/apache/thrift/lib/go/thrift"
    28  )
    29  
    30  // TSerialize is used to serialize thrift TStruct to []byte
    31  func TSerialize(ctx context.Context, t thrift.TStruct) (b []byte, err error) {
    32  	return thrift.NewTSerializer().Write(ctx, t)
    33  }
    34  
    35  // TListSerialize is used to serialize list of thrift TStruct to []byte
    36  func TListSerialize(ts []thrift.TStruct) (b []byte, err error) {
    37  	if ts == nil {
    38  		return
    39  	}
    40  
    41  	t := thrift.NewTSerializer()
    42  	t.Transport.Reset()
    43  
    44  	// NOTE: we don't write any markers as thrift by design being a streaming protocol doesn't
    45  	// recommend writing length.
    46  
    47  	// TODO populate context from argument
    48  	ctx := context.Background()
    49  	for _, v := range ts {
    50  		if e := v.Write(ctx, t.Protocol); e != nil {
    51  			err = thrift.PrependError("error writing TStruct: ", e)
    52  			return
    53  		}
    54  	}
    55  
    56  	if err = t.Protocol.Flush(ctx); err != nil {
    57  		return
    58  	}
    59  
    60  	if err = t.Transport.Flush(ctx); err != nil {
    61  		return
    62  	}
    63  
    64  	b = t.Transport.Bytes()
    65  	return
    66  }
    67  
    68  // TDeserialize is used to deserialize []byte to thrift TStruct
    69  func TDeserialize(ctx context.Context, t thrift.TStruct, b []byte) (err error) {
    70  	return thrift.NewTDeserializer().Read(ctx, t, b)
    71  }
    72  
    73  // TListDeserialize is used to deserialize []byte to list of thrift TStruct
    74  func TListDeserialize(ts []thrift.TStruct, b []byte) (err error) {
    75  	t := thrift.NewTDeserializer()
    76  	err = nil
    77  	if _, err = t.Transport.Write(b); err != nil {
    78  		return
    79  	}
    80  
    81  	// TODO populate context from argument
    82  	ctx := context.Background()
    83  	for i := 0; i < len(ts); i++ {
    84  		if e := ts[i].Read(ctx, t.Protocol); e != nil {
    85  			err = thrift.PrependError("error reading TStruct: ", e)
    86  			return
    87  		}
    88  	}
    89  
    90  	return
    91  }
    92  
    93  // IsUseThriftEncoding checks if the objects passed in are all encoded using thrift.
    94  func IsUseThriftEncoding(objs []interface{}) bool {
    95  	// NOTE: our criteria to use which encoder is simple if all the types are serializable using thrift then we use
    96  	// thrift encoder. For everything else we default to gob.
    97  
    98  	if len(objs) == 0 {
    99  		return false
   100  	}
   101  
   102  	for i := 0; i < len(objs); i++ {
   103  		if !IsThriftType(objs[i]) {
   104  			return false
   105  		}
   106  	}
   107  	return true
   108  }
   109  
   110  // IsUseThriftDecoding checks if the objects passed in are all de-serializable using thrift.
   111  func IsUseThriftDecoding(objs []interface{}) bool {
   112  	// NOTE: our criteria to use which encoder is simple if all the types are de-serializable using thrift then we use
   113  	// thrift decoder. For everything else we default to gob.
   114  
   115  	if len(objs) == 0 {
   116  		return false
   117  	}
   118  
   119  	for i := 0; i < len(objs); i++ {
   120  		rVal := reflect.ValueOf(objs[i])
   121  		if rVal.Kind() != reflect.Ptr || !IsThriftType(reflect.Indirect(rVal).Interface()) {
   122  			return false
   123  		}
   124  	}
   125  	return true
   126  }
   127  
   128  // IsThriftType checks whether the object passed in is a thrift encoded object.
   129  func IsThriftType(v interface{}) bool {
   130  	// NOTE: Thrift serialization works only if the values are pointers.
   131  	// Thrift has a validation that it meets thift.TStruct which has Read/Write pointer receivers.
   132  
   133  	if reflect.ValueOf(v).Kind() != reflect.Ptr {
   134  		return false
   135  	}
   136  	t := reflect.TypeOf((*thrift.TStruct)(nil)).Elem()
   137  	return reflect.TypeOf(v).Implements(t)
   138  }