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  }