github.com/cloudwego/dynamicgo@v0.2.6-0.20240519101509-707f41b6b834/thrift/annotation/value_mapping.go (about) 1 /** 2 * Copyright 2023 CloudWeGo Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* 18 * Copyright 2021 CloudWeGo Authors 19 * 20 * Licensed under the Apache License, Version 2.0 (the "License"); 21 * you may not use this file except in compliance with the License. 22 * You may obtain a copy of the License at 23 * 24 * http://www.apache.org/licenses/LICENSE-2.0 25 * 26 * Unless required by applicable law or agreed to in writing, software 27 * distributed under the License is distributed on an "AS IS" BASIS, 28 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 29 * See the License for the specific language governing permissions and 30 * limitations under the License. 31 */ 32 33 package annotation 34 35 import ( 36 "context" 37 "errors" 38 "fmt" 39 40 "github.com/cloudwego/dynamicgo/internal/json" 41 "github.com/cloudwego/dynamicgo/internal/native/types" 42 "github.com/cloudwego/dynamicgo/internal/rt" 43 "github.com/cloudwego/dynamicgo/meta" 44 "github.com/cloudwego/dynamicgo/thrift" 45 "github.com/cloudwego/thriftgo/parser" 46 ) 47 48 const ( 49 JSConv = thrift.AnnoType(types.VM_JSCONV) 50 BodyDynamic thrift.AnnoType = thrift.AnnoType(257) 51 ) 52 53 type valueMappingAnnotation struct { 54 typ thrift.AnnoID 55 } 56 57 func newValueMappingAnnotation(typ thrift.AnnoID) valueMappingAnnotation { 58 return valueMappingAnnotation{ 59 typ: typ, 60 } 61 } 62 63 func (self valueMappingAnnotation) ID() thrift.AnnoID { 64 return self.typ 65 } 66 67 func (self valueMappingAnnotation) Make(ctx context.Context, values []parser.Annotation, ast interface{}) (interface{}, error) { 68 if len(values) != 1 { 69 return nil, fmt.Errorf("valueMappingAnnotation only support one value") 70 } 71 switch t := self.typ.Type(); t { 72 case JSConv: 73 return apiJSConv{}, nil 74 case BodyDynamic: 75 return agwBodyDynamic{}, nil 76 default: 77 return nil, errNotImplemented(fmt.Sprintf("unsupported type %v of valueMappingAnnotation", t)) 78 } 79 } 80 81 type agwBodyDynamic struct{} 82 83 func (m agwBodyDynamic) Read(ctx context.Context, p *thrift.BinaryProtocol, field *thrift.FieldDescriptor, out *[]byte) error { 84 if field.Type().Type() != thrift.STRING { 85 return errors.New("body_dynamic only support STRING type") 86 } 87 b, err := p.ReadBinary(false) 88 if err != nil { 89 return err 90 } 91 //FIXME: must validate the json string 92 // ok, _ := encoder.Valid(b) 93 // if !ok { 94 // return fmt.Errorf("invalid json: %s", string(b)) 95 // } 96 *out = append(*out, b...) 97 return nil 98 } 99 100 func (m agwBodyDynamic) Write(ctx context.Context, p *thrift.BinaryProtocol, field *thrift.FieldDescriptor, in []byte) error { 101 if field.Type().Type() != thrift.STRING { 102 return errors.New("body_dynamic only support STRING type") 103 } 104 return p.WriteBinary(in) 105 } 106 107 type apiJSConv struct{} 108 109 func (m apiJSConv) Write(ctx context.Context, p *thrift.BinaryProtocol, field *thrift.FieldDescriptor, in []byte) error { 110 return errNotImplemented("apiJSConv not support writing") 111 } 112 113 func (m apiJSConv) Read(ctx context.Context, p *thrift.BinaryProtocol, field *thrift.FieldDescriptor, out *[]byte) error { 114 switch field.Type().Type() { 115 case thrift.LIST: 116 *out = append(*out, '[') 117 et, n, err := p.ReadListBegin() 118 if err != nil { 119 return err 120 } 121 for i := 0; i < n; i++ { 122 err := appendInt(p, thrift.Type(et), out) 123 if err != nil { 124 return err 125 } 126 if i != n-1 { 127 *out = append(*out, ',') 128 } 129 } 130 *out = append(*out, ']') 131 default: 132 return appendInt(p, field.Type().Type(), out) 133 } 134 return nil 135 } 136 137 func appendInt(p *thrift.BinaryProtocol, typ thrift.Type, out *[]byte) error { 138 *out = append(*out, '"') 139 l := len(*out) 140 if cap(*out)-l < types.MaxInt64StringLen { 141 rt.GuardSlice(out, types.MaxInt64StringLen) 142 } 143 144 switch typ { 145 case thrift.BYTE: 146 i, err := p.ReadByte() 147 if err != nil { 148 return err 149 } 150 *out = json.EncodeInt64(*out, int64(i)) 151 case thrift.I16: 152 i, err := p.ReadI16() 153 if err != nil { 154 return err 155 } 156 *out = json.EncodeInt64(*out, int64(i)) 157 case thrift.I32: 158 i, err := p.ReadI32() 159 if err != nil { 160 return err 161 } 162 *out = json.EncodeInt64(*out, int64(i)) 163 case thrift.I64: 164 i, err := p.ReadI64() 165 if err != nil { 166 return err 167 } 168 *out = json.EncodeInt64(*out, int64(i)) 169 case thrift.DOUBLE: 170 i, err := p.ReadDouble() 171 if err != nil { 172 return err 173 } 174 *out = json.EncodeFloat64(*out, float64(i)) 175 case thrift.STRING: 176 s, err := p.ReadString(false) 177 if err != nil { 178 return err 179 } 180 *out = append(*out, s...) 181 default: 182 return meta.NewError(meta.ErrUnsupportedType, fmt.Sprintf("unsupported type: %v", typ), nil) 183 } 184 185 *out = append(*out, '"') 186 return nil 187 }