github.com/jackc/pgx/v5@v5.5.5/pgtype/convert.go (about) 1 package pgtype 2 3 import ( 4 "reflect" 5 ) 6 7 func NullAssignTo(dst any) error { 8 dstPtr := reflect.ValueOf(dst) 9 10 // AssignTo dst must always be a pointer 11 if dstPtr.Kind() != reflect.Ptr { 12 return &nullAssignmentError{dst: dst} 13 } 14 15 dstVal := dstPtr.Elem() 16 17 switch dstVal.Kind() { 18 case reflect.Ptr, reflect.Slice, reflect.Map: 19 dstVal.Set(reflect.Zero(dstVal.Type())) 20 return nil 21 } 22 23 return &nullAssignmentError{dst: dst} 24 } 25 26 var kindTypes map[reflect.Kind]reflect.Type 27 28 func toInterface(dst reflect.Value, t reflect.Type) (any, bool) { 29 nextDst := dst.Convert(t) 30 return nextDst.Interface(), dst.Type() != nextDst.Type() 31 } 32 33 // GetAssignToDstType attempts to convert dst to something AssignTo can assign 34 // to. If dst is a pointer to pointer it allocates a value and returns the 35 // dereferences pointer. If dst is a named type such as *Foo where Foo is type 36 // Foo int16, it converts dst to *int16. 37 // 38 // GetAssignToDstType returns the converted dst and a bool representing if any 39 // change was made. 40 func GetAssignToDstType(dst any) (any, bool) { 41 dstPtr := reflect.ValueOf(dst) 42 43 // AssignTo dst must always be a pointer 44 if dstPtr.Kind() != reflect.Ptr { 45 return nil, false 46 } 47 48 dstVal := dstPtr.Elem() 49 50 // if dst is a pointer to pointer, allocate space try again with the dereferenced pointer 51 if dstVal.Kind() == reflect.Ptr { 52 dstVal.Set(reflect.New(dstVal.Type().Elem())) 53 return dstVal.Interface(), true 54 } 55 56 // if dst is pointer to a base type that has been renamed 57 if baseValType, ok := kindTypes[dstVal.Kind()]; ok { 58 return toInterface(dstPtr, reflect.PtrTo(baseValType)) 59 } 60 61 if dstVal.Kind() == reflect.Slice { 62 if baseElemType, ok := kindTypes[dstVal.Type().Elem().Kind()]; ok { 63 return toInterface(dstPtr, reflect.PtrTo(reflect.SliceOf(baseElemType))) 64 } 65 } 66 67 if dstVal.Kind() == reflect.Array { 68 if baseElemType, ok := kindTypes[dstVal.Type().Elem().Kind()]; ok { 69 return toInterface(dstPtr, reflect.PtrTo(reflect.ArrayOf(dstVal.Len(), baseElemType))) 70 } 71 } 72 73 if dstVal.Kind() == reflect.Struct { 74 if dstVal.Type().NumField() == 1 && dstVal.Type().Field(0).Anonymous { 75 dstPtr = dstVal.Field(0).Addr() 76 nested := dstVal.Type().Field(0).Type 77 if nested.Kind() == reflect.Array { 78 if baseElemType, ok := kindTypes[nested.Elem().Kind()]; ok { 79 return toInterface(dstPtr, reflect.PtrTo(reflect.ArrayOf(nested.Len(), baseElemType))) 80 } 81 } 82 if _, ok := kindTypes[nested.Kind()]; ok && dstPtr.CanInterface() { 83 return dstPtr.Interface(), true 84 } 85 } 86 } 87 88 return nil, false 89 } 90 91 func init() { 92 kindTypes = map[reflect.Kind]reflect.Type{ 93 reflect.Bool: reflect.TypeOf(false), 94 reflect.Float32: reflect.TypeOf(float32(0)), 95 reflect.Float64: reflect.TypeOf(float64(0)), 96 reflect.Int: reflect.TypeOf(int(0)), 97 reflect.Int8: reflect.TypeOf(int8(0)), 98 reflect.Int16: reflect.TypeOf(int16(0)), 99 reflect.Int32: reflect.TypeOf(int32(0)), 100 reflect.Int64: reflect.TypeOf(int64(0)), 101 reflect.Uint: reflect.TypeOf(uint(0)), 102 reflect.Uint8: reflect.TypeOf(uint8(0)), 103 reflect.Uint16: reflect.TypeOf(uint16(0)), 104 reflect.Uint32: reflect.TypeOf(uint32(0)), 105 reflect.Uint64: reflect.TypeOf(uint64(0)), 106 reflect.String: reflect.TypeOf(""), 107 } 108 }