merge_structs.go 1.72 KB
Newer Older
Sybren A. Stüvel's avatar
Sybren A. Stüvel committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
package bunqapi

import (
	"fmt"
	"reflect"
)

// MergeStructs merges an array of structs into a single struct.
func MergeStructs(responses interface{}, mergedResp interface{}) {
	arrayType := reflect.TypeOf(responses)
	if arrayType.Kind() != reflect.Slice && arrayType.Kind() != reflect.Array {
		panic(fmt.Sprintf("responses should be a slice or array, not %v", arrayType.Kind()))
	}

	responsesValue := reflect.ValueOf(responses)
	numResponses := responsesValue.Len()

	respType := arrayType.Elem()
	numFields := respType.NumField()

	resultType := reflect.TypeOf(mergedResp)
	if resultType.Elem() != respType {
		panic(fmt.Sprintf("mergedResp should be *%v, not %v", respType, reflect.TypeOf(mergedResp)))
	}
	resultValue := reflect.ValueOf(mergedResp).Elem()

	for index := 0; index < numResponses; index++ {
		// fmt.Printf("response #%d:\n", index)
		responseValue := responsesValue.Index(index)

		for fieldnum := 0; fieldnum < numFields; fieldnum++ {
			// field := respType.Field(fieldnum)
			fieldVal := responseValue.Field(fieldnum)

			// Skip unexported fields.
			if !fieldVal.CanSet() {
				continue
			}

			// fmt.Printf("  - field %d: %10v ", fieldnum, field.Name)
			useValue := false
			switch fieldVal.Kind() {
			case reflect.Ptr:
				useValue = !fieldVal.IsNil()
				// fmt.Printf("is pointer: %v", useValue)
			case reflect.String:
				useValue = fieldVal.String() != ""
				// fmt.Printf("is string : %v", useValue)
			case reflect.Bool:
				useValue = fieldVal.Bool()
				// fmt.Printf("is bool   : %v", useValue)
			default:
				// fmt.Printf("is kind   : %v (not using)", fieldVal.Kind())
			}
			// fmt.Println()

			if !useValue {
				continue
			}

			resultField := resultValue.Field(fieldnum)
			resultField.Set(fieldVal)

		}
	}
}