gitee.com/zhongguo168a/gocodes@v0.0.0-20230609140523-e1828349603f/datax/coderx/MapToByte.go (about) 1 package coderx 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "gitee.com/zhongguo168a/gocodes/datax" 7 "gitee.com/zhongguo168a/gocodes/datax/binaryx" 8 "gitee.com/zhongguo168a/gocodes/datax/convertx" 9 "gitee.com/zhongguo168a/gocodes/datax/listx" 10 "gitee.com/zhongguo168a/gocodes/datax/mapx" 11 "gitee.com/zhongguo168a/gocodes/datax/schemax" 12 "gitee.com/zhongguo168a/gocodes/datax/schemax/basickind" 13 "gitee.com/zhongguo168a/gocodes/myx/errorx" 14 "io" 15 "sort" 16 "strconv" 17 ) 18 19 func NewMapToByteWithType(_type string) (obj *MapToByte, err error) { 20 schema := schemax.GetDeclByKey(_type) 21 if schema == nil { 22 err = errorx.New("schema not found: ", datax.M{"_type": _type}) 23 return 24 } 25 obj = NewMapToByteWithSchema(schema.(*schemax.ClassDecl)) 26 return 27 } 28 29 func NewMapToByteWithSchema(schema *schemax.ClassDecl) (obj *MapToByte) { 30 obj = NewMapToByte() 31 obj.schema = schema 32 33 return 34 } 35 36 func NewMapToByte() (obj *MapToByte) { 37 obj = &MapToByte{} 38 obj.endian = binary.LittleEndian 39 return 40 } 41 42 type MapToByte struct { 43 schema *schemax.ClassDecl 44 45 ignoreAny bool 46 // 47 change bool 48 // 49 endian binary.ByteOrder 50 } 51 52 func (coder *MapToByte) Reset() { 53 coder.schema = nil 54 coder.ignoreAny = false 55 coder.endian = binary.LittleEndian 56 coder.change = false 57 } 58 59 func (coder *MapToByte) SetByteOrder(order binary.ByteOrder) *MapToByte { 60 coder.endian = order 61 return coder 62 } 63 64 // WithIgnoreAny 设置 IgnoreAny 后, 遇到 Any 类型的字段将被忽略,否则会返回错误 65 func (coder *MapToByte) WithIgnoreAny() *MapToByte { 66 coder.ignoreAny = true 67 return coder 68 } 69 70 func (coder *MapToByte) WithChange() *MapToByte { 71 coder.change = true 72 return coder 73 } 74 75 func (coder *MapToByte) Write(source map[string]interface{}, writer io.Writer) (err error) { 76 err = binaryx.WriteBool(writer, binary.BigEndian, coder.change) 77 err = coder.exportAllObj(source, writer, coder.schema) 78 if err != nil { 79 err = errorx.Wrap(err, coder.schema.Name) 80 return 81 } 82 return 83 } 84 85 // keyMode 0-source的字段, 1-所有字段 86 func (coder *MapToByte) exportAllObj(sourceMap map[string]interface{}, writer io.Writer, schema schemax.IDecl) (err error) { 87 var ( 88 decl = schema.(*schemax.ClassDecl) 89 ) 90 allfields := decl.GetAllField() 91 92 if coder.change { 93 l := &listx.List{} 94 for _, field := range allfields { 95 l.Push(field) 96 } 97 var newfields []*schemax.Field 98 group := l.GroupByCount(8) 99 for _, val := range group { 100 state := uint(0) 101 val.ForRange(func(index int, item interface{}) error { 102 field := item.(*schemax.Field) 103 fname := field.Name 104 _, mhas := sourceMap[fname] 105 if mhas { 106 state = binaryx.SetState(state, 1<<index, true) 107 newfields = append(newfields, field) 108 } 109 110 return nil 111 }) 112 err = binaryx.WriteUint8(writer, binary.BigEndian, uint8(state)) 113 } 114 115 allfields = newfields 116 } 117 118 for _, field := range allfields { 119 fname := field.Name 120 mval, mhas := sourceMap[fname] 121 switch ftyp := field.Type.(type) { 122 case *schemax.ClassType: 123 err = coder.exportAllClass(mhas, mval, writer, ftyp.Decl) 124 case *schemax.ArrayType: 125 err = coder.exportAllSlice(mhas, mval, writer, fname, ftyp) 126 case *schemax.MapType: 127 err = coder.exportAllMap(mhas, fname, mval, writer, ftyp) 128 case *schemax.EnumType: 129 err = coder.exportAllEnum(mval, writer, ftyp.Decl) 130 case *schemax.BasicType: 131 err = coder.exportAllBasic(mval, writer, ftyp.Kind) 132 case *schemax.AnyType: 133 if !coder.ignoreAny { 134 err = errorx.New("not support type any") 135 return 136 } 137 default: 138 } 139 if err != nil { 140 err = errorx.Wrap(err, fname) 141 return 142 } 143 } 144 return 145 } 146 147 func (coder *MapToByte) exportAllClass(has bool, many interface{}, writer io.Writer, decl string) (err error) { 148 var ( 149 isNil = false 150 mmap map[string]interface{} 151 isMap bool 152 ) 153 if !has { 154 isNil = true 155 } else { 156 if many == nil { 157 isNil = true 158 } else { 159 mmap, isMap = many.(map[string]interface{}) 160 if !isMap { 161 err = errorx.Wrap(err, fmt.Sprintf("map value is not map[string]interface{}")) 162 return 163 } 164 isNil = mmap == nil 165 } 166 } 167 168 err = binaryx.WriteBool(writer, binary.BigEndian, isNil) 169 if err != nil { 170 err = errorx.Wrap(err, fmt.Sprintf("write map nil")) 171 return 172 } 173 if isNil { 174 return 175 } 176 stdesc := schemax.GetDeclByKey(decl) 177 if stdesc == nil { 178 err = errorx.New("schema not found: ", datax.M{"decl": decl}) 179 return 180 } 181 182 err = coder.exportAllObj(many.(map[string]interface{}), writer, stdesc) 183 return 184 } 185 func (coder *MapToByte) exportAllEnum(mval interface{}, writer io.Writer, decl string) (err error) { 186 idesc := schemax.GetDeclByKey(decl) 187 if idesc == nil { 188 err = errorx.New("schema not found", datax.M{"decl": decl}) 189 return 190 } 191 192 enumdesc := idesc.(*schemax.EnumDecl) 193 err = coder.exportAllBasic(enumdesc.ConvertToValue(mval), writer, basickind.Kind(enumdesc.Kind)) 194 if err != nil { 195 return 196 } 197 return 198 } 199 200 func (coder *MapToByte) exportAllSlice(has bool, many interface{}, writer io.Writer, fname string, ftyp *schemax.ArrayType) (err error) { 201 202 if !has || many == nil { 203 err = binaryx.WriteInt16(writer, binary.BigEndian, int16(0)) 204 if err != nil { 205 err = errorx.Wrap(err, fmt.Sprintf("write array length zero")) 206 return 207 } 208 return 209 } 210 marr, ok := many.([]interface{}) 211 if !ok { 212 err = errorx.New("value is not []interface{}") 213 return 214 } 215 216 var mlen = len(marr) 217 err = binaryx.WriteInt16(writer, binary.BigEndian, int16(mlen)) 218 if err != nil { 219 err = errorx.Wrap(err, fmt.Sprintf("write array length")) 220 return 221 } 222 if mlen == 0 { 223 return 224 } 225 switch etyp := ftyp.Elem.(type) { 226 case *schemax.ClassType: 227 for i := 0; i < len(marr); i++ { 228 mval := marr[i] 229 err = coder.exportAllClass(has, mval, writer, etyp.Decl) 230 if err != nil { 231 err = errorx.Wrap(err, strconv.Itoa(i)) 232 return 233 } 234 } 235 case *schemax.BasicType: 236 for i := 0; i < len(marr); i++ { 237 err = coder.exportAllBasic(marr[i], writer, etyp.Kind) 238 if err != nil { 239 err = errorx.Wrap(err, strconv.Itoa(i)) 240 return 241 } 242 } 243 case *schemax.EnumType: 244 for i := 0; i < len(marr); i++ { 245 mval := marr[i] 246 err = coder.exportAllEnum(mval, writer, etyp.Decl) 247 if err != nil { 248 err = errorx.Wrap(err, strconv.Itoa(i)) 249 return 250 } 251 } 252 default: 253 err = errorx.New("decode array: not support type: " + etyp.String()) 254 return 255 256 } 257 258 return 259 } 260 261 func (coder *MapToByte) exportAllMap(has bool, fname string, many interface{}, writer io.Writer, ftyp *schemax.MapType) (err error) { 262 isNil := func() (x bool) { 263 return !has || many == nil 264 }() 265 err = binaryx.WriteBool(writer, binary.BigEndian, isNil) 266 267 if isNil { 268 return 269 } 270 mmap, ok := many.(map[string]interface{}) 271 if !ok { 272 err = errorx.New("value is not map[string]interface{}") 273 return 274 } 275 // 276 keys := mapx.Keys(mmap) 277 sort.Strings(keys) 278 279 err = binaryx.WriteInt16(writer, binary.BigEndian, int16(len(keys))) 280 if err != nil { 281 err = errorx.Wrap(err, fmt.Sprintf("write map length")) 282 return 283 } 284 285 for _, mkey := range keys { 286 mval := mmap[mkey] 287 err = binaryx.WriteUTF(writer, binary.BigEndian, mkey) 288 if err != nil { 289 err = errorx.Wrap(err, fmt.Sprintf("write map key %v", mkey)) 290 return 291 } 292 switch etyp := ftyp.Value.(type) { 293 case *schemax.ClassType: 294 mval, has := mmap[mkey] 295 err = coder.exportAllClass(has, mval, writer, etyp.Decl) 296 if err != nil { 297 err = errorx.Wrap(err, mkey) 298 return 299 } 300 case *schemax.BasicType: 301 err = coder.exportAllBasic(mval, writer, etyp.Kind) 302 if err != nil { 303 err = errorx.Wrap(err, mkey) 304 return 305 } 306 case *schemax.EnumType: 307 err = coder.exportAllEnum(mval, writer, etyp.Decl) 308 if err != nil { 309 err = errorx.Wrap(err, mkey) 310 return 311 } 312 default: 313 err = errorx.New("not support type: " + etyp.String()) 314 return 315 } 316 } 317 318 return 319 } 320 321 func (coder *MapToByte) exportAllBasic(mval interface{}, writer io.Writer, kind basickind.Kind) (err error) { 322 switch kind { 323 case basickind.Bool: 324 err = binaryx.WriteBool(writer, binary.BigEndian, convertx.AnyToBool(mval)) 325 case basickind.Int8: 326 err = binaryx.WriteInt8(writer, binary.BigEndian, int8(convertx.AnyToInt(mval))) 327 case basickind.Int16: 328 err = binaryx.WriteInt16(writer, binary.BigEndian, int16(convertx.AnyToInt(mval))) 329 case basickind.Int32: 330 err = binaryx.WriteInt32(writer, binary.BigEndian, int32(convertx.AnyToInt(mval))) 331 case basickind.Int64: 332 err = binaryx.WriteInt64(writer, binary.BigEndian, int64(convertx.AnyToInt(mval))) 333 case basickind.Uint8: 334 err = binaryx.WriteUint8(writer, binary.BigEndian, uint8(convertx.AnyToUint(mval))) 335 case basickind.Uint16: 336 err = binaryx.WriteUint16(writer, binary.BigEndian, uint16(convertx.AnyToUint(mval))) 337 case basickind.Uint32: 338 err = binaryx.WriteUint32(writer, binary.BigEndian, uint32(convertx.AnyToUint(mval))) 339 case basickind.Uint64: 340 err = binaryx.WriteUint64(writer, binary.BigEndian, uint64(convertx.AnyToUint(mval))) 341 case basickind.Float32: 342 err = binaryx.WriteFloat32(writer, binary.BigEndian, float32(convertx.AnyToFloat64(mval))) 343 case basickind.Float64: 344 err = binaryx.WriteFloat64(writer, binary.BigEndian, convertx.AnyToFloat64(mval)) 345 case basickind.String: 346 err = binaryx.WriteUTF(writer, binary.BigEndian, convertx.AnyToString(mval)) 347 } 348 if err != nil { 349 err = errorx.Wrap(err, "write binary", datax.M{"kind": kind}) 350 return 351 } 352 return 353 }