434 lines
8.3 KiB
Go
434 lines
8.3 KiB
Go
package dynamicstruct
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"time"
|
|
)
|
|
|
|
type (
|
|
// Reader 通过反射读取结构体信息
|
|
Reader interface {
|
|
// HasField 是否存在指定名称的字段
|
|
HasField(name string) bool
|
|
// GetField 获取指定字段信息
|
|
GetField(name string) Field
|
|
// GetAllFields 获取全部字段
|
|
GetAllFields() []Field
|
|
// ToStruct 转结构体
|
|
ToStruct(value any) error
|
|
// ToSliceOfReaders 转slice
|
|
ToSliceOfReaders() []Reader
|
|
// ToMapReaderOfReaders returns a map of Reader interfaces if value is representation
|
|
ToMapReaderOfReaders() map[any]Reader
|
|
// GetValue 获取输入的原始值
|
|
GetValue() any
|
|
}
|
|
|
|
// Field 对结构体字段的操作
|
|
Field interface {
|
|
// Name 返回字段名称
|
|
Name() string
|
|
// PointerInt int 指针
|
|
PointerInt() *int
|
|
// Int int
|
|
Int() int
|
|
// PointerInt8 int8指针
|
|
PointerInt8() *int8
|
|
// Int8 int
|
|
Int8() int8
|
|
// PointerInt16 int16指针
|
|
PointerInt16() *int16
|
|
// Int16 int16
|
|
Int16() int16
|
|
// PointerInt32 int32指针
|
|
PointerInt32() *int32
|
|
// Int32 int32
|
|
Int32() int32
|
|
// PointerInt64 int64指针
|
|
PointerInt64() *int64
|
|
// Int64 int64
|
|
Int64() int64
|
|
// PointerUint uint指针
|
|
PointerUint() *uint
|
|
// Uint uint
|
|
Uint() uint
|
|
// PointerUint8 uint8指针
|
|
PointerUint8() *uint8
|
|
// Uint8 uint8
|
|
Uint8() uint8
|
|
// PointerUint16 uint16指针
|
|
PointerUint16() *uint16
|
|
// Uint16 uint16
|
|
Uint16() uint16
|
|
// PointerUint32 uint32指针
|
|
PointerUint32() *uint32
|
|
// Uint32 uint32
|
|
Uint32() uint32
|
|
// PointerUint64 uint64指针
|
|
PointerUint64() *uint64
|
|
// Uint64 uint64
|
|
Uint64() uint64
|
|
// PointerFloat32 float32指针
|
|
PointerFloat32() *float32
|
|
// Float32 float32
|
|
Float32() float32
|
|
// PointerFloat64 float64指针
|
|
PointerFloat64() *float64
|
|
// Float64 float64
|
|
Float64() float64
|
|
// PointerString string指针
|
|
PointerString() *string
|
|
// String string
|
|
String() string
|
|
// PointerBool bool指针
|
|
PointerBool() *bool
|
|
// Bool bool...
|
|
Bool() bool
|
|
// PointerTime time指针
|
|
PointerTime() *time.Time
|
|
// Time time...
|
|
Time() time.Time
|
|
// Any any...
|
|
Any() any
|
|
}
|
|
|
|
readImpl struct {
|
|
fields map[string]fieldImpl
|
|
value any
|
|
}
|
|
|
|
fieldImpl struct {
|
|
field reflect.StructField
|
|
value reflect.Value
|
|
}
|
|
)
|
|
|
|
// NewReader reads struct instance and provides instance of
|
|
// Reader interface to give possibility to read all fields' values.
|
|
func NewReader(value any) Reader {
|
|
fields := map[string]fieldImpl{}
|
|
|
|
valueOf := reflect.Indirect(reflect.ValueOf(value))
|
|
typeOf := valueOf.Type()
|
|
|
|
if typeOf.Kind() == reflect.Struct {
|
|
for i := 0; i < valueOf.NumField(); i++ {
|
|
field := typeOf.Field(i)
|
|
fields[field.Name] = fieldImpl{
|
|
field: field,
|
|
value: valueOf.Field(i),
|
|
}
|
|
}
|
|
}
|
|
|
|
return readImpl{
|
|
fields: fields,
|
|
value: value,
|
|
}
|
|
}
|
|
|
|
func (r readImpl) HasField(name string) bool {
|
|
_, ok := r.fields[name]
|
|
return ok
|
|
}
|
|
|
|
func (r readImpl) GetField(name string) Field {
|
|
if !r.HasField(name) {
|
|
return nil
|
|
}
|
|
return r.fields[name]
|
|
}
|
|
|
|
func (r readImpl) GetAllFields() []Field {
|
|
var fields []Field
|
|
|
|
for _, field := range r.fields {
|
|
fields = append(fields, field)
|
|
}
|
|
|
|
return fields
|
|
}
|
|
|
|
func (r readImpl) ToStruct(value any) error {
|
|
valueOf := reflect.ValueOf(value)
|
|
|
|
if valueOf.Kind() != reflect.Ptr || valueOf.IsNil() {
|
|
return errors.New("ToStruct: expected a pointer as an argument")
|
|
}
|
|
|
|
valueOf = valueOf.Elem()
|
|
typeOf := valueOf.Type()
|
|
|
|
if valueOf.Kind() != reflect.Struct {
|
|
return errors.New("ToStruct: expected a pointer to struct as an argument")
|
|
}
|
|
|
|
for i := 0; i < valueOf.NumField(); i++ {
|
|
fieldType := typeOf.Field(i)
|
|
fieldValue := valueOf.Field(i)
|
|
|
|
original, ok := r.fields[fieldType.Name]
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
if fieldValue.CanSet() && r.haveSameTypes(original.value.Type(), fieldValue.Type()) {
|
|
fieldValue.Set(original.value)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r readImpl) ToSliceOfReaders() []Reader {
|
|
valueOf := reflect.Indirect(reflect.ValueOf(r.value))
|
|
typeOf := valueOf.Type()
|
|
|
|
if typeOf.Kind() != reflect.Slice && typeOf.Kind() != reflect.Array {
|
|
return nil
|
|
}
|
|
|
|
var readers []Reader
|
|
|
|
for i := 0; i < valueOf.Len(); i++ {
|
|
readers = append(readers, NewReader(valueOf.Index(i).Interface()))
|
|
}
|
|
|
|
return readers
|
|
}
|
|
|
|
func (r readImpl) ToMapReaderOfReaders() map[any]Reader {
|
|
valueOf := reflect.Indirect(reflect.ValueOf(r.value))
|
|
typeOf := valueOf.Type()
|
|
|
|
if typeOf.Kind() != reflect.Map {
|
|
return nil
|
|
}
|
|
|
|
readers := map[any]Reader{}
|
|
|
|
for _, keyValue := range valueOf.MapKeys() {
|
|
readers[keyValue.Interface()] = NewReader(valueOf.MapIndex(keyValue).Interface())
|
|
}
|
|
|
|
return readers
|
|
}
|
|
|
|
func (r readImpl) GetValue() any {
|
|
return r.value
|
|
}
|
|
|
|
func (r readImpl) haveSameTypes(first reflect.Type, second reflect.Type) bool {
|
|
if first.Kind() != second.Kind() {
|
|
return false
|
|
}
|
|
|
|
switch first.Kind() {
|
|
case reflect.Ptr:
|
|
return r.haveSameTypes(first.Elem(), second.Elem())
|
|
case reflect.Struct:
|
|
return first.PkgPath() == second.PkgPath() && first.Name() == second.Name()
|
|
case reflect.Slice:
|
|
return r.haveSameTypes(first.Elem(), second.Elem())
|
|
case reflect.Map:
|
|
return r.haveSameTypes(first.Elem(), second.Elem()) && r.haveSameTypes(first.Key(), second.Key())
|
|
default:
|
|
return first.Kind() == second.Kind()
|
|
}
|
|
}
|
|
|
|
func (f fieldImpl) Name() string {
|
|
return f.field.Name
|
|
}
|
|
|
|
func (f fieldImpl) PointerInt() *int {
|
|
if f.value.IsNil() {
|
|
return nil
|
|
}
|
|
value := f.Int()
|
|
return &value
|
|
}
|
|
|
|
func (f fieldImpl) Int() int {
|
|
return int(reflect.Indirect(f.value).Int())
|
|
}
|
|
|
|
func (f fieldImpl) PointerInt8() *int8 {
|
|
if f.value.IsNil() {
|
|
return nil
|
|
}
|
|
value := f.Int8()
|
|
return &value
|
|
}
|
|
|
|
func (f fieldImpl) Int8() int8 {
|
|
return int8(reflect.Indirect(f.value).Int())
|
|
}
|
|
|
|
func (f fieldImpl) PointerInt16() *int16 {
|
|
if f.value.IsNil() {
|
|
return nil
|
|
}
|
|
value := f.Int16()
|
|
return &value
|
|
}
|
|
|
|
func (f fieldImpl) Int16() int16 {
|
|
return int16(reflect.Indirect(f.value).Int())
|
|
}
|
|
|
|
func (f fieldImpl) PointerInt32() *int32 {
|
|
if f.value.IsNil() {
|
|
return nil
|
|
}
|
|
value := f.Int32()
|
|
return &value
|
|
}
|
|
|
|
func (f fieldImpl) Int32() int32 {
|
|
return int32(reflect.Indirect(f.value).Int())
|
|
}
|
|
|
|
func (f fieldImpl) PointerInt64() *int64 {
|
|
if f.value.IsNil() {
|
|
return nil
|
|
}
|
|
value := f.Int64()
|
|
return &value
|
|
}
|
|
|
|
func (f fieldImpl) Int64() int64 {
|
|
return reflect.Indirect(f.value).Int()
|
|
}
|
|
|
|
func (f fieldImpl) PointerUint() *uint {
|
|
if f.value.IsNil() {
|
|
return nil
|
|
}
|
|
value := f.Uint()
|
|
return &value
|
|
}
|
|
|
|
func (f fieldImpl) Uint() uint {
|
|
return uint(reflect.Indirect(f.value).Uint())
|
|
}
|
|
|
|
func (f fieldImpl) PointerUint8() *uint8 {
|
|
if f.value.IsNil() {
|
|
return nil
|
|
}
|
|
value := f.Uint8()
|
|
return &value
|
|
}
|
|
|
|
func (f fieldImpl) Uint8() uint8 {
|
|
return uint8(reflect.Indirect(f.value).Uint())
|
|
}
|
|
|
|
func (f fieldImpl) PointerUint16() *uint16 {
|
|
if f.value.IsNil() {
|
|
return nil
|
|
}
|
|
value := f.Uint16()
|
|
return &value
|
|
}
|
|
|
|
func (f fieldImpl) Uint16() uint16 {
|
|
return uint16(reflect.Indirect(f.value).Uint())
|
|
}
|
|
|
|
func (f fieldImpl) PointerUint32() *uint32 {
|
|
if f.value.IsNil() {
|
|
return nil
|
|
}
|
|
value := f.Uint32()
|
|
return &value
|
|
}
|
|
|
|
func (f fieldImpl) Uint32() uint32 {
|
|
return uint32(reflect.Indirect(f.value).Uint())
|
|
}
|
|
|
|
func (f fieldImpl) PointerUint64() *uint64 {
|
|
if f.value.IsNil() {
|
|
return nil
|
|
}
|
|
value := f.Uint64()
|
|
return &value
|
|
}
|
|
|
|
func (f fieldImpl) Uint64() uint64 {
|
|
return reflect.Indirect(f.value).Uint()
|
|
}
|
|
|
|
func (f fieldImpl) PointerFloat32() *float32 {
|
|
if f.value.IsNil() {
|
|
return nil
|
|
}
|
|
value := f.Float32()
|
|
return &value
|
|
}
|
|
|
|
func (f fieldImpl) Float32() float32 {
|
|
return float32(reflect.Indirect(f.value).Float())
|
|
}
|
|
|
|
func (f fieldImpl) PointerFloat64() *float64 {
|
|
if f.value.IsNil() {
|
|
return nil
|
|
}
|
|
value := f.Float64()
|
|
return &value
|
|
}
|
|
|
|
func (f fieldImpl) Float64() float64 {
|
|
return reflect.Indirect(f.value).Float()
|
|
}
|
|
|
|
func (f fieldImpl) PointerString() *string {
|
|
if f.value.IsNil() {
|
|
return nil
|
|
}
|
|
value := f.String()
|
|
return &value
|
|
}
|
|
|
|
func (f fieldImpl) String() string {
|
|
return reflect.Indirect(f.value).String()
|
|
}
|
|
|
|
func (f fieldImpl) PointerBool() *bool {
|
|
if f.value.IsNil() {
|
|
return nil
|
|
}
|
|
value := f.Bool()
|
|
return &value
|
|
}
|
|
|
|
func (f fieldImpl) Bool() bool {
|
|
return reflect.Indirect(f.value).Bool()
|
|
}
|
|
|
|
func (f fieldImpl) PointerTime() *time.Time {
|
|
if f.value.IsNil() {
|
|
return nil
|
|
}
|
|
value := f.Time()
|
|
return &value
|
|
}
|
|
|
|
func (f fieldImpl) Time() time.Time {
|
|
value, ok := reflect.Indirect(f.value).Interface().(time.Time)
|
|
if !ok {
|
|
panic(fmt.Sprintf(`field "%s" is not instance of time.Time`, f.field.Name))
|
|
}
|
|
|
|
return value
|
|
}
|
|
|
|
func (f fieldImpl) Any() any {
|
|
return f.value.Interface()
|
|
}
|