package hscan

import (
	
	
	
	
	

	
)

// structMap contains the map of struct fields for target structs
// indexed by the struct type.
type structMap struct {
	m sync.Map
}

func newStructMap() *structMap {
	return new(structMap)
}

func ( *structMap) ( reflect.Type) *structSpec {
	if ,  := .m.Load();  {
		return .(*structSpec)
	}

	 := newStructSpec(, "redis")
	.m.Store(, )
	return 
}

//------------------------------------------------------------------------------

// structSpec contains the list of all fields in a target struct.
type structSpec struct {
	m map[string]*structField
}

func ( *structSpec) ( string,  *structField) {
	.m[] = 
}

func newStructSpec( reflect.Type,  string) *structSpec {
	 := .NumField()
	 := &structSpec{
		m: make(map[string]*structField, ),
	}

	for  := 0;  < ; ++ {
		 := .Field()

		 := .Tag.Get()
		if  == "" ||  == "-" {
			continue
		}

		 = strings.Split(, ",")[0]
		if  == "" {
			continue
		}

		// Use the built-in decoder.
		.set(, &structField{index: , fn: decoders[.Type.Kind()]})
	}

	return 
}

//------------------------------------------------------------------------------

// structField represents a single field in a target struct.
type structField struct {
	index int
	fn    decoderFunc
}

//------------------------------------------------------------------------------

type StructValue struct {
	spec  *structSpec
	value reflect.Value
}

func ( StructValue) ( string,  string) error {
	,  := .spec.m[]
	if ! {
		return nil
	}

	 := .value.Field(.index)
	 := .Kind() == reflect.Ptr

	if  && .IsNil() {
		.Set(reflect.New(.Type().Elem()))
	}
	if ! && .Type().Name() != "" && .CanAddr() {
		 = .Addr()
		 = true
	}

	if  && .Type().NumMethod() > 0 && .CanInterface() {
		switch scan := .Interface().(type) {
		case Scanner:
			return .ScanRedis()
		case encoding.TextUnmarshaler:
			return .UnmarshalText(util.StringToBytes())
		}
	}

	if  {
		 = .Elem()
	}

	if  := .fn(, );  != nil {
		 := .value.Type()
		return fmt.Errorf("cannot scan redis.result %s into struct field %s.%s of type %s, error-%s",
			, .Name(), .Field(.index).Name, .Field(.index).Type, .Error())
	}
	return nil
}