github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/utils/mxjson/structs.go (about) 1 package mxjson 2 3 import ( 4 "errors" 5 "fmt" 6 ) 7 8 // parser state 9 10 type parserState int 11 12 const ( 13 stateBeginKey parserState = 0 + iota 14 stateEndKey 15 stateBeginVal 16 stateEndVal 17 stateExpectNext 18 ) 19 20 type objectType int 21 22 const ( 23 objUndefined objectType = 0 + iota 24 objBoolean 25 objNumber 26 objString 27 objArrayUndefined 28 objArrayBoolean 29 objArrayNumber 30 objArrayString 31 objArrayArray 32 objArrayMap 33 objMap 34 ) 35 36 // quote pairs 37 38 type quote struct { 39 open bool 40 pos int 41 } 42 43 func (q *quote) IsOpen() bool { 44 return q.open 45 } 46 47 func (q *quote) Open(pos int) { 48 q.open = true 49 q.pos = pos 50 } 51 52 func (q *quote) Close() { 53 q.open = false 54 } 55 56 // bracket pairs 57 58 type pair struct { 59 pos []int 60 len int 61 } 62 63 func newPair() *pair { 64 p := new(pair) 65 p.pos = make([]int, 100) 66 return p 67 } 68 69 func (p *pair) IsOpen() bool { 70 return p.len != 0 71 } 72 73 func (p *pair) Open(pos int) { 74 if len(p.pos) == p.len { 75 p.pos = append(p.pos, pos) 76 } else { 77 p.pos[p.len] = pos 78 } 79 p.len++ 80 } 81 82 func (p *pair) Close() error { 83 if p.len == 0 { 84 return errors.New("close found with no open") 85 } 86 p.len-- 87 return nil 88 } 89 90 // lazy string 91 92 type str struct { 93 b []byte 94 len int 95 } 96 97 func newStr() *str { 98 s := new(str) 99 s.b = make([]byte, 1024*1024) 100 return s 101 } 102 103 func (s *str) Append(b byte) { 104 if len(s.b) == s.len { 105 s.b = append(s.b, b) 106 } else { 107 s.b[s.len] = b 108 } 109 s.len++ 110 } 111 112 func (s *str) Get() []byte { 113 if s.len == 0 { 114 return nil 115 } 116 117 b := s.b[:s.len] 118 s.len = 0 119 return b 120 } 121 122 func (s *str) String() string { 123 if s.len == 0 { 124 return "" 125 } 126 127 b := s.b[:s.len] 128 s.len = 0 129 return string(b) 130 } 131 132 // object type 133 134 type nestedObject struct { 135 nest []item 136 len int 137 } 138 type item struct { 139 key *str 140 value interface{} 141 objType objectType 142 } 143 144 func newObjs() (no nestedObject) { 145 no.nest = make([]item, 10) 146 for i := range no.nest { 147 no.nest[i].key = newStr() 148 } 149 no.len = -1 150 return 151 } 152 153 func (no *nestedObject) New(objType objectType) { 154 no.len++ 155 156 var v interface{} 157 switch objType { 158 case objUndefined: 159 panic("Undef object type - We should know what the data type is by now!") 160 161 case objBoolean: 162 v = false 163 164 case objNumber: 165 v = float64(0) 166 167 case objString: 168 v = "" 169 170 case objArrayUndefined: 171 //panic("Undef array - We should know what the array is by now!") 172 v = []interface{}{} 173 174 case objArrayBoolean: 175 v = []bool{} 176 177 case objArrayNumber: 178 v = []float64{} 179 180 case objArrayString: 181 v = []string{} 182 183 case objArrayArray: 184 v = [][]interface{}{} 185 186 case objArrayMap: 187 v = []interface{}{} 188 189 case objMap: 190 v = make(map[string]interface{}) 191 192 default: 193 panic("This condition shouldn't arise!") 194 } 195 196 if len(no.nest) == no.len { 197 no.nest = append(no.nest, item{ 198 key: newStr(), 199 objType: objType, 200 value: v, 201 }) 202 } else { 203 no.nest[no.len].objType = objType 204 no.nest[no.len].value = v 205 } 206 } 207 208 func (no *nestedObject) GetKeyPtr() *str { 209 return no.nest[no.len].key 210 } 211 212 func (no *nestedObject) GetObjType() objectType { 213 if no.len < 0 || len(no.nest) == 0 || no.len > len(no.nest) { 214 return objUndefined 215 } 216 return no.nest[no.len].objType 217 } 218 219 func (no *nestedObject) SetObjType(objType objectType) { 220 no.nest[no.len].objType = objType 221 } 222 223 func (no *nestedObject) SetValue(value interface{}) error { 224 if no.len < 0 { 225 return fmt.Errorf("unable to marshal '%v' into parent structure. This might be due to the an incorrect file", value) 226 } 227 228 switch no.nest[no.len].objType { 229 case objUndefined: 230 return fmt.Errorf("undef object type. We should know what the data type is by now. Please file a bug at https://github.com/lmorg/murex/issues") 231 232 case objBoolean: 233 no.nest[no.len].value = value.(bool) 234 235 case objNumber: 236 no.nest[no.len].value = value.(float64) 237 238 case objString: 239 no.nest[no.len].value = value.(string) 240 241 case objArrayUndefined: 242 //panic("Undef array - We should know what the array is by now!") 243 no.nest[no.len].value = append(no.nest[no.len].value.([]interface{}), value) 244 245 case objArrayBoolean: 246 no.nest[no.len].value = append(no.nest[no.len].value.([]bool), value.(bool)) 247 248 case objArrayNumber: 249 no.nest[no.len].value = append(no.nest[no.len].value.([]float64), value.(float64)) 250 251 case objArrayString: 252 no.nest[no.len].value = append(no.nest[no.len].value.([]string), value.(string)) 253 254 case objArrayArray: 255 no.nest[no.len].value = append(no.nest[no.len].value.([][]interface{}), value.([]interface{})) 256 257 case objArrayMap: 258 no.nest[no.len].value = append(no.nest[no.len].value.([]interface{}), value) 259 260 case objMap: 261 no.nest[no.len].value.(map[string]interface{})[no.nest[no.len].key.String()] = value 262 263 default: 264 return fmt.Errorf("switch statement unexpectedly failed. This condition shouldn't arise, so please file a bug at https://github.com/lmorg/murex/issues") 265 } 266 267 return nil 268 } 269 270 func (no *nestedObject) MergeDown() { 271 switch no.len { 272 case -1: 273 panic("This condition shouldn't arise!") 274 275 case 0: 276 no.len-- 277 278 default: 279 no.len-- 280 no.SetValue(no.nest[no.len+1].value) 281 } 282 }