Module convert + initialisation du go.mod
This commit is contained in:
		
							parent
							
								
									6582c6d9cd
								
							
						
					
					
						commit
						a524d1d0dc
					
				
					 3 changed files with 1271 additions and 0 deletions
				
			
		
							
								
								
									
										762
									
								
								convert/convert.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										762
									
								
								convert/convert.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,762 @@
 | 
			
		|||
package convert
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
 | 
			
		||||
	. "gitea.zaclys.com/bvaudour/gob/option"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type BoolType interface {
 | 
			
		||||
	~bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CharType interface {
 | 
			
		||||
	~byte | ~rune
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type StringType interface {
 | 
			
		||||
	~string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type IntType interface {
 | 
			
		||||
	~int | ~int8 | ~int16 | ~int32 | ~int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UintType interface {
 | 
			
		||||
	~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type FloatType interface {
 | 
			
		||||
	~float32 | ~float64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ComplexType interface {
 | 
			
		||||
	~complex64 | ~complex128
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type IntegerType interface {
 | 
			
		||||
	IntType | UintType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RealType interface {
 | 
			
		||||
	IntegerType | FloatType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type NumberType interface {
 | 
			
		||||
	RealType | ComplexType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type convFunc = func(Value, Value) bool
 | 
			
		||||
 | 
			
		||||
func isConvertible(t1, t2 Type) bool {
 | 
			
		||||
	return t1.AssignableTo(t2) || t1.EquivalentTo(t2)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getConvFunc(t Type) (f Option[convFunc]) {
 | 
			
		||||
	switch {
 | 
			
		||||
	case t.Is(Bool):
 | 
			
		||||
		f = Some(fromBool)
 | 
			
		||||
	case t.Is(Char):
 | 
			
		||||
		f = Some(fromChar)
 | 
			
		||||
	case t.Is(Int):
 | 
			
		||||
		f = Some(fromInt)
 | 
			
		||||
	case t.Is(Uint):
 | 
			
		||||
		f = Some(fromUint)
 | 
			
		||||
	case t.Is(Float):
 | 
			
		||||
		f = Some(fromFloat)
 | 
			
		||||
	case t.Is(Complex):
 | 
			
		||||
		f = Some(fromComplex)
 | 
			
		||||
	case t.Is(String):
 | 
			
		||||
		f = Some(fromString)
 | 
			
		||||
	case t.Is(Slice.Or(Array)):
 | 
			
		||||
		f = Some(fromSlice)
 | 
			
		||||
	case t.IsSet():
 | 
			
		||||
		f = Some(fromSet)
 | 
			
		||||
	case t.Is(Map):
 | 
			
		||||
		f = Some(fromMap)
 | 
			
		||||
	case t.Is(Struct):
 | 
			
		||||
		f = Some(fromStruct)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func safeConv(src, dest Value) bool {
 | 
			
		||||
	ts, td := src.Type(), dest.Type()
 | 
			
		||||
	if ts.AssignableTo(td) {
 | 
			
		||||
		dest.Set(src)
 | 
			
		||||
		return true
 | 
			
		||||
	} else if ts.EquivalentTo(td) {
 | 
			
		||||
		dest.Set(src.Convert(td))
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func unsafeConv(src, dest Value) bool {
 | 
			
		||||
	f, ok := getConvFunc(src.Type()).Get()
 | 
			
		||||
	return ok && f(src, dest)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func conv(src, dest Value, safe ...bool) bool {
 | 
			
		||||
	if safeConv(src, dest) {
 | 
			
		||||
		return true
 | 
			
		||||
	} else if len(safe) == 0 || !safe[0] {
 | 
			
		||||
		return unsafeConv(src, dest)
 | 
			
		||||
	} else if src.Is(Slice.Or(Array)) && dest.Is(Slice.Or(Array)) {
 | 
			
		||||
		return safeConvSlice(src, dest)
 | 
			
		||||
	} else if src.Is(Map) && dest.Is(Map) {
 | 
			
		||||
		return safeConvMap(src, dest)
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func safeConvSlice(src, dest Value) (ok bool) {
 | 
			
		||||
	l, t := src.Len(), dest.Type()
 | 
			
		||||
	isArray := t.Is(Array)
 | 
			
		||||
	var v Value
 | 
			
		||||
	if isArray {
 | 
			
		||||
		if t.Len() != l {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		v = SliceOf(SliceTypeOf(t.Elem()), l, src.Cap())
 | 
			
		||||
	} else {
 | 
			
		||||
		v = SliceOf(t, l, src.Cap())
 | 
			
		||||
	}
 | 
			
		||||
	ok = true
 | 
			
		||||
	for i := 0; i < l; i++ {
 | 
			
		||||
		e1, e2 := src.Index(i), v.Index(i)
 | 
			
		||||
		if ok = Convert(e1.Interface(), e2.Pointer().Interface(), true); !ok {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if isArray {
 | 
			
		||||
		v = v.Convert(PointerTo(t)).Elem()
 | 
			
		||||
	}
 | 
			
		||||
	dest.Set(v)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func safeConvMap(src, dest Value) (ok bool) {
 | 
			
		||||
	t := dest.Type()
 | 
			
		||||
	tk, tv := t.Key(), t.Elem()
 | 
			
		||||
	v := MapOf(t)
 | 
			
		||||
	keys := src.Keys()
 | 
			
		||||
	ok = true
 | 
			
		||||
	for _, k1 := range keys {
 | 
			
		||||
		k2 := PointerOf(tk)
 | 
			
		||||
		if ok = Convert(k1.Interface(), k2.Interface(), true); !ok {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		e1, e2 := src.MapIndex(k1), PointerOf(tv)
 | 
			
		||||
		if ok = Convert(e1.Interface(), e2.Interface(), true); !ok {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		v.SetMapIndex(k2.Elem(), e2.Elem())
 | 
			
		||||
	}
 | 
			
		||||
	dest.Set(v)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func toSlice(src, dest Value) (ok bool) {
 | 
			
		||||
	t := dest.Type()
 | 
			
		||||
	r := AddressableOf(t.Elem())
 | 
			
		||||
	if ok = conv(src, r); ok {
 | 
			
		||||
		sl := SliceOf(t, 1, 1)
 | 
			
		||||
		sl.Index(0).Set(r)
 | 
			
		||||
		dest.Set(sl)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func toArray(src, dest Value) (ok bool) {
 | 
			
		||||
	t := dest.Type()
 | 
			
		||||
	tsl := SliceTypeOf(t.Elem())
 | 
			
		||||
	sl := AddressableOf(tsl)
 | 
			
		||||
	if ok = toSlice(src, sl); ok {
 | 
			
		||||
		dest.Set(sl.Convert(t))
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func toSet(src, dest Value) (ok bool) {
 | 
			
		||||
	t := dest.Type()
 | 
			
		||||
	r := AddressableOf(t.Key())
 | 
			
		||||
	if ok = conv(src, r); ok {
 | 
			
		||||
		m := MapOf(t)
 | 
			
		||||
		m.AddToSet(r)
 | 
			
		||||
		dest.Set(m)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fromBool(src, dest Value) (ok bool) {
 | 
			
		||||
	e := src.Bool()
 | 
			
		||||
	var r any
 | 
			
		||||
	switch {
 | 
			
		||||
	case dest.Is(Bool):
 | 
			
		||||
		r, ok = e, true
 | 
			
		||||
	case dest.Is(Number):
 | 
			
		||||
		r, ok = 0, true
 | 
			
		||||
		if e {
 | 
			
		||||
			r = 1
 | 
			
		||||
		}
 | 
			
		||||
	case dest.Is(String):
 | 
			
		||||
		r, ok = strconv.FormatBool(e), true
 | 
			
		||||
	case dest.Is(Slice):
 | 
			
		||||
		return toSlice(src, dest)
 | 
			
		||||
	case dest.Is(Array):
 | 
			
		||||
		return toArray(src, dest)
 | 
			
		||||
	case dest.IsSet():
 | 
			
		||||
		return toSet(src, dest)
 | 
			
		||||
	}
 | 
			
		||||
	if ok {
 | 
			
		||||
		v := ValueOf(r).Convert(dest.Type())
 | 
			
		||||
		dest.Set(v)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fromChar(src, dest Value) (ok bool) {
 | 
			
		||||
	e := src.Int()
 | 
			
		||||
	var r any
 | 
			
		||||
	switch {
 | 
			
		||||
	case dest.Is(Bool):
 | 
			
		||||
		r, ok = e != 0, true
 | 
			
		||||
	case dest.Is(Char):
 | 
			
		||||
		r, ok = e, true
 | 
			
		||||
	case dest.Is(Number):
 | 
			
		||||
		r, ok = e-int64('0'), true
 | 
			
		||||
	case dest.Is(String):
 | 
			
		||||
		r, ok = fmt.Sprintf("%c", e), true
 | 
			
		||||
	case dest.Is(Slice):
 | 
			
		||||
		return toSlice(src, dest)
 | 
			
		||||
	case dest.Is(Array):
 | 
			
		||||
		return toArray(src, dest)
 | 
			
		||||
	case dest.IsSet():
 | 
			
		||||
		return toSet(src, dest)
 | 
			
		||||
	}
 | 
			
		||||
	if ok {
 | 
			
		||||
		v := ValueOf(r).Convert(dest.Type())
 | 
			
		||||
		dest.Set(v)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fromString(src, dest Value) (ok bool) {
 | 
			
		||||
	e := src.String()
 | 
			
		||||
	var r any
 | 
			
		||||
	var err error
 | 
			
		||||
	switch {
 | 
			
		||||
	case dest.Is(Bool):
 | 
			
		||||
		r, err = strconv.ParseBool(e)
 | 
			
		||||
		ok = err == nil
 | 
			
		||||
	case dest.Is(Char):
 | 
			
		||||
		if ok = utf8.RuneCountInString(e) == 1; ok {
 | 
			
		||||
			r, _ = utf8.DecodeRuneInString(e)
 | 
			
		||||
		}
 | 
			
		||||
	case dest.Is(Int):
 | 
			
		||||
		r, err = strconv.ParseInt(e, 0, 64)
 | 
			
		||||
		ok = err == nil
 | 
			
		||||
	case dest.Is(Uint):
 | 
			
		||||
		r, err = strconv.ParseUint(e, 0, 64)
 | 
			
		||||
		ok = err == nil
 | 
			
		||||
	case dest.Is(Float):
 | 
			
		||||
		r, err = strconv.ParseFloat(e, 64)
 | 
			
		||||
		ok = err == nil
 | 
			
		||||
	case dest.Is(Complex):
 | 
			
		||||
		r, err = strconv.ParseComplex(e, 128)
 | 
			
		||||
		ok = err == nil
 | 
			
		||||
	case dest.Is(Slice):
 | 
			
		||||
		return toSlice(src, dest)
 | 
			
		||||
	case dest.Is(Array):
 | 
			
		||||
		return toArray(src, dest)
 | 
			
		||||
	case dest.IsSet():
 | 
			
		||||
		return toSet(src, dest)
 | 
			
		||||
	}
 | 
			
		||||
	if ok {
 | 
			
		||||
		v := ValueOf(r).Convert(dest.Type())
 | 
			
		||||
		dest.Set(v)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fromNumber[T RealType](src, dest Value, e T, f func(T) any) (ok bool) {
 | 
			
		||||
	var r any
 | 
			
		||||
	switch {
 | 
			
		||||
	case dest.Is(Bool):
 | 
			
		||||
		r, ok = e != 0, true
 | 
			
		||||
	case dest.Is(Char):
 | 
			
		||||
		r, ok = rune(int64(e))+'0', true
 | 
			
		||||
 | 
			
		||||
	case dest.Is(Number):
 | 
			
		||||
		r, ok = e, true
 | 
			
		||||
	case dest.Is(String):
 | 
			
		||||
		r, ok = f(e), true
 | 
			
		||||
	case dest.Is(Slice):
 | 
			
		||||
		return toSlice(src, dest)
 | 
			
		||||
	case dest.Is(Array):
 | 
			
		||||
		return toArray(src, dest)
 | 
			
		||||
	case dest.IsSet():
 | 
			
		||||
		return toSet(src, dest)
 | 
			
		||||
	}
 | 
			
		||||
	if ok {
 | 
			
		||||
		v := ValueOf(r).Convert(dest.Type())
 | 
			
		||||
		dest.Set(v)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fromInt(src, dest Value) (ok bool) {
 | 
			
		||||
	e := src.Int()
 | 
			
		||||
	return fromNumber(
 | 
			
		||||
		src,
 | 
			
		||||
		dest,
 | 
			
		||||
		e,
 | 
			
		||||
		func(n int64) any { return strconv.FormatInt(n, 10) },
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fromUint(src, dest Value) (ok bool) {
 | 
			
		||||
	e := src.Uint()
 | 
			
		||||
	return fromNumber(
 | 
			
		||||
		src,
 | 
			
		||||
		dest,
 | 
			
		||||
		e,
 | 
			
		||||
		func(n uint64) any { return strconv.FormatUint(n, 10) },
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fromFloat(src, dest Value) (ok bool) {
 | 
			
		||||
	e := src.Float()
 | 
			
		||||
	return fromNumber(
 | 
			
		||||
		src,
 | 
			
		||||
		dest,
 | 
			
		||||
		e,
 | 
			
		||||
		func(n float64) any { return strconv.FormatFloat(n, 'f', -1, 64) },
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fromComplex(src, dest Value) (ok bool) {
 | 
			
		||||
	e := src.Complex()
 | 
			
		||||
	var r any
 | 
			
		||||
	switch {
 | 
			
		||||
	case dest.Is(Bool):
 | 
			
		||||
		r, ok = e != 0, true
 | 
			
		||||
	case dest.Is(Char):
 | 
			
		||||
		r, ok = rune(real(e))+'0', true
 | 
			
		||||
	case dest.Is(Real):
 | 
			
		||||
		r, ok = real(e), true
 | 
			
		||||
	case dest.Is(Complex):
 | 
			
		||||
		r, ok = e, true
 | 
			
		||||
	case dest.Is(String):
 | 
			
		||||
		r, ok = strconv.FormatComplex(e, 'f', -1, 64), true
 | 
			
		||||
	case dest.Is(Slice):
 | 
			
		||||
		return toSlice(src, dest)
 | 
			
		||||
	case dest.Is(Array):
 | 
			
		||||
		return toArray(src, dest)
 | 
			
		||||
	case dest.IsSet():
 | 
			
		||||
		return toSet(src, dest)
 | 
			
		||||
	}
 | 
			
		||||
	if ok {
 | 
			
		||||
		v := ValueOf(r).Convert(dest.Type())
 | 
			
		||||
		dest.Set(v)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fromSlice(src, dest Value) (ok bool) {
 | 
			
		||||
	t, l := dest.Type(), src.Len()
 | 
			
		||||
	var r Value
 | 
			
		||||
	switch {
 | 
			
		||||
	case dest.Is(Slice):
 | 
			
		||||
		r, ok = SliceOf(t, l, src.Cap()), true
 | 
			
		||||
		for i := 0; i < l; i++ {
 | 
			
		||||
			if ok = conv(src.Index(i, true), r.Index(i)); !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	case dest.Is(Array):
 | 
			
		||||
		if ok = l == t.Len(); !ok {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		tsl := SliceTypeOf(t.Elem())
 | 
			
		||||
		r = SliceOf(tsl, l, src.Cap())
 | 
			
		||||
		if ok = fromSlice(src, r); !ok {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		r = r.Convert(PointerTo(t)).Elem()
 | 
			
		||||
	case dest.IsSet():
 | 
			
		||||
		tk := t.Key()
 | 
			
		||||
		r = MapOf(t)
 | 
			
		||||
		for i := 0; i < l; i++ {
 | 
			
		||||
			e1, e2 := src.Index(i, true), AddressableOf(tk)
 | 
			
		||||
			if ok = conv(e1, e2); !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			r.AddToSet(e2)
 | 
			
		||||
		}
 | 
			
		||||
	case dest.Is(Map):
 | 
			
		||||
		t := dest.Type()
 | 
			
		||||
		tk, tv := t.Key(), t.Elem()
 | 
			
		||||
		r = MapOf(t)
 | 
			
		||||
		for i := 0; i < l; i++ {
 | 
			
		||||
			e1, e2 := src.Index(i, true), AddressableOf(tv)
 | 
			
		||||
			if ok = conv(e1, e2); !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			k := AddressableOf(tk)
 | 
			
		||||
			if ok = conv(ValueOf(i), k); !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			r.SetMapIndex(k, e2)
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		if ok = l == 1; ok {
 | 
			
		||||
			return conv(src.Index(0, true), dest)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if ok {
 | 
			
		||||
		dest.Set(r)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fromSet(src, dest Value) (ok bool) {
 | 
			
		||||
	t, keys := dest.Type(), src.Keys()
 | 
			
		||||
	var r Value
 | 
			
		||||
	switch {
 | 
			
		||||
	case dest.Is(Slice):
 | 
			
		||||
		r, ok = SliceOf(t, len(keys), len(keys)), true
 | 
			
		||||
		for i, k := range keys {
 | 
			
		||||
			if ok = conv(src.MapIndex(k, true), r.Index(i)); !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	case dest.Is(Array):
 | 
			
		||||
		if ok = len(keys) == t.Len(); !ok {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		tsl := SliceTypeOf(t.Elem())
 | 
			
		||||
		r = SliceOf(tsl, len(keys), len(keys))
 | 
			
		||||
		if ok = fromSet(src, r); ok {
 | 
			
		||||
			r = r.Convert(PointerTo(t)).Elem()
 | 
			
		||||
		}
 | 
			
		||||
	case dest.IsSet():
 | 
			
		||||
		tk := t.Key()
 | 
			
		||||
		r, ok = MapOf(t), true
 | 
			
		||||
		for _, k := range keys {
 | 
			
		||||
			e1, e2 := src.MapIndex(k, true), AddressableOf(tk)
 | 
			
		||||
			if ok = conv(e1, e2); !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			r.AddToSet(e2)
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		if ok = len(keys) == 1; ok {
 | 
			
		||||
			ok = conv(src.MapIndex(keys[0], true), dest)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if ok {
 | 
			
		||||
		dest.Set(r)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fromMap(src, dest Value) (ok bool) {
 | 
			
		||||
	t, keys := dest.Type(), src.Keys()
 | 
			
		||||
	var r Value
 | 
			
		||||
	switch {
 | 
			
		||||
	case dest.Is(Slice):
 | 
			
		||||
		idx := make([]int, len(keys))
 | 
			
		||||
		ki := make(map[Value]int)
 | 
			
		||||
		for i, k := range keys {
 | 
			
		||||
			var e int
 | 
			
		||||
			if ok = conv(ValueOf(k.Interface()), ValueOf(&e).Elem()); !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			ki[k], idx[i] = e, e
 | 
			
		||||
		}
 | 
			
		||||
		sort.Ints(idx)
 | 
			
		||||
		for i, j := range idx {
 | 
			
		||||
			if ok = i == j; !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		r, ok = SliceOf(t, len(keys), len(keys)), true
 | 
			
		||||
		for _, k := range keys {
 | 
			
		||||
			if ok = conv(src.MapIndex(k, true), r.Index(ki[k])); !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	case dest.Is(Array):
 | 
			
		||||
		if ok = t.Len() != len(keys); !ok {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		tsl := SliceTypeOf(t.Elem())
 | 
			
		||||
		r = AddressableOf(tsl)
 | 
			
		||||
		if ok = fromMap(src, r); ok {
 | 
			
		||||
			r = r.Convert(PointerTo(t)).Elem()
 | 
			
		||||
		}
 | 
			
		||||
	case dest.Is(Map):
 | 
			
		||||
		tk, tv := t.Key(), t.Elem()
 | 
			
		||||
		r, ok = MapOf(t), true
 | 
			
		||||
		for _, k := range keys {
 | 
			
		||||
			e1, e2 := src.MapIndex(k, true), AddressableOf(tv)
 | 
			
		||||
			if ok = conv(e1, e2); !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			kd := AddressableOf(tk)
 | 
			
		||||
			if ok = conv(ValueOf(k.Interface()), kd); !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			r.SetMapIndex(kd, e2)
 | 
			
		||||
		}
 | 
			
		||||
	case dest.Is(Struct):
 | 
			
		||||
		r, ok = AddressableOf(t), true
 | 
			
		||||
		for _, k := range keys {
 | 
			
		||||
			var fs string
 | 
			
		||||
			if !Convert(k.Interface(), &fs) {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			if f, exists := t.FieldByName(fs); !exists || f.PkgPath != "" {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			e1, e2 := src.MapIndex(k, true), r.FieldByName(fs)
 | 
			
		||||
			if !e1.Is(Ptr) && e2.Is(Ptr) {
 | 
			
		||||
				e2.Set(PointerOf(e2.TypeElem()))
 | 
			
		||||
				e2 = e2.Elem()
 | 
			
		||||
			}
 | 
			
		||||
			if ok = conv(e1, e2); !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if ok {
 | 
			
		||||
		dest.Set(r)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fromStruct(src, dest Value) (ok bool) {
 | 
			
		||||
	ts, t := src.Type(), dest.Type()
 | 
			
		||||
	fields := ts.Fields()
 | 
			
		||||
	var r Value
 | 
			
		||||
	switch {
 | 
			
		||||
	case dest.Is(Struct):
 | 
			
		||||
		r, ok = AddressableOf(t), true
 | 
			
		||||
		for _, f := range fields {
 | 
			
		||||
			if _, exists := t.FieldByName(f.Name); !exists {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			e1, e2 := src.FieldByName(f.Name, true), r.FieldByName(f.Name)
 | 
			
		||||
			if !e1.Is(Ptr) && e2.Is(Ptr) {
 | 
			
		||||
				e2.Set(PointerOf(e2.TypeElem()))
 | 
			
		||||
				e2 = e2.Elem()
 | 
			
		||||
			} else if e1.Is(Ptr) && !e2.Is(Ptr) {
 | 
			
		||||
				if e1.IsNil() {
 | 
			
		||||
					e1 = ZeroOf(e1.Type().Elem())
 | 
			
		||||
				} else {
 | 
			
		||||
					e1 = e1.Elem()
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if ok = conv(e1, e2); !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	case dest.Is(Map):
 | 
			
		||||
		r, ok = MapOf(t), true
 | 
			
		||||
		tk, tv := t.Key(), t.Elem()
 | 
			
		||||
		for _, f := range fields {
 | 
			
		||||
			e1, e2 := src.FieldByName(f.Name, true), AddressableOf(tv)
 | 
			
		||||
			if e1.Is(Ptr) && !e2.Is(Ptr) {
 | 
			
		||||
				if e1.IsNil() {
 | 
			
		||||
					e1 = ZeroOf(e1.Type().Elem())
 | 
			
		||||
				} else {
 | 
			
		||||
					e1 = e1.Elem()
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if ok = conv(e1, e2); !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			k := AddressableOf(tk)
 | 
			
		||||
			if ok = conv(ValueOf(f.Name), k); !ok {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			r.SetMapIndex(k, e2)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if ok {
 | 
			
		||||
		dest.Set(r)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert convertit la valeur du paramètre source vers
 | 
			
		||||
// le paramètre destination et retourne true si l’opération
 | 
			
		||||
// s’est effectuée avec succès.
 | 
			
		||||
// La destination doit être un pointeur, afin de pouvoir modifier
 | 
			
		||||
// sa valeur.
 | 
			
		||||
// Si le paramètre optionnel safe est fourni et vaut true,
 | 
			
		||||
// la destination n’est modifiée que si son type est équivalent
 | 
			
		||||
// à celui de la source (par exemple int vers int64, mais
 | 
			
		||||
// pas int vers string).
 | 
			
		||||
func Convert(src, dest any, safe ...bool) bool {
 | 
			
		||||
	vs, vd := ValueOf(src), ValueOf(dest)
 | 
			
		||||
	if !vd.Is(Ptr) || vd.IsNil() {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return conv(vs, vd.Elem(), safe...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setDefault[T any](def ...T) (out T) {
 | 
			
		||||
	if len(def) > 0 {
 | 
			
		||||
		out = def[0]
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func toSingle[T BoolType | StringType | NumberType](src any, def ...T) (dest T) {
 | 
			
		||||
	if ok := Convert(src, &dest); !ok {
 | 
			
		||||
		dest = setDefault(def...)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ToBool[T BoolType](src any, def ...T) T {
 | 
			
		||||
	return toSingle(src, def...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ToChar[T CharType](src any, def ...T) T {
 | 
			
		||||
	return toSingle(src, def...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ToInt[T IntType](src any, def ...T) T {
 | 
			
		||||
	return toSingle(src, def...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ToUint[T UintType](src any, def ...T) T {
 | 
			
		||||
	return toSingle(src, def...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ToFloat[T FloatType](src any, def ...T) T {
 | 
			
		||||
	return toSingle(src, def...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ToComplex[T ComplexType](src any, def ...T) T {
 | 
			
		||||
	return toSingle(src, def...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ToString[T StringType](src any, def ...T) T {
 | 
			
		||||
	return toSingle(src, def...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ToSlice[T any](src any, def ...T) (dest []T) {
 | 
			
		||||
	if ok := Convert(src, &dest); !ok {
 | 
			
		||||
		dest = def
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ToMap[K comparable, V any](src any, def ...map[K]V) (dest map[K]V) {
 | 
			
		||||
	if ok := Convert(src, &dest); !ok {
 | 
			
		||||
		if len(def) > 0 {
 | 
			
		||||
			dest = def[0]
 | 
			
		||||
		} else {
 | 
			
		||||
			dest = make(map[K]V)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ToSet[K comparable](src any, def ...map[K]struct{}) map[K]struct{} {
 | 
			
		||||
	return ToMap(src, def...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetZero réinitialise la variable pointée
 | 
			
		||||
// par le paramètre d’entrée à sa valeur initiale
 | 
			
		||||
func SetZero(dst any) bool {
 | 
			
		||||
	vd := ValueOf(dst)
 | 
			
		||||
	if !vd.Is(Ptr) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	z := ZeroOf(vd.TypeElem())
 | 
			
		||||
	vd.SetElem(z)
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func clone(v Value, deep ...bool) Value {
 | 
			
		||||
	t := v.Type()
 | 
			
		||||
	var c Value
 | 
			
		||||
	switch {
 | 
			
		||||
	case v.IsNil():
 | 
			
		||||
		c = v
 | 
			
		||||
	case v.Is(Ptr):
 | 
			
		||||
		if len(deep) == 0 || !deep[0] {
 | 
			
		||||
			return v
 | 
			
		||||
		}
 | 
			
		||||
		vc := clone(v.Elem(), deep...)
 | 
			
		||||
		c = PointerOf(t.Elem())
 | 
			
		||||
		c.SetElem(vc)
 | 
			
		||||
	case v.Is(Slice):
 | 
			
		||||
		l := v.Len()
 | 
			
		||||
		c := SliceOf(t, l, v.Cap())
 | 
			
		||||
		for i := 0; i < l; i++ {
 | 
			
		||||
			s, d := v.Index(i), c.Index(i)
 | 
			
		||||
			d.Set(clone(s, deep...))
 | 
			
		||||
		}
 | 
			
		||||
	case v.Is(Array):
 | 
			
		||||
		l := v.Len()
 | 
			
		||||
		tsl := SliceTypeOf(t.Elem())
 | 
			
		||||
		c := SliceOf(tsl, l, v.Cap())
 | 
			
		||||
		for i := 0; i < l; i++ {
 | 
			
		||||
			s, d := v.Index(i), c.Index(i)
 | 
			
		||||
			d.Set(clone(s, deep...))
 | 
			
		||||
		}
 | 
			
		||||
		c = c.Convert(PointerTo(t)).Elem()
 | 
			
		||||
	case v.Is(Map):
 | 
			
		||||
		c = MapOf(t)
 | 
			
		||||
		for _, k := range v.Keys() {
 | 
			
		||||
			s := v.MapIndex(k)
 | 
			
		||||
			c.SetMapIndex(clone(k, deep...), clone(s, deep...))
 | 
			
		||||
		}
 | 
			
		||||
	case v.Is(Struct):
 | 
			
		||||
		c := ValueOf(t)
 | 
			
		||||
		n := t.NumField()
 | 
			
		||||
		for i := 0; i < n; i++ {
 | 
			
		||||
			f := t.Field(i)
 | 
			
		||||
			if f.PkgPath != "" {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			s, d := v.Field(i), c.Field(i)
 | 
			
		||||
			d.Set(clone(s, deep...))
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		c = PointerOf(t)
 | 
			
		||||
		Convert(v.Interface(), c.Interface())
 | 
			
		||||
		c = c.Elem()
 | 
			
		||||
	}
 | 
			
		||||
	return c
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CloneInterface est l’équivalent rapide de Clone
 | 
			
		||||
// si la valeur de sortie n’a pas besoin d’être typée.
 | 
			
		||||
func CloneInterface(e any, deep ...bool) any {
 | 
			
		||||
	c := clone(ValueOf(e), deep...)
 | 
			
		||||
	return c.Interface()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Clone retourne une copie de l’élément fournit en paramètre.
 | 
			
		||||
// Si deep est fourni et vaut true, le clonage s’effectue récursivement.
 | 
			
		||||
func Clone[T any](e T, deep ...bool) T {
 | 
			
		||||
	c := clone(ValueOf(e), deep...)
 | 
			
		||||
	if c.IsNil() {
 | 
			
		||||
		return e
 | 
			
		||||
	}
 | 
			
		||||
	var out T
 | 
			
		||||
	v := ValueOf(&out)
 | 
			
		||||
	v.SetElem(c)
 | 
			
		||||
	return v.Interface().(T)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										506
									
								
								convert/value.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										506
									
								
								convert/value.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,506 @@
 | 
			
		|||
package convert
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
 | 
			
		||||
	. "gitea.zaclys.com/bvaudour/gob/option"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Kind est un ensemble de reflect.Kind.
 | 
			
		||||
// Il permet de faciliter la comparaison de types similaires.
 | 
			
		||||
type Kind []reflect.Kind
 | 
			
		||||
 | 
			
		||||
func (k Kind) Or(in ...Kind) (out Kind) {
 | 
			
		||||
	out = append(out, k...)
 | 
			
		||||
 | 
			
		||||
	for _, e := range in {
 | 
			
		||||
		out = append(out, e...)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	Invalid   = Kind{reflect.Invalid}
 | 
			
		||||
	Bool      = Kind{reflect.Bool}
 | 
			
		||||
	Array     = Kind{reflect.Array}
 | 
			
		||||
	Chan      = Kind{reflect.Chan}
 | 
			
		||||
	Func      = Kind{reflect.Func}
 | 
			
		||||
	Interface = Kind{reflect.Interface}
 | 
			
		||||
	Map       = Kind{reflect.Map}
 | 
			
		||||
	Ptr       = Kind{reflect.Ptr}
 | 
			
		||||
	Slice     = Kind{reflect.Slice}
 | 
			
		||||
	String    = Kind{reflect.String}
 | 
			
		||||
	Struct    = Kind{reflect.Struct}
 | 
			
		||||
	Byte      = Kind{reflect.Uint8}
 | 
			
		||||
	Rune      = Kind{reflect.Int32}
 | 
			
		||||
	Int       = Kind{reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64}
 | 
			
		||||
	Uint      = Kind{reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr}
 | 
			
		||||
	Integer   = Int.Or(Uint)
 | 
			
		||||
	Float     = Kind{reflect.Float32, reflect.Float64}
 | 
			
		||||
	Complex   = Kind{reflect.Complex64, reflect.Complex128}
 | 
			
		||||
	Real      = Integer.Or(Float)
 | 
			
		||||
	Number    = Real.Or(Complex)
 | 
			
		||||
	Char      = Kind{reflect.Uint8, reflect.Int32}
 | 
			
		||||
	Nillable  = Kind{reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.Interface}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	empty        struct{}
 | 
			
		||||
	valueOfEmpty = ValueOf(empty)
 | 
			
		||||
	typeOfEmpty  = TypeOf(empty)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Kinder est une interface permettant de déterminer une sorte de type.
 | 
			
		||||
// Elle est implémentée par reflect.Type et reflect.Value.
 | 
			
		||||
type Kinder interface {
 | 
			
		||||
	Kind() reflect.Kind
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Type fournit des méthodes supplémentaires à reflect.Type dont elle hérite.
 | 
			
		||||
type Type struct {
 | 
			
		||||
	reflect.Type
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Value fournit des méthodes supplémentaires à reflect.Value dont elle hérite.
 | 
			
		||||
type Value struct {
 | 
			
		||||
	reflect.Value
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MapIter est similaire à reflect.MapIter mais pour travailler sur Value.
 | 
			
		||||
type MapIter struct {
 | 
			
		||||
	*reflect.MapIter
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (it MapIter) Key() Value {
 | 
			
		||||
	return Value{it.MapIter.Key()}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (it MapIter) Value() Value {
 | 
			
		||||
	return Value{it.MapIter.Value()}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SliceIter fournit un itérateur de Value de type Slice.
 | 
			
		||||
type SliceIter struct {
 | 
			
		||||
	sl Value
 | 
			
		||||
	i  int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (it *SliceIter) Reset() {
 | 
			
		||||
	it.i = -1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (it *SliceIter) Next() bool {
 | 
			
		||||
	if it.i < it.sl.Len()-1 {
 | 
			
		||||
		it.i++
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (it *SliceIter) Index() int {
 | 
			
		||||
	return it.i
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (it *SliceIter) Value() Value {
 | 
			
		||||
	return it.sl.Index(it.i)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func is(e Kinder, k Kind) (out bool) {
 | 
			
		||||
	ke := e.Kind()
 | 
			
		||||
	for _, ki := range k {
 | 
			
		||||
		if ke == ki {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValueOf retourne une valeur à partir d’une valeur concrète donnée.
 | 
			
		||||
func ValueOf(e any) Value {
 | 
			
		||||
	return Value{reflect.ValueOf(e)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PointerOf retourne une valeur contenant un pointeur du type donné.
 | 
			
		||||
// Par exemple, si t représente un type int, la valeur retournée
 | 
			
		||||
// embarque une valeur de type *int, initialisée. Cet exemple est équivalent
 | 
			
		||||
// à ValueOf(new(int)).
 | 
			
		||||
func PointerOf(t Type) Value {
 | 
			
		||||
	return Value{reflect.New(t.Type)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddressableOf retourne une valeur de type donnée et qui est adressable,
 | 
			
		||||
// donc modifiable. C’est équivalent à PointerOf(t).Elem()
 | 
			
		||||
func AddressableOf(t Type) Value {
 | 
			
		||||
	return PointerOf(t).Elem()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PointerTo retourne un type représentant un pointeur du type donné.
 | 
			
		||||
// Par exemple, si t est un type représentant int, le type retourné
 | 
			
		||||
// représente *int.
 | 
			
		||||
func PointerTo(t Type) Type {
 | 
			
		||||
	return Type{reflect.PointerTo(t.Type)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SliceOf retourne un slice initialisé de type t, longueur l et capacité c.
 | 
			
		||||
func SliceOf(t Type, l, c int) Value {
 | 
			
		||||
	return Value{reflect.MakeSlice(t.Type, l, c)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MapOf retourne une map initialisée du type donné.
 | 
			
		||||
func MapOf(t Type) Value {
 | 
			
		||||
	return Value{reflect.MakeMap(t.Type)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ZeroOf retourne la valeur zéro du type donné.
 | 
			
		||||
func ZeroOf(t Type) Value {
 | 
			
		||||
	return Value{reflect.Zero(t.Type)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SliceTypeOf retourne un type représentation une slice du type donné.
 | 
			
		||||
// Par exemple, si t est un type représentant int, le type retourné représente []int.
 | 
			
		||||
func SliceTypeOf(t Type) Type {
 | 
			
		||||
	return Type{reflect.SliceOf(t.Type)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MapTypeOf retourne un type représentation une map des types clé et valeur donnés.
 | 
			
		||||
// Par exemple, si k est un type représentant un string, et v, un type représentant un int,
 | 
			
		||||
// le type retourné représente map[string]int.
 | 
			
		||||
func MapTypeOf(k Type, v Type) Type {
 | 
			
		||||
	return Type{reflect.MapOf(k.Type, v.Type)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Copy copie le contenu de dest vers src.
 | 
			
		||||
// dest et src doivent être de même type et être des slices ou des arrays.
 | 
			
		||||
func Copy(src, dest Value) int {
 | 
			
		||||
	return reflect.Copy(src.Value, dest.Value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Append ajoute les valeurs de x au slice s et retourne le slice résultant.
 | 
			
		||||
func Append(s Value, x ...Value) Value {
 | 
			
		||||
	x2 := make([]reflect.Value, len(x))
 | 
			
		||||
	for i, e := range x {
 | 
			
		||||
		x2[i] = e.Value
 | 
			
		||||
	}
 | 
			
		||||
	return Value{reflect.Append(s.Value, x2...)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AppendSlice ajoute le slice t au slice s et retourne le slice résultant.
 | 
			
		||||
func AppendSlice(s Value, t Value) Value {
 | 
			
		||||
	return Value{reflect.AppendSlice(s.Value, t.Value)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Is vérifie si la valeur a un type appartenant à l’ensemble de sortes de types donné.
 | 
			
		||||
func (v Value) Is(k Kind) bool {
 | 
			
		||||
	return is(v, k)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Slice retourne une portion de slice. C’est en quelque sorte l’équivalent de v[i:j]
 | 
			
		||||
func (v Value) Slice(i, j int) Value {
 | 
			
		||||
	return Value{v.Value.Slice(i, j)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Type retourne le type de la valeur.
 | 
			
		||||
func (v Value) Type() Type {
 | 
			
		||||
	return Type{v.Value.Type()}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeepType retourne le type profond de la valeur.
 | 
			
		||||
// Généralement, cela est équivalent à v.Type(), sauf dans le cas ou la valeur
 | 
			
		||||
// est générée de façon interne, par exemple un élément d’une map de type map[any]any
 | 
			
		||||
// qui, bien qu’initialisée est considérée comme une interface mais pourrait contenir
 | 
			
		||||
// en vraie une string.
 | 
			
		||||
func (v Value) DeepType() Type {
 | 
			
		||||
	return TypeOf(v.Interface())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TypeElem retourne le type d’élément du type de la valeur.
 | 
			
		||||
// Par exemple, si v représente un []int, son élément sera de type int.
 | 
			
		||||
func (v Value) TypeElem() Type {
 | 
			
		||||
	return v.Type().Elem()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsSet retourne vrai si la valeur a un type de la forme map[T]struct{}
 | 
			
		||||
func (v Value) IsSet() bool {
 | 
			
		||||
	return v.Type().IsSet()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsZero retourne vrai si la valeur est le zéro de son type.
 | 
			
		||||
// Contrairement à la méthode équivalente de reflect.Value, elle ne panique jamais.
 | 
			
		||||
func (v Value) IsZero() bool {
 | 
			
		||||
	return !v.Is(Invalid) && v.Value.IsZero()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsNil retourne vrai si la valeur est nulle.
 | 
			
		||||
// Contrairement à la méthode équivalente de reflect.Value, elle ne panique jamais.
 | 
			
		||||
func (v Value) IsNil() bool {
 | 
			
		||||
	return v.Is(Invalid) || (v.Is(Nillable) && v.Value.IsNil())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Zero retourne le zéro du type de la valeur.
 | 
			
		||||
func (v Value) Zero() Value {
 | 
			
		||||
	if v.IsZero() {
 | 
			
		||||
		return v
 | 
			
		||||
	}
 | 
			
		||||
	return v.Type().Zero()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Pointer retourne un pointeur vers la valeur.
 | 
			
		||||
// Si la valeur n’est pas adressable, elle retourne
 | 
			
		||||
// un pointeur initialisé vers une valeur du type de la valeur.
 | 
			
		||||
func (v Value) Pointer() Value {
 | 
			
		||||
	if v.CanAddr() {
 | 
			
		||||
		return Value{v.Addr()}
 | 
			
		||||
	}
 | 
			
		||||
	return v.Type().Pointer()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Elem retourne l’élément pointé par la valeur.
 | 
			
		||||
// Tout comme reflect.Value, elle panique si v n’est pas une interface ou un pointeur.
 | 
			
		||||
func (v Value) Elem() Value {
 | 
			
		||||
	return Value{v.Value.Elem()}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set modifie la valeur par la valeur donnée.
 | 
			
		||||
func (v Value) Set(e Value) {
 | 
			
		||||
	v.Value.Set(e.Value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetVal est équivalent à Set mais avec une valeur concrète.
 | 
			
		||||
func (v Value) SetVal(e any) {
 | 
			
		||||
	v.Set(ValueOf(e))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetElem modifie la valeur de la variable pointée par la valeur.
 | 
			
		||||
func (v Value) SetElem(e Value) {
 | 
			
		||||
	v.Elem().Set(e)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetElemVal est équivalent à SetElem mais avec une valeur concrète.
 | 
			
		||||
func (v Value) SetElemVal(e any) {
 | 
			
		||||
	v.Elem().SetVal(e)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Convert retourne la valeur convertie au type donné.
 | 
			
		||||
// La valeur n’est pas modifiée.
 | 
			
		||||
func (v Value) Convert(t Type) Value {
 | 
			
		||||
	return Value{v.Value.Convert(t.Type)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func deepValue(v reflect.Value, deep []bool) Value {
 | 
			
		||||
	if len(deep) > 0 && deep[0] {
 | 
			
		||||
		return ValueOf(v.Interface())
 | 
			
		||||
	}
 | 
			
		||||
	return Value{v}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Index retourne la ième valeur d’un tableau. Si deep est fourni
 | 
			
		||||
// et est vrai, il force le retypage profond.
 | 
			
		||||
// Par exemple, si v représente []any{5}, v.Index(0) retourne
 | 
			
		||||
// la valeur 5 de type interface, mais v.Index(0, true) retourne
 | 
			
		||||
// la valeur 5 de type int.
 | 
			
		||||
func (v Value) Index(i int, deep ...bool) Value {
 | 
			
		||||
	return deepValue(v.Value.Index(i), deep)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SliceRange retourne un itérateur de slice.
 | 
			
		||||
func (v Value) SliceRange() *SliceIter {
 | 
			
		||||
	if !v.Is(Slice) {
 | 
			
		||||
		panic("not a slice")
 | 
			
		||||
	}
 | 
			
		||||
	return &SliceIter{
 | 
			
		||||
		sl: v,
 | 
			
		||||
		i:  -1,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddToSet ajoute une valeur dans le set de valeurs représenté par v.
 | 
			
		||||
// v doit donc être du type de la forme map[T]struct{}
 | 
			
		||||
func (v Value) AddToSet(e Value) { v.SetMapIndex(e, valueOfEmpty) }
 | 
			
		||||
 | 
			
		||||
// Keys retourne les clés de la valeur. La valeur doit être une map.
 | 
			
		||||
func (v Value) Keys() []Value {
 | 
			
		||||
	keys := v.MapKeys()
 | 
			
		||||
	out := make([]Value, len(keys))
 | 
			
		||||
	for i, k := range keys {
 | 
			
		||||
		out[i].Value = k
 | 
			
		||||
	}
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MapIndex retourne la kème valeur d’une map. Si deep est fourni
 | 
			
		||||
// et est vrai, il force le retypage profond.
 | 
			
		||||
// Par exemple, si v représente map[string]any{"cinq": 5}, v.MapIndex(ValueOf("cinq")) retourne
 | 
			
		||||
// la valeur 5 de type interface, mais v.MapIndex(ValueOf("cinq"), true) retourne
 | 
			
		||||
// la valeur 5 de type int.
 | 
			
		||||
func (v Value) MapIndex(k Value, deep ...bool) Value {
 | 
			
		||||
	return deepValue(v.Value.MapIndex(k.Value), deep)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MapRange retourne un itérateur de map.
 | 
			
		||||
func (v Value) MapRange() MapIter {
 | 
			
		||||
	return MapIter{v.Value.MapRange()}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Equal retourne vrai si les valeurs sont égales.
 | 
			
		||||
func (v1 Value) Equal(v2 Value) bool {
 | 
			
		||||
	return v1.Value.Equal(v2.Value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MapIndexIfExists agit comme MapIndex mais indique aussi si la valeur existe.
 | 
			
		||||
func (v Value) MapIndexIfExists(k Value) (out Option[Value]) {
 | 
			
		||||
	r := v.MapRange()
 | 
			
		||||
	for r.Next() {
 | 
			
		||||
		if exists := k.Equal(r.Key()); exists {
 | 
			
		||||
			out = Some(r.Value())
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetMapIndex associe value à la clé key dans la map.
 | 
			
		||||
func (v Value) SetMapIndex(key, value Value) {
 | 
			
		||||
	if vv, ok := v.MapIndexIfExists(key).Get(); ok {
 | 
			
		||||
		vv.Set(value)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DelMapIndex supprime la clé de la map.
 | 
			
		||||
func (v Value) DelMapIndex(key Value) {
 | 
			
		||||
	v.Value.SetMapIndex(key.Value, ZeroOf(v.TypeElem()).Value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetIndex modifie la valeur de l’index du slice par la valeur fournie.
 | 
			
		||||
func (v Value) SetIndex(i int, value Value) {
 | 
			
		||||
	v.Index(i).Set(value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FieldByName retourne la valeur du champ nommé n. v doit être une structure.
 | 
			
		||||
// Si deep est vrai, force le typage interne.
 | 
			
		||||
func (v Value) FieldByName(n string, deep ...bool) Value {
 | 
			
		||||
	return deepValue(v.Value.FieldByName(n), deep)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Field retourne la valeur du iè champ. v doit être une structure.
 | 
			
		||||
// Si deep est vrai, force le typage interne.
 | 
			
		||||
func (v Value) Field(i int, deep ...bool) Value {
 | 
			
		||||
	return deepValue(v.Value.Field(i), deep)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Fields retourne la liste des champs. v doit être une structure.
 | 
			
		||||
func (v Value) Fields() []reflect.StructField {
 | 
			
		||||
	return v.Type().Fields()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TypeOf retourne le type de la valeur donnée.
 | 
			
		||||
func TypeOf(e any) Type {
 | 
			
		||||
	return Type{reflect.TypeOf(e)}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Is vérifie si la valeur a un type appartenant à l’ensemble de sortes de types donné.
 | 
			
		||||
func (t Type) Is(k Kind) bool {
 | 
			
		||||
	return is(t, k)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsSet retourne vrai si la valeur a un type de la forme map[T]struct{}
 | 
			
		||||
func (t Type) IsSet() bool {
 | 
			
		||||
	return t.Is(Map) && typeOfEmpty.AssignableTo(t.Elem()) && t.Elem().AssignableTo(typeOfEmpty)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Elem retourne l’élément pointé par la valeur.
 | 
			
		||||
// Tout comme reflect.Type, elle panique si t n’est pas un pointeur, un array, un slice, une map ou un chan.
 | 
			
		||||
func (t Type) Elem() Type {
 | 
			
		||||
	return Type{t.Type.Elem()}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Key retourne le type de la clé. Elle panique si t n’est pas une map.
 | 
			
		||||
func (t Type) Key() Type {
 | 
			
		||||
	return Type{t.Type.Key()}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AssignableTo se comporte comme la méthode équivalente de reflect.Type.
 | 
			
		||||
func (t Type) AssignableTo(e Type) bool {
 | 
			
		||||
	return t.Type.AssignableTo(e.Type)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ComvertibleTo se comporte comme la méthode équivalente de reflect.Type.
 | 
			
		||||
func (t Type) ConvertibleTo(e Type) bool {
 | 
			
		||||
	return t.Type.ConvertibleTo(e.Type)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EquivalentTo vérifie la convertibilité dans les deux sens.
 | 
			
		||||
// Par exemple un int64 est équivalent à un int mais pas une interface.
 | 
			
		||||
func (t Type) EquivalentTo(e Type) bool {
 | 
			
		||||
	return t.ConvertibleTo(e) && e.ConvertibleTo(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Zero retourne la valeur zéro du type.
 | 
			
		||||
func (t Type) Zero() Value {
 | 
			
		||||
	return ZeroOf(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Pointer retourne un pointeur initialisé vers une valeur du type.
 | 
			
		||||
func (t Type) Pointer() Value {
 | 
			
		||||
	return PointerOf(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Fields retourne la liste des champs. t doit être une structure.
 | 
			
		||||
func (t Type) Fields() []reflect.StructField {
 | 
			
		||||
	l := t.NumField()
 | 
			
		||||
	fields := make([]reflect.StructField, 0, l)
 | 
			
		||||
	for i := 0; i < l; i++ {
 | 
			
		||||
		f := t.Field(i)
 | 
			
		||||
		if f.PkgPath == "" {
 | 
			
		||||
			fields = append(fields, f)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return fields
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MapFields retourne la liste des champs indexés par leurs noms. t doit être une structure.
 | 
			
		||||
func (t Type) MapFields() map[string]reflect.StructField {
 | 
			
		||||
	l := t.NumField()
 | 
			
		||||
	fields := make(map[string]reflect.StructField)
 | 
			
		||||
	for i := 0; i < l; i++ {
 | 
			
		||||
		f := t.Field(i)
 | 
			
		||||
		if f.PkgPath == "" {
 | 
			
		||||
			fields[f.Name] = f
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return fields
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Is vérifie si la valeur e a un type appartenant à l’ensemble de sortes de types donné.
 | 
			
		||||
func Is(e any, k Kind) bool {
 | 
			
		||||
	return TypeOf(e).Is(k)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func IsZero(e any) bool { return ValueOf(e).IsZero() }
 | 
			
		||||
func IsNil(e any) bool  { return ValueOf(e).IsNil() }
 | 
			
		||||
 | 
			
		||||
func IsInvalid(e any) bool   { return Is(e, Invalid) }
 | 
			
		||||
func IsBool(e any) bool      { return Is(e, Bool) }
 | 
			
		||||
func IsArray(e any) bool     { return Is(e, Array) }
 | 
			
		||||
func IsChan(e any) bool      { return Is(e, Chan) }
 | 
			
		||||
func IsFunc(e any) bool      { return Is(e, Func) }
 | 
			
		||||
func IsInterface(e any) bool { return Is(e, Interface) }
 | 
			
		||||
func IsMap(e any) bool       { return Is(e, Map) }
 | 
			
		||||
func IsSet(e any) bool       { return TypeOf(e).IsSet() }
 | 
			
		||||
func IsPointer(e any) bool   { return Is(e, Ptr) }
 | 
			
		||||
func IsSlice(e any) bool     { return Is(e, Slice) }
 | 
			
		||||
func IsString(e any) bool    { return Is(e, String) }
 | 
			
		||||
func IsStruct(e any) bool    { return Is(e, Struct) }
 | 
			
		||||
func IsByte(e any) bool      { return Is(e, Byte) }
 | 
			
		||||
func IsRune(e any) bool      { return Is(e, Rune) }
 | 
			
		||||
func IsInt(e any) bool       { return Is(e, Int) }
 | 
			
		||||
func IsUint(e any) bool      { return Is(e, Uint) }
 | 
			
		||||
func IsInteger(e any) bool   { return Is(e, Integer) }
 | 
			
		||||
func IsFloat(e any) bool     { return Is(e, Float) }
 | 
			
		||||
func IsComplex(e any) bool   { return Is(e, Complex) }
 | 
			
		||||
func IsReal(e any) bool      { return Is(e, Real) }
 | 
			
		||||
func IsNumber(e any) bool    { return Is(e, Number) }
 | 
			
		||||
func IsChar(e any) bool      { return Is(e, Char) }
 | 
			
		||||
func IsNillable(e any) bool  { return Is(e, Nillable) }
 | 
			
		||||
							
								
								
									
										3
									
								
								go.mod
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								go.mod
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
module gitea.zaclys.com/bvaudour/gob
 | 
			
		||||
 | 
			
		||||
go 1.21.1
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue