mirror of
				https://github.com/gin-gonic/gin.git
				synced 2025-11-04 09:12:12 +08:00 
			
		
		
		
	* Add Makefile to check the following thing. * vet check * fmt check * embedmd check * misspell check Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com> * remove unused variable. Signed-off-by: Bo-Yi Wu <appleboy.tw@gmail.com>
		
			
				
	
	
		
			183 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			183 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// 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 binding
 | 
						|
 | 
						|
import (
 | 
						|
	"errors"
 | 
						|
	"reflect"
 | 
						|
	"strconv"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
func mapForm(ptr interface{}, form map[string][]string) error {
 | 
						|
	typ := reflect.TypeOf(ptr).Elem()
 | 
						|
	val := reflect.ValueOf(ptr).Elem()
 | 
						|
	for i := 0; i < typ.NumField(); i++ {
 | 
						|
		typeField := typ.Field(i)
 | 
						|
		structField := val.Field(i)
 | 
						|
		if !structField.CanSet() {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		structFieldKind := structField.Kind()
 | 
						|
		inputFieldName := typeField.Tag.Get("form")
 | 
						|
		if inputFieldName == "" {
 | 
						|
			inputFieldName = typeField.Name
 | 
						|
 | 
						|
			// if "form" tag is nil, we inspect if the field is a struct.
 | 
						|
			// this would not make sense for JSON parsing but it does for a form
 | 
						|
			// since data is flatten
 | 
						|
			if structFieldKind == reflect.Struct {
 | 
						|
				err := mapForm(structField.Addr().Interface(), form)
 | 
						|
				if err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
				continue
 | 
						|
			}
 | 
						|
		}
 | 
						|
		inputValue, exists := form[inputFieldName]
 | 
						|
		if !exists {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		numElems := len(inputValue)
 | 
						|
		if structFieldKind == reflect.Slice && numElems > 0 {
 | 
						|
			sliceOf := structField.Type().Elem().Kind()
 | 
						|
			slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
 | 
						|
			for i := 0; i < numElems; i++ {
 | 
						|
				if err := setWithProperType(sliceOf, inputValue[i], slice.Index(i)); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
			}
 | 
						|
			val.Field(i).Set(slice)
 | 
						|
		} else {
 | 
						|
			if _, isTime := structField.Interface().(time.Time); isTime {
 | 
						|
				if err := setTimeField(inputValue[0], typeField, structField); err != nil {
 | 
						|
					return err
 | 
						|
				}
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
 | 
						|
	switch valueKind {
 | 
						|
	case reflect.Int:
 | 
						|
		return setIntField(val, 0, structField)
 | 
						|
	case reflect.Int8:
 | 
						|
		return setIntField(val, 8, structField)
 | 
						|
	case reflect.Int16:
 | 
						|
		return setIntField(val, 16, structField)
 | 
						|
	case reflect.Int32:
 | 
						|
		return setIntField(val, 32, structField)
 | 
						|
	case reflect.Int64:
 | 
						|
		return setIntField(val, 64, structField)
 | 
						|
	case reflect.Uint:
 | 
						|
		return setUintField(val, 0, structField)
 | 
						|
	case reflect.Uint8:
 | 
						|
		return setUintField(val, 8, structField)
 | 
						|
	case reflect.Uint16:
 | 
						|
		return setUintField(val, 16, structField)
 | 
						|
	case reflect.Uint32:
 | 
						|
		return setUintField(val, 32, structField)
 | 
						|
	case reflect.Uint64:
 | 
						|
		return setUintField(val, 64, structField)
 | 
						|
	case reflect.Bool:
 | 
						|
		return setBoolField(val, structField)
 | 
						|
	case reflect.Float32:
 | 
						|
		return setFloatField(val, 32, structField)
 | 
						|
	case reflect.Float64:
 | 
						|
		return setFloatField(val, 64, structField)
 | 
						|
	case reflect.String:
 | 
						|
		structField.SetString(val)
 | 
						|
	default:
 | 
						|
		return errors.New("Unknown type")
 | 
						|
	}
 | 
						|
	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 nil
 | 
						|
}
 | 
						|
 | 
						|
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 == "" {
 | 
						|
		return errors.New("Blank time format")
 | 
						|
	}
 | 
						|
 | 
						|
	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
 | 
						|
	}
 | 
						|
 | 
						|
	t, err := time.ParseInLocation(timeFormat, val, l)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	value.Set(reflect.ValueOf(t))
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Don't pass in pointers to bind to. Can lead to bugs. See:
 | 
						|
// https://github.com/codegangsta/martini-contrib/issues/40
 | 
						|
// https://github.com/codegangsta/martini-contrib/pull/34#issuecomment-29683659
 | 
						|
func ensureNotPointer(obj interface{}) {
 | 
						|
	if reflect.TypeOf(obj).Kind() == reflect.Ptr {
 | 
						|
		panic("Pointers are not accepted as binding models")
 | 
						|
	}
 | 
						|
}
 |