Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cleanup(ygot): render cleanups and minor improvements for reflect uses #831

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 35 additions & 16 deletions ygot/render.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"errors"
"fmt"
"reflect"
"strconv"
"strings"

"github.com/openconfig/gnmi/errlist"
Expand Down Expand Up @@ -65,7 +66,7 @@ var (
// unionSingletonUnderlyingTypes stores the underlying types of the
// singleton (i.e. non-struct, non-slice, non-map) typedefs used to
// represent union subtypes for the "Simplified Union Leaf" way of
// representatiing unions in the Go generated code.
// representing unions in the Go generated code.
unionSingletonUnderlyingTypes = map[string]reflect.Type{
"UnionInt8": reflect.TypeOf(int8(0)),
"UnionInt16": reflect.TypeOf(int16(0)),
Expand Down Expand Up @@ -93,7 +94,10 @@ func (p *path) String() string {
if p.p.isPathElemPath() {
return prototext.Format(&gnmipb.Path{Elem: p.p.pathElemPath})
}
return fmt.Sprintf("%v", p.p.pathElemPath)

// If the path is not path element path, return the joined string (unique for keying)
// of the string slice path.
return strings.Join(p.p.stringSlicePath, "/")
}

// pathval combines path and the value for the relative or absolute path.
Expand Down Expand Up @@ -859,7 +863,7 @@ func EncodeTypedValue(val any, enc gnmipb.Encoding, opts ...EncodeTypedValueOpt)
if err != nil {
return nil, fmt.Errorf("cannot marshal enum, %v", err)
}
return &gnmipb.TypedValue{Value: &gnmipb.TypedValue_StringVal{en}}, nil
return &gnmipb.TypedValue{Value: &gnmipb.TypedValue_StringVal{StringVal: en}}, nil
}

vv := reflect.ValueOf(val)
Expand All @@ -871,9 +875,9 @@ func EncodeTypedValue(val any, enc gnmipb.Encoding, opts ...EncodeTypedValueOpt)
return nil, fmt.Errorf("cannot represent field value %v as TypedValue", val)
case vv.Type().Name() == BinaryTypeName:
// This is a binary type which is defined as a []byte, so we encode it as the bytes.
return &gnmipb.TypedValue{Value: &gnmipb.TypedValue_BytesVal{vv.Bytes()}}, nil
return &gnmipb.TypedValue{Value: &gnmipb.TypedValue_BytesVal{BytesVal: vv.Bytes()}}, nil
case vv.Type().Name() == EmptyTypeName:
return &gnmipb.TypedValue{Value: &gnmipb.TypedValue_BoolVal{vv.Bool()}}, nil
return &gnmipb.TypedValue{Value: &gnmipb.TypedValue_BoolVal{BoolVal: vv.Bool()}}, nil
case vv.Kind() == reflect.Slice:
sval, err := leaflistToSlice(vv, false)
if err != nil {
Expand All @@ -884,7 +888,7 @@ func EncodeTypedValue(val any, enc gnmipb.Encoding, opts ...EncodeTypedValueOpt)
if err != nil {
return nil, err
}
return &gnmipb.TypedValue{Value: &gnmipb.TypedValue_LeaflistVal{arr}}, nil
return &gnmipb.TypedValue{Value: &gnmipb.TypedValue_LeaflistVal{LeaflistVal: arr}}, nil
case util.IsValueStructPtr(vv):
nv, err := unwrapUnionInterfaceValue(vv, false)
if err != nil {
Expand All @@ -893,7 +897,7 @@ func EncodeTypedValue(val any, enc gnmipb.Encoding, opts ...EncodeTypedValueOpt)
vv = reflect.ValueOf(nv)
// Apart from binary, all other possible union subtypes are scalars or typedefs of scalars.
if vv.Type().Name() == BinaryTypeName {
return &gnmipb.TypedValue{Value: &gnmipb.TypedValue_BytesVal{vv.Bytes()}}, nil
return &gnmipb.TypedValue{Value: &gnmipb.TypedValue_BytesVal{BytesVal: vv.Bytes()}}, nil
}
case util.IsValuePtr(vv):
vv = vv.Elem()
Expand Down Expand Up @@ -1246,9 +1250,6 @@ func rewriteModName(mod string, rules map[string]string) string {
// there are modules to be prepended, it also returns the module to which the
// field belongs. It will also return an error if it encounters one.
func prependmodsJSON(fType reflect.StructField, parentMod string, args jsonOutputConfig) ([][]string, string, error) {
var prependmods [][]string
var chMod string

mapModules, err := structTagToLibModules(fType, args.rfc7951Config.PreferShadowPath)
if err != nil {
return nil, "", fmt.Errorf("%s: %v", fType.Name, err)
Expand All @@ -1257,8 +1258,11 @@ func prependmodsJSON(fType reflect.StructField, parentMod string, args jsonOutpu
return nil, "", nil
}

for _, modulePath := range mapModules {
var prependmod []string
prependmods := make([][]string, len(mapModules))
var chMod string

for idx, modulePath := range mapModules {
prependmod := make([]string, modulePath.Len())
prevMod := parentMod
for i := 0; i != modulePath.Len(); i++ {
mod, err := modulePath.StringElemAt(i)
Expand All @@ -1274,12 +1278,12 @@ func prependmodsJSON(fType reflect.StructField, parentMod string, args jsonOutpu
} else {
prevMod = mod
}
prependmod = append(prependmod, mod)
prependmod[i] = mod
}
if chMod != "" && prevMod != chMod {
return nil, "", fmt.Errorf("%s: child modules between all paths are not equal: %v", fType.Name, mapModules)
}
prependmods = append(prependmods, prependmod)
prependmods[idx] = prependmod
chMod = prevMod
}
return prependmods, chMod, nil
Expand Down Expand Up @@ -1415,8 +1419,20 @@ func structJSON(s GoStruct, parentMod string, args jsonOutputConfig) (map[string
// and float64 values are represented as strings.
func writeIETFScalarJSON(i any) any {
switch reflect.ValueOf(i).Kind() {
case reflect.Uint64, reflect.Int64, reflect.Float64:
case reflect.Float64:
return fmt.Sprintf("%v", i)
case reflect.Int64:
if val, ok := i.(int64); ok {
return strconv.FormatInt(int64(val), 10)
}

return fmt.Sprintf("%d", i)
case reflect.Uint64:
if val, ok := i.(uint64); ok {
return strconv.FormatUint(uint64(val), 10)
}

return fmt.Sprintf("%d", i)
}
return i
}
Expand Down Expand Up @@ -1635,14 +1651,17 @@ func jsonValue(field reflect.Value, parentMod string, args jsonOutputConfig) (an
if err != nil {
errs.Add(err)
}
case reflect.String:
value = field.Elem().String()
case reflect.Bool:
value = field.Elem().Bool()
default:
value = field.Elem().Interface()
if args.jType == RFC7951 {
value = writeIETFScalarJSON(value)
}
}
case reflect.Slice:

isAnnotationSlice := func(v reflect.Value) bool {
annoT := reflect.TypeOf((*Annotation)(nil)).Elem()
return v.Type().Elem().Implements(annoT)
Expand Down