/
githubmirror
/
hugo
Обзор
Документация
Войти
/
githubmirror
/
hugo
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
common/hreflect/convert.go
222 строки
5 KB
Bjørn Erik Pedersen
all: Run go fix ./...
07 мар 2026, 20:30
07 мар 2026, 20:30
e310822
Код
Авторство
О чём код?
// Copyright 2025 The Hugo Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package hreflect import ( "fmt" "math" "reflect" ) var ( typeInt64 = reflect.TypeFor[int64]() typeFloat64 = reflect.TypeFor[float64]() typeString = reflect.TypeFor[string]() ) // ToInt64 converts v to int64 if possible, returning an error if not. func ToInt64E(v reflect.Value) (int64, error) { if v, ok := ConvertIfPossible(v, typeInt64); ok { return v.Int(), nil } return 0, errConvert(v, "int64") } // ToInt64 converts v to int64 if possible. It panics if the conversion is not possible. func ToInt64(v reflect.Value) int64 { vv, err := ToInt64E(v) if err != nil { panic(err) } return vv } // ToFloat64E converts v to float64 if possible, returning an error if not. func ToFloat64E(v reflect.Value) (float64, error) { if v, ok := ConvertIfPossible(v, typeFloat64); ok { return v.Float(), nil } return 0, errConvert(v, "float64") } // ToFloat64 converts v to float64 if possible, panicking if not. func ToFloat64(v reflect.Value) float64 { vv, err := ToFloat64E(v) if err != nil { panic(err) } return vv } // ToStringE converts v to string if possible, returning an error if not. func ToStringE(v reflect.Value) (string, error) { vv, err := ToStringValueE(v) if err != nil { return "", err } return vv.String(), nil } func ToStringValueE(v reflect.Value) (reflect.Value, error) { if v, ok := ConvertIfPossible(v, typeString); ok { return v, nil } return reflect.Value{}, errConvert(v, "string") } // ToString converts v to string if possible, panicking if not. func ToString(v reflect.Value) string { vv, err := ToStringE(v) if err != nil { panic(err) } return vv } func errConvert(v reflect.Value, s string) error { return fmt.Errorf("unable to convert value of type %q to %q", v.Type().String(), s) } // ConvertIfPossible tries to convert val to typ if possible. // This is currently only implemented for int kinds, // added to handle the move to a new YAML library which produces uint64 for unsigned integers. // We can expand on this later if needed. // This conversion is lossless. // See Issue 14079. func ConvertIfPossible(val reflect.Value, typ reflect.Type) (reflect.Value, bool) { switch val.Kind() { case reflect.Pointer, reflect.Interface: if val.IsNil() { // Return typ's zero value. return reflect.Zero(typ), true } val = val.Elem() } if val.Type().AssignableTo(typ) { // No conversion needed. return val, true } if IsInt(typ.Kind()) { return convertToIntIfPossible(val, typ) } if IsFloat(typ.Kind()) { return convertToFloatIfPossible(val, typ) } if IsUint(typ.Kind()) { return convertToUintIfPossible(val, typ) } if IsString(typ.Kind()) && IsString(val.Kind()) { return val.Convert(typ), true } return reflect.Value{}, false } func convertToUintIfPossible(val reflect.Value, typ reflect.Type) (reflect.Value, bool) { if IsInt(val.Kind()) { i := val.Int() if i < 0 { return reflect.Value{}, false } u := uint64(i) if typ.OverflowUint(u) { return reflect.Value{}, false } return reflect.ValueOf(u).Convert(typ), true } if IsUint(val.Kind()) { if typ.OverflowUint(val.Uint()) { return reflect.Value{}, false } return val.Convert(typ), true } if IsFloat(val.Kind()) { f := val.Float() if f < 0 || f > float64(math.MaxUint64) { return reflect.Value{}, false } if f != math.Trunc(f) { return reflect.Value{}, false } u := uint64(f) if typ.OverflowUint(u) { return reflect.Value{}, false } return reflect.ValueOf(u).Convert(typ), true } return reflect.Value{}, false } func convertToFloatIfPossible(val reflect.Value, typ reflect.Type) (reflect.Value, bool) { if IsInt(val.Kind()) { i := val.Int() f := float64(i) if typ.OverflowFloat(f) { return reflect.Value{}, false } return reflect.ValueOf(f).Convert(typ), true } if IsUint(val.Kind()) { u := val.Uint() f := float64(u) if typ.OverflowFloat(f) { return reflect.Value{}, false } return reflect.ValueOf(f).Convert(typ), true } if IsFloat(val.Kind()) { if typ.OverflowFloat(val.Float()) { return reflect.Value{}, false } return val.Convert(typ), true } return reflect.Value{}, false } func convertToIntIfPossible(val reflect.Value, typ reflect.Type) (reflect.Value, bool) { if IsInt(val.Kind()) { if typ.OverflowInt(val.Int()) { return reflect.Value{}, false } return val.Convert(typ), true } if IsUint(val.Kind()) { if val.Uint() > uint64(math.MaxInt64) { return reflect.Value{}, false } if typ.OverflowInt(int64(val.Uint())) { return reflect.Value{}, false } return val.Convert(typ), true } if IsFloat(val.Kind()) { f := val.Float() if f < float64(math.MinInt64) || f > float64(math.MaxInt64) { return reflect.Value{}, false } if f != math.Trunc(f) { return reflect.Value{}, false } if typ.OverflowInt(int64(f)) { return reflect.Value{}, false } return reflect.ValueOf(int64(f)).Convert(typ), true } return reflect.Value{}, false }