dynamic-struct/reader.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()
}