@@ -19,13 +19,13 @@ import (
1919 "errors"
2020 "fmt"
2121 "reflect"
22- "sort"
2322 "strings"
2423
2524 "github.com/openconfig/gnmi/errlist"
2625 "github.com/openconfig/gnmi/value"
2726 "github.com/openconfig/ygot/internal/yreflect"
2827 "github.com/openconfig/ygot/util"
28+ "golang.org/x/exp/slices"
2929 "google.golang.org/protobuf/encoding/prototext"
3030 "google.golang.org/protobuf/proto"
3131
@@ -1442,74 +1442,68 @@ func keyValue(v reflect.Value, prependModuleNameIref bool) (any, error) {
14421442 return name , nil
14431443}
14441444
1445- // mapJSON takes an input reflect.Value containing a map, and
1446- // constructs the representation for JSON marshalling that corresponds to it.
1447- // The module within which the map is defined is specified by the parentMod
1448- // argument.
1449- func mapJSON (field reflect.Value , parentMod string , args jsonOutputConfig ) (any , error ) {
1450- var errs errlist.List
1451- mapKeyMap := map [string ]reflect.Value {}
1452- // Order of elements determines the order in which keys will be processed.
1453- var mapKeys []string
1445+ // mapKeyToJSONString converts a map key to a string to be used in JSON output.
1446+ func mapKeyToJSONString (k reflect.Value , args jsonOutputConfig ) (string , error ) {
14541447 switch args .jType {
14551448 case RFC7951 :
1456- // YANG lists are marshalled into a JSON object array for IETF
1457- // JSON. We handle the keys in alphabetical order to ensure that
1458- // deterministic ordering is achieved in the output JSON.
1459- for _ , k := range field .MapKeys () {
1460- keyval , err := keyValue (k , false )
1461- if err != nil {
1462- errs .Add (fmt .Errorf ("invalid enumerated key: %v" , err ))
1463- continue
1464- }
1465- kn := fmt .Sprintf ("%v" , keyval )
1466- mapKeys = append (mapKeys , kn )
1467- mapKeyMap [kn ] = k
1449+ k , err := keyValue (k , false )
1450+ if err != nil {
1451+ return "" , fmt .Errorf ("invalid enumerated key: %v" , err )
14681452 }
1453+ return fmt .Sprintf ("%v" , k ), nil
14691454 case Internal :
14701455 // In non-IETF JSON, then we output a list as a JSON object. The keys
14711456 // are stored as strings.
1472- for _ , k := range field .MapKeys () {
1473- var kn string
1474- switch k .Kind () {
1475- case reflect .Struct :
1476- // Handle the case of a multikey list.
1477- var kp []string
1478- for j := 0 ; j < k .NumField (); j ++ {
1479- keyval , err := keyValue (k .Field (j ), false )
1480- if err != nil {
1481- errs .Add (fmt .Errorf ("invalid enumerated key: %v" , err ))
1482- continue
1483- }
1484- kp = append (kp , fmt .Sprintf ("%v" , keyval ))
1485- }
1486- kn = strings .Join (kp , " " )
1487- case reflect .Int64 :
1488- keyval , err := keyValue (k , false )
1457+ switch k .Kind () {
1458+ case reflect .Struct :
1459+ var errs errlist.List
1460+ // Handle the case of a multikey list.
1461+ var kp []string
1462+ for j := 0 ; j < k .NumField (); j ++ {
1463+ keyval , err := keyValue (k .Field (j ), false )
14891464 if err != nil {
14901465 errs .Add (fmt .Errorf ("invalid enumerated key: %v" , err ))
14911466 continue
14921467 }
1493- kn = fmt .Sprintf ("%v" , keyval )
1494- default :
1495- kn = fmt .Sprintf ("%v" , k .Interface ())
1468+ kp = append (kp , fmt .Sprintf ("%v" , keyval ))
1469+ }
1470+ if errs .Err () != nil {
1471+ return "" , errs .Err ()
1472+ }
1473+ return strings .Join (kp , " " ), nil
1474+ case reflect .Int64 :
1475+ keyval , err := keyValue (k , false )
1476+ if err != nil {
1477+ return "" , fmt .Errorf ("invalid enumerated key: %v" , err )
14961478 }
1497- mapKeys = append (mapKeys , kn )
1498- mapKeyMap [kn ] = k
1479+ return fmt .Sprintf ("%v" , keyval ), nil
1480+ default :
1481+ return fmt .Sprintf ("%v" , k .Interface ()), nil
14991482 }
15001483 default :
1501- return nil , fmt .Errorf ("unknown JSON type: %v" , args .jType )
1484+ return "" , fmt .Errorf ("unknown JSON type: %v" , args .jType )
15021485 }
1503- sort .Strings (mapKeys )
1486+ }
1487+
1488+ // mapValuePair represents a map value pair with the key as a string.
1489+ type mapValuePair struct {
1490+ k string
1491+ v reflect.Value
1492+ }
15041493
1505- if len (mapKeys ) == 0 {
1494+ // mapValuePairsToJSON converts the given ordered pair of map values to JSON
1495+ // according to the JSON format option.
1496+ func mapValuePairsToJSON (pairs []mapValuePair , parentMod string , args jsonOutputConfig ) (any , error ) {
1497+ if len (pairs ) == 0 {
15061498 // empty list should be encoded as empty list
15071499 if args .jType == RFC7951 {
15081500 return []any {}, nil
15091501 }
15101502 return nil , nil
15111503 }
15121504
1505+ var errs errlist.List
1506+
15131507 // Build the output that we expect. Since there is a difference between the IETF
15141508 // and non-IETF forms, we simply choose vals to be any, and then type assert
15151509 // it later on. Since t cannot mutuate through this function we can guarantee that
@@ -1524,11 +1518,10 @@ func mapJSON(field reflect.Value, parentMod string, args jsonOutputConfig) (any,
15241518 default :
15251519 return nil , fmt .Errorf ("invalid JSON format specified: %v" , args .jType )
15261520 }
1527- for _ , kn := range mapKeys {
1528- k := mapKeyMap [kn ]
1529- goStruct , ok := field .MapIndex (k ).Interface ().(GoStruct )
1521+ for _ , pair := range pairs {
1522+ goStruct , ok := pair .v .Interface ().(GoStruct )
15301523 if ! ok {
1531- errs .Add (fmt .Errorf ("cannot map struct %v, invalid GoStruct" , field ))
1524+ errs .Add (fmt .Errorf ("cannot map struct %v, invalid GoStruct" , pair . v . Interface () ))
15321525 continue
15331526 }
15341527
@@ -1542,19 +1535,46 @@ func mapJSON(field reflect.Value, parentMod string, args jsonOutputConfig) (any,
15421535 case RFC7951 :
15431536 vals = append (vals .([]any ), val )
15441537 case Internal :
1545- vals .(map [string ]any )[kn ] = val
1538+ vals .(map [string ]any )[pair . k ] = val
15461539 default :
15471540 errs .Add (fmt .Errorf ("invalid JSON type: %v" , args .jType ))
15481541 continue
15491542 }
15501543 }
1551-
15521544 if errs .Err () != nil {
15531545 return nil , errs .Err ()
15541546 }
15551547 return vals , nil
15561548}
15571549
1550+ // mapJSON takes an input reflect.Value containing a map, and
1551+ // constructs the representation for JSON marshalling that corresponds to it.
1552+ // The module within which the map is defined is specified by the parentMod
1553+ // argument.
1554+ func mapJSON (field reflect.Value , parentMod string , args jsonOutputConfig ) (any , error ) {
1555+ var errs errlist.List
1556+ // Order of elements determines the order in which keys will be processed.
1557+ var pairs []mapValuePair
1558+
1559+ iter := field .MapRange ()
1560+ for iter .Next () {
1561+ kn , err := mapKeyToJSONString (iter .Key (), args )
1562+ if err != nil {
1563+ errs .Add (err )
1564+ continue
1565+ }
1566+ pairs = append (pairs , mapValuePair {k : kn , v : iter .Value ()})
1567+ }
1568+ slices .SortFunc (pairs , func (a , b mapValuePair ) bool { return a .k < b .k })
1569+
1570+ js , err := mapValuePairsToJSON (pairs , parentMod , args )
1571+ errs .Add (err )
1572+ if errs .Err () != nil {
1573+ return nil , errs .Err ()
1574+ }
1575+ return js , nil
1576+ }
1577+
15581578// jsonValue takes a reflect.Value which represents a struct field and
15591579// constructs the representation that can be used to marshal the field to JSON.
15601580// The module within which the value is defined is specified by the parentMod string,
@@ -1581,21 +1601,26 @@ func jsonValue(field reflect.Value, parentMod string, args jsonOutputConfig) (an
15811601 errs .Add (err )
15821602 }
15831603 case reflect .Ptr :
1584- if _ , ok := field .Interface ().(GoOrderedMap ); ok {
1585- // This is an ordered-map for YANG "ordered-by user" lists.
1586- valuesMethod , err := yreflect .MethodByName (field , "Values" )
1587- if err != nil {
1588- return nil , err
1589- }
1590- ret := valuesMethod .Call (nil )
1591- if got , wantReturnN := len (ret ), 1 ; got != wantReturnN {
1592- return nil , fmt .Errorf ("method Values() doesn't have expected number of return values, got %v, want %v" , got , wantReturnN )
1604+ if om , ok := field .Interface ().(GoOrderedMap ); ok {
1605+ var pairs []mapValuePair
1606+ if err := yreflect .RangeOrderedMap (om , func (k reflect.Value , v reflect.Value ) bool {
1607+ kn , err := mapKeyToJSONString (k , args )
1608+ if err != nil {
1609+ errs .Add (err )
1610+ return true
1611+ }
1612+ pairs = append (pairs , mapValuePair {k : kn , v : v })
1613+ return true
1614+ }); err != nil {
1615+ errs .Add (err )
15931616 }
1594- values := ret [0 ]
1595- if gotKind := values .Type ().Kind (); gotKind != reflect .Slice {
1596- return nil , fmt .Errorf ("method Values() did not return a slice value, got %v" , gotKind )
1617+
1618+ js , err := mapValuePairsToJSON (pairs , parentMod , args )
1619+ errs .Add (err )
1620+ if errs .Err () != nil {
1621+ return nil , errs .Err ()
15971622 }
1598- return jsonValue ( values , parentMod , args )
1623+ return js , nil
15991624 }
16001625
16011626 switch field .Elem ().Kind () {
0 commit comments