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 }