@@ -2,10 +2,13 @@ package edgeos
22
33import (
44 "fmt"
5- "reflect "
5+ "sort "
66 "strings"
77)
88
9+ // ForceConsistentMapOrdering is used in tests to ensure consistent output
10+ var ForceConsistentMapOrdering = false
11+
912type InvalidMapValueTypeError struct {
1013 valueType string
1114}
@@ -22,57 +25,121 @@ type StringBuilder interface {
2225const indent = " "
2326
2427func ConfigFromMap (out StringBuilder , in map [string ]interface {}, depth int ) error {
25- indentDepth := strings .Repeat (indent , depth )
26- for k , v := range in {
27- if _ , err := out .WriteString (indentDepth ); err != nil {
28- return err
29- }
30- if _ , err := out .WriteString (k ); err != nil {
31- return err
32- }
33- if err := out .WriteByte (' ' ); err != nil {
34- return err
35- }
28+ keys := mapKeys (in )
29+ if ForceConsistentMapOrdering {
30+ sort .Strings (keys )
31+ }
32+
33+ indentString := strings .Repeat (indent , depth )
34+ for _ , k := range keys {
35+ v := in [k ]
3636 switch t := v .(type ) {
37- case string :
38- if strings .Contains (t , " " ) {
39- if err := out .WriteByte ('"' ); err != nil {
37+ case []interface {}:
38+ for _ , item := range t {
39+ s , err := primitiveToString (item )
40+ if err != nil {
4041 return err
4142 }
42- if _ , err := out . WriteString ( t ); err != nil {
43+ if err := writeKV ( out , k , s , indentString ); err != nil {
4344 return err
4445 }
45- if err := out .WriteByte ('"' ); err != nil {
46- return err
47- }
48- } else {
49- if _ , err := out .WriteString (t ); err != nil {
46+ }
47+ case []string :
48+ for _ , item := range t {
49+ if err := writeKV (out , k , item , indentString ); err != nil {
5050 return err
5151 }
5252 }
53- if err := out .WriteByte ('\n' ); err != nil {
53+ case map [string ]interface {}:
54+ if _ , err := out .WriteString (indentString ); err != nil {
5455 return err
5556 }
56- case map [string ]interface {}:
57- if _ , err := out .WriteString ("{\n " ); err != nil {
57+ if _ , err := out .WriteString (k ); err != nil {
58+ return err
59+ }
60+ if _ , err := out .WriteString (" {\n " ); err != nil {
5861 return err
5962 }
6063
6164 if err := ConfigFromMap (out , t , depth + 1 ); err != nil {
6265 return err
6366 }
6467
65- if _ , err := out .WriteString (indentDepth ); err != nil {
68+ if _ , err := out .WriteString (indentString ); err != nil {
6669 return err
6770 }
6871 if _ , err := out .WriteString ("}\n " ); err != nil {
6972 return err
7073 }
74+ case bool :
75+ if ! t {
76+ continue
77+ }
78+ if _ , err := out .WriteString (indent ); err != nil {
79+ return err
80+ }
81+ if _ , err := out .WriteString (k ); err != nil {
82+ return err
83+ }
84+ if err := out .WriteByte ('\n' ); err != nil {
85+ return err
86+ }
7187 default :
72- return InvalidMapValueTypeError {
73- valueType : reflect .TypeOf (v ).Name (),
88+ s , err := primitiveToString (t )
89+ if err != nil {
90+ return err
91+ }
92+ if err := writeKV (out , k , s , indentString ); err != nil {
93+ return err
7494 }
7595 }
7696 }
7797 return nil
7898}
99+
100+ func writeKV (out StringBuilder , k , v string , indent string ) error {
101+ quoted := strings .Contains (v , " " )
102+ if _ , err := out .WriteString (indent ); err != nil {
103+ return err
104+ }
105+ if _ , err := out .WriteString (k ); err != nil {
106+ return err
107+ }
108+ if err := out .WriteByte (' ' ); err != nil {
109+ return err
110+ }
111+ if quoted {
112+ if err := out .WriteByte ('"' ); err != nil {
113+ return err
114+ }
115+ }
116+ if _ , err := out .WriteString (v ); err != nil {
117+ return err
118+ }
119+ if quoted {
120+ if err := out .WriteByte ('"' ); err != nil {
121+ return err
122+ }
123+ }
124+ return out .WriteByte ('\n' )
125+ }
126+
127+ func primitiveToString (in interface {}) (string , error ) {
128+ switch t := in .(type ) {
129+ case string :
130+ return t , nil
131+ case uint , int , uint32 , int32 , uint64 , int64 , float32 , float64 :
132+ return fmt .Sprintf ("%d" , t ), nil
133+ }
134+ return "" , & InvalidMapValueTypeError {
135+ valueType : fmt .Sprintf ("%T" , in ),
136+ }
137+ }
138+
139+ func mapKeys [T any ](in map [string ]T ) []string {
140+ out := make ([]string , 0 , len (in ))
141+ for key := range in {
142+ out = append (out , key )
143+ }
144+ return out
145+ }
0 commit comments