github.com/gogf/gf@v1.16.9/util/gconv/gconv_maptomap.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package gconv
     8  
     9  import (
    10  	"github.com/gogf/gf/errors/gcode"
    11  	"github.com/gogf/gf/errors/gerror"
    12  	"github.com/gogf/gf/internal/json"
    13  	"reflect"
    14  )
    15  
    16  // MapToMap converts any map type variable `params` to another map type variable `pointer`
    17  // using reflect.
    18  // See doMapToMap.
    19  func MapToMap(params interface{}, pointer interface{}, mapping ...map[string]string) error {
    20  	return doMapToMap(params, pointer, mapping...)
    21  }
    22  
    23  // doMapToMap converts any map type variable `params` to another map type variable `pointer`.
    24  //
    25  // The parameter `params` can be any type of map, like:
    26  // map[string]string, map[string]struct, map[string]*struct, etc.
    27  //
    28  // The parameter `pointer` should be type of *map, like:
    29  // map[int]string, map[string]struct, map[string]*struct, etc.
    30  //
    31  // The optional parameter `mapping` is used for struct attribute to map key mapping, which makes
    32  // sense only if the items of original map `params` is type struct.
    33  func doMapToMap(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
    34  	// If given `params` is JSON, it then uses json.Unmarshal doing the converting.
    35  	switch r := params.(type) {
    36  	case []byte:
    37  		if json.Valid(r) {
    38  			if rv, ok := pointer.(reflect.Value); ok {
    39  				if rv.Kind() == reflect.Ptr {
    40  					return json.UnmarshalUseNumber(r, rv.Interface())
    41  				}
    42  			} else {
    43  				return json.UnmarshalUseNumber(r, pointer)
    44  			}
    45  		}
    46  	case string:
    47  		if paramsBytes := []byte(r); json.Valid(paramsBytes) {
    48  			if rv, ok := pointer.(reflect.Value); ok {
    49  				if rv.Kind() == reflect.Ptr {
    50  					return json.UnmarshalUseNumber(paramsBytes, rv.Interface())
    51  				}
    52  			} else {
    53  				return json.UnmarshalUseNumber(paramsBytes, pointer)
    54  			}
    55  		}
    56  	}
    57  	var (
    58  		paramsRv                  reflect.Value
    59  		paramsKind                reflect.Kind
    60  		keyToAttributeNameMapping map[string]string
    61  	)
    62  	if len(mapping) > 0 {
    63  		keyToAttributeNameMapping = mapping[0]
    64  	}
    65  	if v, ok := params.(reflect.Value); ok {
    66  		paramsRv = v
    67  	} else {
    68  		paramsRv = reflect.ValueOf(params)
    69  	}
    70  	paramsKind = paramsRv.Kind()
    71  	if paramsKind == reflect.Ptr {
    72  		paramsRv = paramsRv.Elem()
    73  		paramsKind = paramsRv.Kind()
    74  	}
    75  	if paramsKind != reflect.Map {
    76  		return doMapToMap(Map(params), pointer, mapping...)
    77  	}
    78  	// Empty params map, no need continue.
    79  	if paramsRv.Len() == 0 {
    80  		return nil
    81  	}
    82  	var pointerRv reflect.Value
    83  	if v, ok := pointer.(reflect.Value); ok {
    84  		pointerRv = v
    85  	} else {
    86  		pointerRv = reflect.ValueOf(pointer)
    87  	}
    88  	pointerKind := pointerRv.Kind()
    89  	for pointerKind == reflect.Ptr {
    90  		pointerRv = pointerRv.Elem()
    91  		pointerKind = pointerRv.Kind()
    92  	}
    93  	if pointerKind != reflect.Map {
    94  		return gerror.NewCodef(gcode.CodeInvalidParameter, "pointer should be type of *map, but got:%s", pointerKind)
    95  	}
    96  	defer func() {
    97  		// Catch the panic, especially the reflect operation panics.
    98  		if exception := recover(); exception != nil {
    99  			if e, ok := exception.(errorStack); ok {
   100  				err = e
   101  			} else {
   102  				err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%v", exception)
   103  			}
   104  		}
   105  	}()
   106  	var (
   107  		paramsKeys       = paramsRv.MapKeys()
   108  		pointerKeyType   = pointerRv.Type().Key()
   109  		pointerValueType = pointerRv.Type().Elem()
   110  		pointerValueKind = pointerValueType.Kind()
   111  		dataMap          = reflect.MakeMapWithSize(pointerRv.Type(), len(paramsKeys))
   112  	)
   113  	// Retrieve the true element type of target map.
   114  	if pointerValueKind == reflect.Ptr {
   115  		pointerValueKind = pointerValueType.Elem().Kind()
   116  	}
   117  	for _, key := range paramsKeys {
   118  		e := reflect.New(pointerValueType).Elem()
   119  		switch pointerValueKind {
   120  		case reflect.Map, reflect.Struct:
   121  			if err = doStruct(paramsRv.MapIndex(key).Interface(), e, keyToAttributeNameMapping, ""); err != nil {
   122  				return err
   123  			}
   124  		default:
   125  			e.Set(
   126  				reflect.ValueOf(
   127  					Convert(
   128  						paramsRv.MapIndex(key).Interface(),
   129  						pointerValueType.String(),
   130  					),
   131  				),
   132  			)
   133  		}
   134  		dataMap.SetMapIndex(
   135  			reflect.ValueOf(
   136  				Convert(
   137  					key.Interface(),
   138  					pointerKeyType.Name(),
   139  				),
   140  			),
   141  			e,
   142  		)
   143  	}
   144  	pointerRv.Set(dataMap)
   145  	return nil
   146  }