github.com/shohhei1126/hugo@v0.42.2-0.20180623210752-3d5928889ad7/tpl/collections/reflect_helpers.go (about)

     1  // Copyright 2017 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package collections
    15  
    16  import (
    17  	"errors"
    18  	"fmt"
    19  	"reflect"
    20  	"time"
    21  )
    22  
    23  var (
    24  	zero      reflect.Value
    25  	errorType = reflect.TypeOf((*error)(nil)).Elem()
    26  	timeType  = reflect.TypeOf((*time.Time)(nil)).Elem()
    27  )
    28  
    29  func numberToFloat(v reflect.Value) (float64, error) {
    30  	switch kind := v.Kind(); {
    31  	case isFloat(kind):
    32  		return v.Float(), nil
    33  	case isInt(kind):
    34  		return float64(v.Int()), nil
    35  	case isUint(kind):
    36  		return float64(v.Uint()), nil
    37  	case kind == reflect.Interface:
    38  		return numberToFloat(v.Elem())
    39  	default:
    40  		return 0, fmt.Errorf("Invalid kind %s in numberToFloat", kind)
    41  	}
    42  }
    43  
    44  // There are potential overflows in this function, but the downconversion of
    45  // int64 etc. into int8 etc. is coming from the synthetic unit tests for Union etc.
    46  // TODO(bep) We should consider normalizing the slices to int64 etc.
    47  func convertNumber(v reflect.Value, to reflect.Kind) (reflect.Value, error) {
    48  	var n reflect.Value
    49  	if isFloat(to) {
    50  		f, err := toFloat(v)
    51  		if err != nil {
    52  			return n, err
    53  		}
    54  		switch to {
    55  		case reflect.Float32:
    56  			n = reflect.ValueOf(float32(f))
    57  		default:
    58  			n = reflect.ValueOf(float64(f))
    59  		}
    60  	} else if isInt(to) {
    61  		i, err := toInt(v)
    62  		if err != nil {
    63  			return n, err
    64  		}
    65  		switch to {
    66  		case reflect.Int:
    67  			n = reflect.ValueOf(int(i))
    68  		case reflect.Int8:
    69  			n = reflect.ValueOf(int8(i))
    70  		case reflect.Int16:
    71  			n = reflect.ValueOf(int16(i))
    72  		case reflect.Int32:
    73  			n = reflect.ValueOf(int32(i))
    74  		case reflect.Int64:
    75  			n = reflect.ValueOf(int64(i))
    76  		}
    77  	} else if isUint(to) {
    78  		i, err := toUint(v)
    79  		if err != nil {
    80  			return n, err
    81  		}
    82  		switch to {
    83  		case reflect.Uint:
    84  			n = reflect.ValueOf(uint(i))
    85  		case reflect.Uint8:
    86  			n = reflect.ValueOf(uint8(i))
    87  		case reflect.Uint16:
    88  			n = reflect.ValueOf(uint16(i))
    89  		case reflect.Uint32:
    90  			n = reflect.ValueOf(uint32(i))
    91  		case reflect.Uint64:
    92  			n = reflect.ValueOf(uint64(i))
    93  		}
    94  
    95  	}
    96  
    97  	if !n.IsValid() {
    98  		return n, errors.New("invalid values")
    99  	}
   100  
   101  	return n, nil
   102  
   103  }
   104  
   105  func isNumber(kind reflect.Kind) bool {
   106  	return isInt(kind) || isUint(kind) || isFloat(kind)
   107  }
   108  
   109  func isInt(kind reflect.Kind) bool {
   110  	switch kind {
   111  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   112  		return true
   113  	default:
   114  		return false
   115  	}
   116  }
   117  
   118  func isUint(kind reflect.Kind) bool {
   119  	switch kind {
   120  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   121  		return true
   122  	default:
   123  		return false
   124  	}
   125  }
   126  
   127  func isFloat(kind reflect.Kind) bool {
   128  	switch kind {
   129  	case reflect.Float32, reflect.Float64:
   130  		return true
   131  	default:
   132  		return false
   133  	}
   134  }