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  }