mirror of
https://github.com/xxjwxc/ginrpc.git
synced 2025-10-07 07:50:56 +08:00
fix get on json
添加get模式支持json 标签,主要用于proto自动生成文件
This commit is contained in:
20
common.go
20
common.go
@@ -24,10 +24,6 @@ import (
|
|||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *_Base) parseReqResp(typ reflect.Type, isObj bool) (reflect.Type, reflect.Type) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkHandlerFunc Judge whether to match rules
|
// checkHandlerFunc Judge whether to match rules
|
||||||
func (b *_Base) checkHandlerFunc(typ reflect.Type, isObj bool) (int, bool) { // 判断是否匹配规则,返回参数个数
|
func (b *_Base) checkHandlerFunc(typ reflect.Type, isObj bool) (int, bool) { // 判断是否匹配规则,返回参数个数
|
||||||
offset := 0
|
offset := 0
|
||||||
@@ -267,8 +263,8 @@ func (b *_Base) getCallObj3(tvl, obj reflect.Value, methodName string) (func(*gi
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var returnValues []reflect.Value
|
// var returnValues []reflect.Value
|
||||||
returnValues = tvl.Call([]reflect.Value{obj, reflect.ValueOf(apiFun(c)), req})
|
returnValues := tvl.Call([]reflect.Value{obj, reflect.ValueOf(apiFun(c)), req})
|
||||||
|
|
||||||
if returnValues != nil {
|
if returnValues != nil {
|
||||||
bainfo.Resp = returnValues[0].Interface()
|
bainfo.Resp = returnValues[0].Interface()
|
||||||
@@ -320,11 +316,14 @@ func (b *_Base) handErrorString(c *gin.Context, req reflect.Value, err error) {
|
|||||||
msg := message.GetErrorMsg(message.ParameterInvalid)
|
msg := message.GetErrorMsg(message.ParameterInvalid)
|
||||||
msg.Error = fmt.Sprintf("req param : %v", strings.Join(fields, ";"))
|
msg.Error = fmt.Sprintf("req param : %v", strings.Join(fields, ";"))
|
||||||
c.JSON(http.StatusBadRequest, msg)
|
c.JSON(http.StatusBadRequest, msg)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *_Base) unmarshal(c *gin.Context, v interface{}) error {
|
func (b *_Base) unmarshal(c *gin.Context, v interface{}) error {
|
||||||
return c.ShouldBind(v)
|
err := c.ShouldBind(v)
|
||||||
|
if err != nil || strings.EqualFold(c.Request.Method, "get") { // get 模式 补刀json
|
||||||
|
err = mapJson(v, c.Request.Form)
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *_Base) parserStruct(req, resp *parmInfo, astPkg *ast.Package, modPkg, modFile string) (r, p *mydoc.StructInfo) {
|
func (b *_Base) parserStruct(req, resp *parmInfo, astPkg *ast.Package, modPkg, modFile string) (r, p *mydoc.StructInfo) {
|
||||||
@@ -424,9 +423,10 @@ func (b *_Base) parserComments(f *ast.FuncDecl, objName, objFunc string, imports
|
|||||||
gc.Methods = strings.Split(methods, ",")
|
gc.Methods = strings.Split(methods, ",")
|
||||||
}
|
}
|
||||||
gcs = append(gcs, gc)
|
gcs = append(gcs, gc)
|
||||||
} else {
|
|
||||||
// return nil, errors.New("Router information is missing")
|
|
||||||
}
|
}
|
||||||
|
// else {
|
||||||
|
// return nil, errors.New("Router information is missing")
|
||||||
|
// }
|
||||||
} else if strings.HasPrefix(t, objFunc) { // find note
|
} else if strings.HasPrefix(t, objFunc) { // find note
|
||||||
t = strings.TrimSpace(strings.TrimPrefix(t, objFunc))
|
t = strings.TrimSpace(strings.TrimPrefix(t, objFunc))
|
||||||
note += t
|
note += t
|
||||||
|
388
form_mapping.go
Normal file
388
form_mapping.go
Normal file
@@ -0,0 +1,388 @@
|
|||||||
|
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ginrpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/xxjwxc/ginrpc/internal/bytesconv"
|
||||||
|
"github.com/xxjwxc/ginrpc/internal/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errUnknownType = errors.New("unknown type")
|
||||||
|
|
||||||
|
func mapJson(ptr interface{}, form map[string][]string) error {
|
||||||
|
return mapFormByTag(ptr, form, "json")
|
||||||
|
}
|
||||||
|
|
||||||
|
var emptyField = reflect.StructField{}
|
||||||
|
|
||||||
|
func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error {
|
||||||
|
// Check if ptr is a map
|
||||||
|
ptrVal := reflect.ValueOf(ptr)
|
||||||
|
var pointed interface{}
|
||||||
|
if ptrVal.Kind() == reflect.Ptr {
|
||||||
|
ptrVal = ptrVal.Elem()
|
||||||
|
pointed = ptrVal.Interface()
|
||||||
|
}
|
||||||
|
if ptrVal.Kind() == reflect.Map &&
|
||||||
|
ptrVal.Type().Key().Kind() == reflect.String {
|
||||||
|
if pointed != nil {
|
||||||
|
ptr = pointed
|
||||||
|
}
|
||||||
|
return setFormMap(ptr, form)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mappingByPtr(ptr, formSource(form), tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setter tries to set value on a walking by fields of a struct
|
||||||
|
type setter interface {
|
||||||
|
TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type formSource map[string][]string
|
||||||
|
|
||||||
|
var _ setter = formSource(nil)
|
||||||
|
|
||||||
|
// TrySet tries to set a value by request's form source (like map[string][]string)
|
||||||
|
func (form formSource) TrySet(value reflect.Value, field reflect.StructField, tagValue string, opt setOptions) (isSetted bool, err error) {
|
||||||
|
return setByForm(value, field, form, tagValue, opt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func mappingByPtr(ptr interface{}, setter setter, tag string) error {
|
||||||
|
_, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
|
||||||
|
if field.Tag.Get(tag) == "-" { // just ignoring this field
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var vKind = value.Kind()
|
||||||
|
|
||||||
|
if vKind == reflect.Ptr {
|
||||||
|
var isNew bool
|
||||||
|
vPtr := value
|
||||||
|
if value.IsNil() {
|
||||||
|
isNew = true
|
||||||
|
vPtr = reflect.New(value.Type().Elem())
|
||||||
|
}
|
||||||
|
isSetted, err := mapping(vPtr.Elem(), field, setter, tag)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if isNew && isSetted {
|
||||||
|
value.Set(vPtr)
|
||||||
|
}
|
||||||
|
return isSetted, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if vKind != reflect.Struct || !field.Anonymous {
|
||||||
|
ok, err := tryToSetValue(value, field, setter, tag)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if vKind == reflect.Struct {
|
||||||
|
tValue := value.Type()
|
||||||
|
|
||||||
|
var isSetted bool
|
||||||
|
for i := 0; i < value.NumField(); i++ {
|
||||||
|
sf := tValue.Field(i)
|
||||||
|
if sf.PkgPath != "" && !sf.Anonymous { // unexported
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ok, err := mapping(value.Field(i), tValue.Field(i), setter, tag)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
isSetted = isSetted || ok
|
||||||
|
}
|
||||||
|
return isSetted, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type setOptions struct {
|
||||||
|
isDefaultExists bool
|
||||||
|
defaultValue string
|
||||||
|
}
|
||||||
|
|
||||||
|
func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
|
||||||
|
var tagValue string
|
||||||
|
var setOpt setOptions
|
||||||
|
|
||||||
|
tagValue = field.Tag.Get(tag)
|
||||||
|
tagValue, opts := head(tagValue, ",")
|
||||||
|
|
||||||
|
if tagValue == "" { // default value is FieldName
|
||||||
|
tagValue = field.Name
|
||||||
|
}
|
||||||
|
if tagValue == "" { // when field is "emptyField" variable
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var opt string
|
||||||
|
for len(opts) > 0 {
|
||||||
|
opt, opts = head(opts, ",")
|
||||||
|
|
||||||
|
if k, v := head(opt, "="); k == "default" {
|
||||||
|
setOpt.isDefaultExists = true
|
||||||
|
setOpt.defaultValue = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return setter.TrySet(value, field, tagValue, setOpt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, tagValue string, opt setOptions) (isSetted bool, err error) {
|
||||||
|
vs, ok := form[tagValue]
|
||||||
|
if !ok && !opt.isDefaultExists {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value.Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
if !ok {
|
||||||
|
vs = []string{opt.defaultValue}
|
||||||
|
}
|
||||||
|
return true, setSlice(vs, value, field)
|
||||||
|
case reflect.Array:
|
||||||
|
if !ok {
|
||||||
|
vs = []string{opt.defaultValue}
|
||||||
|
}
|
||||||
|
if len(vs) != value.Len() {
|
||||||
|
return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String())
|
||||||
|
}
|
||||||
|
return true, setArray(vs, value, field)
|
||||||
|
default:
|
||||||
|
var val string
|
||||||
|
if !ok {
|
||||||
|
val = opt.defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(vs) > 0 {
|
||||||
|
val = vs[0]
|
||||||
|
}
|
||||||
|
return true, setWithProperType(val, value, field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setWithProperType(val string, value reflect.Value, field reflect.StructField) error {
|
||||||
|
switch value.Kind() {
|
||||||
|
case reflect.Int:
|
||||||
|
return setIntField(val, 0, value)
|
||||||
|
case reflect.Int8:
|
||||||
|
return setIntField(val, 8, value)
|
||||||
|
case reflect.Int16:
|
||||||
|
return setIntField(val, 16, value)
|
||||||
|
case reflect.Int32:
|
||||||
|
return setIntField(val, 32, value)
|
||||||
|
case reflect.Int64:
|
||||||
|
switch value.Interface().(type) {
|
||||||
|
case time.Duration:
|
||||||
|
return setTimeDuration(val, value, field)
|
||||||
|
}
|
||||||
|
return setIntField(val, 64, value)
|
||||||
|
case reflect.Uint:
|
||||||
|
return setUintField(val, 0, value)
|
||||||
|
case reflect.Uint8:
|
||||||
|
return setUintField(val, 8, value)
|
||||||
|
case reflect.Uint16:
|
||||||
|
return setUintField(val, 16, value)
|
||||||
|
case reflect.Uint32:
|
||||||
|
return setUintField(val, 32, value)
|
||||||
|
case reflect.Uint64:
|
||||||
|
return setUintField(val, 64, value)
|
||||||
|
case reflect.Bool:
|
||||||
|
return setBoolField(val, value)
|
||||||
|
case reflect.Float32:
|
||||||
|
return setFloatField(val, 32, value)
|
||||||
|
case reflect.Float64:
|
||||||
|
return setFloatField(val, 64, value)
|
||||||
|
case reflect.String:
|
||||||
|
value.SetString(val)
|
||||||
|
case reflect.Struct:
|
||||||
|
switch value.Interface().(type) {
|
||||||
|
case time.Time:
|
||||||
|
return setTimeField(val, field, value)
|
||||||
|
}
|
||||||
|
return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface())
|
||||||
|
case reflect.Map:
|
||||||
|
return json.Unmarshal(bytesconv.StringToBytes(val), value.Addr().Interface())
|
||||||
|
default:
|
||||||
|
return errUnknownType
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setIntField(val string, bitSize int, field reflect.Value) error {
|
||||||
|
if val == "" {
|
||||||
|
val = "0"
|
||||||
|
}
|
||||||
|
intVal, err := strconv.ParseInt(val, 10, bitSize)
|
||||||
|
if err == nil {
|
||||||
|
field.SetInt(intVal)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUintField(val string, bitSize int, field reflect.Value) error {
|
||||||
|
if val == "" {
|
||||||
|
val = "0"
|
||||||
|
}
|
||||||
|
uintVal, err := strconv.ParseUint(val, 10, bitSize)
|
||||||
|
if err == nil {
|
||||||
|
field.SetUint(uintVal)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func setBoolField(val string, field reflect.Value) error {
|
||||||
|
if val == "" {
|
||||||
|
val = "false"
|
||||||
|
}
|
||||||
|
boolVal, err := strconv.ParseBool(val)
|
||||||
|
if err == nil {
|
||||||
|
field.SetBool(boolVal)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func setFloatField(val string, bitSize int, field reflect.Value) error {
|
||||||
|
if val == "" {
|
||||||
|
val = "0.0"
|
||||||
|
}
|
||||||
|
floatVal, err := strconv.ParseFloat(val, bitSize)
|
||||||
|
if err == nil {
|
||||||
|
field.SetFloat(floatVal)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
|
||||||
|
timeFormat := structField.Tag.Get("time_format")
|
||||||
|
if timeFormat == "" {
|
||||||
|
timeFormat = time.RFC3339
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tf := strings.ToLower(timeFormat); tf {
|
||||||
|
case "unix", "unixnano":
|
||||||
|
tv, err := strconv.ParseInt(val, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d := time.Duration(1)
|
||||||
|
if tf == "unixnano" {
|
||||||
|
d = time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
t := time.Unix(tv/int64(d), tv%int64(d))
|
||||||
|
value.Set(reflect.ValueOf(t))
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if val == "" {
|
||||||
|
value.Set(reflect.ValueOf(time.Time{}))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
l := time.Local
|
||||||
|
if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC {
|
||||||
|
l = time.UTC
|
||||||
|
}
|
||||||
|
|
||||||
|
if locTag := structField.Tag.Get("time_location"); locTag != "" {
|
||||||
|
loc, err := time.LoadLocation(locTag)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
l = loc
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := time.ParseInLocation(timeFormat, val, l)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
value.Set(reflect.ValueOf(t))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setArray(vals []string, value reflect.Value, field reflect.StructField) error {
|
||||||
|
for i, s := range vals {
|
||||||
|
err := setWithProperType(s, value.Index(i), field)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setSlice(vals []string, value reflect.Value, field reflect.StructField) error {
|
||||||
|
slice := reflect.MakeSlice(value.Type(), len(vals), len(vals))
|
||||||
|
err := setArray(vals, slice, field)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
value.Set(slice)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTimeDuration(val string, value reflect.Value, field reflect.StructField) error {
|
||||||
|
d, err := time.ParseDuration(val)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
value.Set(reflect.ValueOf(d))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func head(str, sep string) (head string, tail string) {
|
||||||
|
idx := strings.Index(str, sep)
|
||||||
|
if idx < 0 {
|
||||||
|
return str, ""
|
||||||
|
}
|
||||||
|
return str[:idx], str[idx+len(sep):]
|
||||||
|
}
|
||||||
|
|
||||||
|
func setFormMap(ptr interface{}, form map[string][]string) error {
|
||||||
|
el := reflect.TypeOf(ptr).Elem()
|
||||||
|
|
||||||
|
if el.Kind() == reflect.Slice {
|
||||||
|
ptrMap, ok := ptr.(map[string][]string)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("cannot convert to map slices of strings")
|
||||||
|
}
|
||||||
|
for k, v := range form {
|
||||||
|
ptrMap[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrMap, ok := ptr.(map[string]string)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("cannot convert to map of strings")
|
||||||
|
}
|
||||||
|
for k, v := range form {
|
||||||
|
ptrMap[k] = v[len(v)-1] // pick last
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
2
go.mod
2
go.mod
@@ -5,6 +5,8 @@ go 1.12
|
|||||||
require (
|
require (
|
||||||
github.com/gin-gonic/gin v1.7.2
|
github.com/gin-gonic/gin v1.7.2
|
||||||
github.com/go-playground/validator/v10 v10.4.1
|
github.com/go-playground/validator/v10 v10.4.1
|
||||||
|
github.com/goccy/go-json v0.7.0
|
||||||
|
github.com/json-iterator/go v1.1.9
|
||||||
github.com/xxjwxc/public v0.0.0-20210604020721-3cc06f1e88c0
|
github.com/xxjwxc/public v0.0.0-20210604020721-3cc06f1e88c0
|
||||||
google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea // indirect
|
google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea // indirect
|
||||||
google.golang.org/grpc v1.29.1
|
google.golang.org/grpc v1.29.1
|
||||||
|
2
go.sum
2
go.sum
@@ -61,6 +61,8 @@ github.com/go-redis/redis/v8 v8.4.11/go.mod h1:d5yY/TlkQyYBSBHnXUmnf1OrHbyQere5J
|
|||||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/goccy/go-json v0.7.0 h1:ZsGt0RuL2c4EP8X33Ij8caSlBrcFx7eYKjlKG4HOWf8=
|
||||||
|
github.com/goccy/go-json v0.7.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
|
24
internal/bytesconv/bytesconv.go
Normal file
24
internal/bytesconv/bytesconv.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2020 Gin Core Team. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bytesconv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StringToBytes converts string to byte slice without a memory allocation.
|
||||||
|
func StringToBytes(s string) []byte {
|
||||||
|
return *(*[]byte)(unsafe.Pointer(
|
||||||
|
&struct {
|
||||||
|
string
|
||||||
|
Cap int
|
||||||
|
}{s, len(s)},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BytesToString converts byte slice to string without a memory allocation.
|
||||||
|
func BytesToString(b []byte) string {
|
||||||
|
return *(*string)(unsafe.Pointer(&b))
|
||||||
|
}
|
99
internal/bytesconv/bytesconv_test.go
Normal file
99
internal/bytesconv/bytesconv_test.go
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// Copyright 2020 Gin Core Team. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bytesconv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"math/rand"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var testString = "Albert Einstein: Logic will get you from A to B. Imagination will take you everywhere."
|
||||||
|
var testBytes = []byte(testString)
|
||||||
|
|
||||||
|
func rawBytesToStr(b []byte) string {
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func rawStrToBytes(s string) []byte {
|
||||||
|
return []byte(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// go test -v
|
||||||
|
|
||||||
|
func TestBytesToString(t *testing.T) {
|
||||||
|
data := make([]byte, 1024)
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
rand.Read(data)
|
||||||
|
if rawBytesToStr(data) != BytesToString(data) {
|
||||||
|
t.Fatal("don't match")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
const (
|
||||||
|
letterIdxBits = 6 // 6 bits to represent a letter index
|
||||||
|
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
||||||
|
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
||||||
|
)
|
||||||
|
|
||||||
|
var src = rand.NewSource(time.Now().UnixNano())
|
||||||
|
|
||||||
|
func RandStringBytesMaskImprSrcSB(n int) string {
|
||||||
|
sb := strings.Builder{}
|
||||||
|
sb.Grow(n)
|
||||||
|
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
|
||||||
|
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
|
||||||
|
if remain == 0 {
|
||||||
|
cache, remain = src.Int63(), letterIdxMax
|
||||||
|
}
|
||||||
|
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
||||||
|
sb.WriteByte(letterBytes[idx])
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
cache >>= letterIdxBits
|
||||||
|
remain--
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringToBytes(t *testing.T) {
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
s := RandStringBytesMaskImprSrcSB(64)
|
||||||
|
if !bytes.Equal(rawStrToBytes(s), StringToBytes(s)) {
|
||||||
|
t.Fatal("don't match")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// go test -v -run=none -bench=^BenchmarkBytesConv -benchmem=true
|
||||||
|
|
||||||
|
func BenchmarkBytesConvBytesToStrRaw(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
rawBytesToStr(testBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkBytesConvBytesToStr(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
BytesToString(testBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkBytesConvStrToBytesRaw(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
rawStrToBytes(testString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkBytesConvStrToBytes(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
StringToBytes(testString)
|
||||||
|
}
|
||||||
|
}
|
23
internal/json/go_json.go
Normal file
23
internal/json/go_json.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2017 Bo-Yi Wu. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build go_json
|
||||||
|
// +build go_json
|
||||||
|
|
||||||
|
package json
|
||||||
|
|
||||||
|
import json "github.com/goccy/go-json"
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Marshal is exported by gin/json package.
|
||||||
|
Marshal = json.Marshal
|
||||||
|
// Unmarshal is exported by gin/json package.
|
||||||
|
Unmarshal = json.Unmarshal
|
||||||
|
// MarshalIndent is exported by gin/json package.
|
||||||
|
MarshalIndent = json.MarshalIndent
|
||||||
|
// NewDecoder is exported by gin/json package.
|
||||||
|
NewDecoder = json.NewDecoder
|
||||||
|
// NewEncoder is exported by gin/json package.
|
||||||
|
NewEncoder = json.NewEncoder
|
||||||
|
)
|
23
internal/json/json.go
Normal file
23
internal/json/json.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2017 Bo-Yi Wu. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !jsoniter && !go_json
|
||||||
|
// +build !jsoniter,!go_json
|
||||||
|
|
||||||
|
package json
|
||||||
|
|
||||||
|
import "encoding/json"
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Marshal is exported by gin/json package.
|
||||||
|
Marshal = json.Marshal
|
||||||
|
// Unmarshal is exported by gin/json package.
|
||||||
|
Unmarshal = json.Unmarshal
|
||||||
|
// MarshalIndent is exported by gin/json package.
|
||||||
|
MarshalIndent = json.MarshalIndent
|
||||||
|
// NewDecoder is exported by gin/json package.
|
||||||
|
NewDecoder = json.NewDecoder
|
||||||
|
// NewEncoder is exported by gin/json package.
|
||||||
|
NewEncoder = json.NewEncoder
|
||||||
|
)
|
24
internal/json/jsoniter.go
Normal file
24
internal/json/jsoniter.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2017 Bo-Yi Wu. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build jsoniter
|
||||||
|
// +build jsoniter
|
||||||
|
|
||||||
|
package json
|
||||||
|
|
||||||
|
import jsoniter "github.com/json-iterator/go"
|
||||||
|
|
||||||
|
var (
|
||||||
|
json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
// Marshal is exported by gin/json package.
|
||||||
|
Marshal = json.Marshal
|
||||||
|
// Unmarshal is exported by gin/json package.
|
||||||
|
Unmarshal = json.Unmarshal
|
||||||
|
// MarshalIndent is exported by gin/json package.
|
||||||
|
MarshalIndent = json.MarshalIndent
|
||||||
|
// NewDecoder is exported by gin/json package.
|
||||||
|
NewDecoder = json.NewDecoder
|
||||||
|
// NewEncoder is exported by gin/json package.
|
||||||
|
NewEncoder = json.NewEncoder
|
||||||
|
)
|
Reference in New Issue
Block a user