254 lines
4.4 KiB
Go
254 lines
4.4 KiB
Go
package value
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"time"
|
|
|
|
"gitoa.ru/go-4devs/config"
|
|
)
|
|
|
|
var _ config.Value = (*Value)(nil)
|
|
|
|
func New(data any) config.Value {
|
|
switch val := data.(type) {
|
|
case config.Value:
|
|
return val
|
|
default:
|
|
return Value{Val: data}
|
|
}
|
|
}
|
|
|
|
type Value struct {
|
|
Val any
|
|
}
|
|
|
|
func (s Value) Int() int {
|
|
v, _ := s.ParseInt()
|
|
|
|
return v
|
|
}
|
|
|
|
func (s Value) Int64() int64 {
|
|
v, _ := s.ParseInt64()
|
|
|
|
return v
|
|
}
|
|
|
|
func (s Value) Uint() uint {
|
|
v, _ := s.ParseUint()
|
|
|
|
return v
|
|
}
|
|
|
|
func (s Value) Uint64() uint64 {
|
|
v, _ := s.ParseUint64()
|
|
|
|
return v
|
|
}
|
|
|
|
func (s Value) Float64() float64 {
|
|
in, _ := s.ParseFloat64()
|
|
|
|
return in
|
|
}
|
|
|
|
func (s Value) String() string {
|
|
v, _ := s.ParseString()
|
|
|
|
return v
|
|
}
|
|
|
|
func (s Value) Bool() bool {
|
|
v, _ := s.ParseBool()
|
|
|
|
return v
|
|
}
|
|
|
|
func (s Value) Duration() time.Duration {
|
|
v, _ := s.ParseDuration()
|
|
|
|
return v
|
|
}
|
|
|
|
func (s Value) Time() time.Time {
|
|
v, _ := s.ParseTime()
|
|
|
|
return v
|
|
}
|
|
|
|
func (s Value) Unmarshal(target any) error {
|
|
return typeAssert(s.Val, target)
|
|
}
|
|
|
|
func (s Value) ParseInt() (int, error) {
|
|
if r, ok := s.Any().(int); ok {
|
|
return r, nil
|
|
}
|
|
|
|
return 0, config.ErrInvalidValue
|
|
}
|
|
|
|
func (s Value) ParseInt64() (int64, error) {
|
|
if r, ok := s.Any().(int64); ok {
|
|
return r, nil
|
|
}
|
|
|
|
return 0, config.ErrInvalidValue
|
|
}
|
|
|
|
func (s Value) ParseUint() (uint, error) {
|
|
if r, ok := s.Any().(uint); ok {
|
|
return r, nil
|
|
}
|
|
|
|
return 0, config.ErrInvalidValue
|
|
}
|
|
|
|
func (s Value) ParseUint64() (uint64, error) {
|
|
if r, ok := s.Any().(uint64); ok {
|
|
return r, nil
|
|
}
|
|
|
|
return 0, config.ErrInvalidValue
|
|
}
|
|
|
|
func (s Value) ParseFloat64() (float64, error) {
|
|
if r, ok := s.Any().(float64); ok {
|
|
return r, nil
|
|
}
|
|
|
|
return 0, config.ErrInvalidValue
|
|
}
|
|
|
|
func (s Value) ParseString() (string, error) {
|
|
if r, ok := s.Any().(string); ok {
|
|
return r, nil
|
|
}
|
|
|
|
return "", config.ErrInvalidValue
|
|
}
|
|
|
|
func (s Value) ParseBool() (bool, error) {
|
|
if b, ok := s.Any().(bool); ok {
|
|
return b, nil
|
|
}
|
|
|
|
return false, config.ErrInvalidValue
|
|
}
|
|
|
|
func (s Value) ParseDuration() (time.Duration, error) {
|
|
if b, ok := s.Any().(time.Duration); ok {
|
|
return b, nil
|
|
}
|
|
|
|
return 0, config.ErrInvalidValue
|
|
}
|
|
|
|
func (s Value) ParseTime() (time.Time, error) {
|
|
if b, ok := s.Any().(time.Time); ok {
|
|
return b, nil
|
|
}
|
|
|
|
return time.Time{}, config.ErrInvalidValue
|
|
}
|
|
|
|
func (s Value) IsEquals(in config.Value) bool {
|
|
return s.Any() == in.Any()
|
|
}
|
|
|
|
func (s Value) Any() any {
|
|
return s.Val
|
|
}
|
|
|
|
func typeAssert(source, target any) error {
|
|
if source == nil {
|
|
return nil
|
|
}
|
|
|
|
if directTypeAssert(source, target) {
|
|
return nil
|
|
}
|
|
|
|
valTarget := reflect.ValueOf(target)
|
|
if !valTarget.IsValid() || valTarget.Kind() != reflect.Pointer {
|
|
return fmt.Errorf("ptr target:%w", config.ErrInvalidValue)
|
|
}
|
|
|
|
valTarget = valTarget.Elem()
|
|
|
|
if !valTarget.IsValid() {
|
|
return fmt.Errorf("elem targer:%w", config.ErrInvalidValue)
|
|
}
|
|
|
|
valSource := reflect.ValueOf(source)
|
|
if !valSource.IsValid() {
|
|
return fmt.Errorf("source:%w", config.ErrInvalidValue)
|
|
}
|
|
|
|
valSource = deReference(valSource)
|
|
if err := canSet(valSource, valTarget); err != nil {
|
|
return fmt.Errorf("can set:%w", err)
|
|
}
|
|
|
|
valTarget.Set(valSource)
|
|
|
|
return nil
|
|
}
|
|
|
|
func canSet(source, target reflect.Value) error {
|
|
if source.Kind() != target.Kind() {
|
|
return fmt.Errorf("source=%v target=%v:%w", source.Kind(), target.Kind(), config.ErrInvalidValue)
|
|
}
|
|
|
|
if source.Kind() == reflect.Slice && source.Type().Elem().Kind() != target.Type().Elem().Kind() {
|
|
return fmt.Errorf("slice source=%v, slice target=%v:%w",
|
|
source.Type().Elem().Kind(), target.Type().Elem().Kind(), config.ErrInvalidValue)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func directTypeAssert(source, target any) bool {
|
|
var ok bool
|
|
|
|
switch val := target.(type) {
|
|
case *string:
|
|
*val, ok = source.(string)
|
|
case *[]byte:
|
|
*val, ok = source.([]byte)
|
|
case *int:
|
|
*val, ok = source.(int)
|
|
case *int64:
|
|
*val, ok = source.(int64)
|
|
case *uint:
|
|
*val, ok = source.(uint)
|
|
case *uint64:
|
|
*val, ok = source.(uint64)
|
|
case *bool:
|
|
*val, ok = source.(bool)
|
|
case *float64:
|
|
*val, ok = source.(float64)
|
|
case *time.Duration:
|
|
*val, ok = source.(time.Duration)
|
|
case *time.Time:
|
|
*val, ok = source.(time.Time)
|
|
case *[]string:
|
|
*val, ok = source.([]string)
|
|
case *map[string]string:
|
|
*val, ok = source.(map[string]string)
|
|
case *map[string]any:
|
|
*val, ok = source.(map[string]any)
|
|
}
|
|
|
|
return ok
|
|
}
|
|
|
|
func deReference(v reflect.Value) reflect.Value {
|
|
if (v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface) && !v.IsNil() {
|
|
return v.Elem()
|
|
}
|
|
|
|
return v
|
|
}
|