@@ -2,8 +2,8 @@ package stores
22
33import (
44 "fmt"
5- "reflect "
6- "slices "
5+ "math "
6+ "sort "
77 "strconv"
88 "strings"
99
@@ -69,98 +69,131 @@ func tokenize(path string) []token {
6969 return tokens
7070}
7171
72- func descendMap (branch sops.TreeBranch , key string ) (sops.TreeBranch , reflect.Value ) {
73- for idx , elt := range branch {
74- if elt .Key == key {
75- return branch , reflect .ValueOf (& branch [idx ].Value )
72+ type node struct {
73+ value * interface {}
74+ subkeys map [string ]* node
75+ indices map [int ]* node
76+ }
77+
78+ func place (value * interface {}, path []token , root * node ) error {
79+ for _ , token := range path {
80+ var next * node
81+ var ok bool
82+ switch t := token .(type ) {
83+ case mapToken :
84+ if root .subkeys == nil {
85+ root .subkeys = make (map [string ]* node )
86+ }
87+ next , ok = root .subkeys [t .key ]
88+ if ! ok {
89+ next = & node {}
90+ root .subkeys [t .key ] = next
91+ }
92+ case listToken :
93+ if root .indices == nil {
94+ root .indices = make (map [int ]* node )
95+ }
96+ next , ok = root .indices [t .position ]
97+ if ! ok {
98+ next = & node {}
99+ root .indices [t .position ] = next
100+ }
76101 }
102+ root = next
77103 }
78- newBranch := append ( branch , sops. TreeItem {
79- Key : key ,
80- Value : nil ,
81- })
82- return newBranch , reflect . ValueOf ( & newBranch [ len ( newBranch ) - 1 ]. Value )
104+ if root . value != nil {
105+ return fmt . Errorf ( "Duplicate value" )
106+ }
107+ root . value = value
108+ return nil
83109}
84110
85- func descendList (array []interface {}, index int ) ([]interface {}, reflect.Value ) {
86- if index >= len (array ) {
87- if index >= cap (array ) {
88- array = slices .Grow (array , index + 1 - cap (array ))
89- }
90- array = array [:index + 1 ]
111+ func b2i (value bool ) int {
112+ if value {
113+ return 1
91114 }
92- return array , reflect . ValueOf ( & array [ index ])
115+ return 0
93116}
94117
95- func descend (value reflect.Value , t token ) (reflect.Value , error ) {
96- interfaceType := reflect .TypeOf ((* interface {})(nil ))
97- switch currToken := t .(type ) {
98- case mapToken :
99- // This special case is only needed for the root
100- treeBranchPtrType := reflect .TypeOf ((* sops .TreeBranch )(nil ))
101- if value .Type () == treeBranchPtrType {
102- v := * value .Interface ().(* sops.TreeBranch )
103- v , nextVal := descendMap (v , currToken .key )
104- reflect .Indirect (value ).Set (reflect .ValueOf (v ))
105- return nextVal , nil
118+ func convert (root * node ) (interface {}, error ) {
119+ hasValue := root .value != nil
120+ hasSubkey := len (root .subkeys ) > 0
121+ hasIndex := len (root .indices ) > 0
122+ if b2i (hasValue )+ b2i (hasSubkey )+ b2i (hasIndex ) > 1 {
123+ return nil , fmt .Errorf ("Type mismatch" )
124+ }
125+ if hasValue {
126+ return * root .value , nil
127+ }
128+ if hasSubkey {
129+ keys := make ([]string , len (root .subkeys ))
130+ index := 0
131+ for k := range root .subkeys {
132+ keys [index ] = k
133+ index += 1
106134 }
107- if value . Type () == interfaceType {
108- val := reflect . Indirect ( value )
109- if val . IsNil () {
110- v , nextVal := descendMap ( nil , currToken . key )
111- val . Set ( reflect . ValueOf ( v ))
112- return nextVal , nil
135+ sort . Strings ( keys )
136+ result := make (sops. TreeBranch , len ( keys ) )
137+ for index , key := range keys {
138+ value , err := convert ( root . subkeys [ key ] )
139+ if err != nil {
140+ return nil , err
113141 }
114- if v , ok := val .Interface ().(sops.TreeBranch ); ok {
115- v , nextVal := descendMap (v , currToken .key )
116- val .Set (reflect .ValueOf (v ))
117- return nextVal , nil
142+ result [index ] = sops.TreeItem {
143+ Key : key ,
144+ Value : value ,
118145 }
119146 }
120- return reflect.Value {}, fmt .Errorf ("Type mismatch: can only use string key for map" )
121- case listToken :
122- if value .Type () == interfaceType {
123- val := reflect .Indirect (value )
124- if val .IsNil () {
125- v , nextVal := descendList (nil , currToken .position )
126- val .Set (reflect .ValueOf (v ))
127- return nextVal , nil
128- }
129- if v , ok := val .Interface ().([]interface {}); ok {
130- v , nextVal := descendList (v , currToken .position )
131- val .Set (reflect .ValueOf (v ))
132- return nextVal , nil
133- }
147+ return result , nil
148+ }
149+ minValue := math .MaxInt
150+ maxValue := math .MinInt
151+ for k := range root .indices {
152+ if k < minValue {
153+ minValue = k
154+ }
155+ if k > maxValue {
156+ maxValue = k
157+ }
158+ }
159+ if minValue != 0 || maxValue + 1 != len (root .indices ) {
160+ return nil , fmt .Errorf ("Incomplete list" )
161+ }
162+ result := make ([]interface {}, maxValue + 1 )
163+ for k , v := range root .indices {
164+ value , err := convert (v )
165+ if err != nil {
166+ return nil , err
134167 }
135- return reflect.Value {}, fmt .Errorf ("Type mismatch: can only use integer key for list" )
136- default :
137- return reflect.Value {}, fmt .Errorf ("Internal error: unknown token %q" , t )
168+ result [k ] = value
138169 }
170+ return result , nil
139171}
140172
141173func unflattenTreeBranch (branch sops.TreeBranch ) (sops.TreeBranch , error ) {
142- var result sops. TreeBranch
174+ root := & node {}
143175 for _ , item := range branch {
144176 if _ , ok := item .Key .(sops.Comment ); ok {
145177 continue
146178 }
147179 if key , ok := item .Key .(string ); ok {
148- current := reflect .ValueOf (& result )
149180 tokens := tokenize (key )
150- for _ , token := range tokens {
151- var err error
152- current , err = descend (current , token )
153- if err != nil {
154- return nil , fmt .Errorf ("Error while unflattening %q: %w" , key , err )
155- }
181+ err := place (& item .Value , tokens , root )
182+ if err != nil {
183+ return nil , fmt .Errorf ("Error while unflattening %q: %w" , key , err )
156184 }
157- reflect .Indirect (current ).Set (reflect .ValueOf (item .Value ))
158- continue
159185 } else {
160186 return nil , fmt .Errorf ("Found non-string key %q when unflattening" , item .Key )
161187 }
162188 }
163- return result , nil
189+ result , err := convert (root )
190+ if err != nil {
191+ return nil , fmt .Errorf ("Error while unflattening: %w" , err )
192+ }
193+ if tb , ok := result .(sops.TreeBranch ); ok {
194+ return tb , nil
195+ }
196+ return nil , fmt .Errorf ("Internal error: cannot find root" )
164197}
165198
166199////////////////////////////////////////////////////////////////////////////////////////////////////////////////
0 commit comments