github.com/lxt1045/json@v0.0.0-20231013032136-54d6b1d6e525/marshal.go (about)

     1  // MIT License
     2  //
     3  // Copyright (c) 2021 Xiantu Li
     4  //
     5  // Permission is hereby granted, free of charge, to any person obtaining a copy
     6  // of this software and associated documentation files (the "Software"), to deal
     7  // in the Software without restriction, including without limitation the rights
     8  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     9  // copies of the Software, and to permit persons to whom the Software is
    10  // furnished to do so, subject to the following conditions:
    11  //
    12  // The above copyright notice and this permission notice shall be included in all
    13  // copies or substantial portions of the Software.
    14  //
    15  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    16  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    17  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    18  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    19  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    20  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    21  // SOFTWARE.
    22  
    23  package json
    24  
    25  import (
    26  	"encoding"
    27  	stdjson "encoding/json"
    28  	"fmt"
    29  	"reflect"
    30  	"strconv"
    31  	"strings"
    32  
    33  	lxterrs "github.com/lxt1045/errors"
    34  )
    35  
    36  /*
    37      fget 函数 list ,打入slice中,然后依次遍历slice,避免了遍历struct 的多个for循环!! greate!
    38      golang不支持尾递归,可能嵌套调用性能没有fget list 方式好
    39  */
    40  
    41  // bsGrow 在 slice marshal 的时候可以根据第一个的序列化结果计算出还需要的长度,如果 bs 不足则提前分配是比较好的选择
    42  func bsGrow(in []byte, lNeed int) (out []byte) {
    43  	lNew := bsPoolN
    44  	if lNew < lNeed+len(in) {
    45  		lNew += lNeed + len(in)
    46  	}
    47  	bsNew := make([]byte, 0, lNew)
    48  	out = append(bsNew, in...)
    49  	return
    50  }
    51  
    52  // 排列一个 fM list,优化掉多个 for 循环
    53  func marshalStruct(store Store, in []byte) (out []byte) {
    54  	out = append(in, '{')
    55  	for _, tag := range store.tag.ChildList {
    56  		out = append(out, tag.TagName...)
    57  		out = append(out, ':')
    58  
    59  		pObj := pointerOffset(store.obj, tag.Offset)
    60  		out = tag.fM(Store{obj: pObj, tag: tag}, out)
    61  
    62  		out = append(out, ',')
    63  	}
    64  	out[len(out)-1] = '}'
    65  	return
    66  }
    67  
    68  // marshalT 序列化明确的类型
    69  func marshalT(in []byte, store Store) (out []byte) {
    70  	out = in
    71  	panic(lxterrs.Errorf("error tag, fM is nil:%+v", store.tag))
    72  
    73  	return
    74  }
    75  
    76  // TODO: 根据一个 marshal 的 len 乘以 len(m) ,达到还需要的空间,如果不足则 New?
    77  func marshalSlice(bs []byte, store Store, l int) (out []byte) {
    78  	out = append(bs, '[')
    79  	if l <= 0 {
    80  		out = append(out, ']')
    81  		return
    82  	}
    83  	son := store.tag
    84  	size := son.TypeSize
    85  
    86  	lBefore := len(out)
    87  	out = son.fM(Store{obj: store.obj, tag: son}, out)
    88  	lObj := len(out) - lBefore + 1 + 16 // 16 随意取的值
    89  	// 解析还需要的空间
    90  	if lNeed := lObj * (l - 1); cap(out)-len(out) < lNeed {
    91  		out = bsGrow(out, lNeed)
    92  	}
    93  
    94  	for i := 1; i < l; i++ {
    95  		out = append(out, ',')
    96  		pSon := pointerOffset(store.obj, uintptr(i*size))
    97  		out = son.fM(Store{obj: pSon, tag: son}, out)
    98  	}
    99  	out = append(out, ']')
   100  	return
   101  }
   102  func marshalInterface(bs []byte, iface interface{}) (out []byte) {
   103  	if iface == nil {
   104  		out = append(bs, "null"...)
   105  		return
   106  	}
   107  	out = bs
   108  	switch v := iface.(type) {
   109  	case int8:
   110  		out = strconv.AppendInt(out, int64(v), 10)
   111  	case int16:
   112  		out = strconv.AppendInt(out, int64(v), 10)
   113  	case int32:
   114  		out = strconv.AppendInt(out, int64(v), 10)
   115  	case int64:
   116  		out = strconv.AppendInt(out, int64(v), 10)
   117  	case int:
   118  		out = strconv.AppendInt(out, int64(v), 10)
   119  	case uint8:
   120  		out = strconv.AppendUint(out, uint64(v), 10)
   121  	case uint16:
   122  		out = strconv.AppendUint(out, uint64(v), 10)
   123  	case uint32:
   124  		out = strconv.AppendUint(out, uint64(v), 10)
   125  	case uint64:
   126  		out = strconv.AppendUint(out, uint64(v), 10)
   127  	case uint:
   128  		out = strconv.AppendUint(out, uint64(v), 10)
   129  	case float32:
   130  		out = strconv.AppendFloat(out, float64(v), 'f', -1, 32)
   131  	case float64:
   132  		out = strconv.AppendFloat(out, v, 'f', -1, 64)
   133  	case string:
   134  		out = append(out, '"')
   135  		out = append(out, v...)
   136  		out = append(out, '"')
   137  	case stdjson.Number:
   138  		// TODO: 检查 numStr 的有效性?
   139  		out = append(out, v.String()...)
   140  	case map[string]interface{}:
   141  		out = marshalMapInterface(out, v)
   142  	case []interface{}:
   143  		out = append(out, '[')
   144  		for i, iface := range v {
   145  			if i != 0 {
   146  				out = append(out, ',')
   147  			}
   148  			marshalInterface(out, iface)
   149  		}
   150  		out = append(out, ']')
   151  	case []byte:
   152  		panic("TODO: []byte...")
   153  	default:
   154  		value := reflect.ValueOf(iface)
   155  		out = marshalValue(out, value)
   156  	}
   157  	return
   158  }
   159  
   160  // TODO: 根据一个 marshal 的 len 乘以 len(m) ,达到还需要的空间,如果不足则 New?
   161  func marshalMapInterface(bs []byte, m map[string]interface{}) (out []byte) {
   162  	out = bs
   163  	out = append(out, '{')
   164  	if len(m) == 0 {
   165  		out = append(out, '}')
   166  		return
   167  	}
   168  
   169  	first := true
   170  	for k, v := range m {
   171  		if first {
   172  			first = false
   173  			lBefore := len(out)
   174  			out = append(out, '"')
   175  			out = append(out, k...)
   176  			out = append(out, `":`...)
   177  			out = marshalInterface(out, v)
   178  			lObj := len(out) - lBefore + 1 + 16 // 16 随意取的值
   179  			if lNeed := lObj * (len(m) - 1); cap(out)-len(out) < lNeed {
   180  				out = bsGrow(out, lNeed)
   181  			}
   182  			continue
   183  		}
   184  		out = append(out, `,"`...)
   185  		out = append(out, k...)
   186  		out = append(out, `":`...)
   187  		out = marshalInterface(out, v)
   188  	}
   189  	out = append(out, '}')
   190  	return
   191  }
   192  
   193  func marshalValue(bs []byte, value reflect.Value) (out []byte) {
   194  	out = bs
   195  
   196  	// 针对指针
   197  	for value.Kind() == reflect.Ptr {
   198  		if value.IsNil() {
   199  			out = append(out, "null"...)
   200  			return
   201  		}
   202  		value = value.Elem()
   203  	}
   204  
   205  	switch value.Kind() {
   206  	case reflect.Interface:
   207  		if value.IsNil() {
   208  			out = append(out, "null"...)
   209  			return
   210  		}
   211  		// UnpackEface(&value)
   212  		// 从 iterface{} 里取出原始类型
   213  		value := reflect.ValueOf(value.Interface())
   214  		out = marshalValue(bs, value)
   215  		return
   216  	case reflect.Map:
   217  		if value.IsNil() {
   218  			out = append(out, "null"...)
   219  			return
   220  		}
   221  		iter := value.MapRange()
   222  		if iter == nil {
   223  			return
   224  		}
   225  		out = append(out, '{')
   226  		l := len(out)
   227  		for iter.Next() {
   228  			out = marshalKey(out, iter.Key())
   229  			out = append(out, ':')
   230  			out = marshalValue(out, iter.Value())
   231  			out = append(out, ',')
   232  		}
   233  		if l < len(out) {
   234  			out = out[:len(out)-1]
   235  		}
   236  		out = append(out, '}')
   237  		return
   238  	case reflect.Slice:
   239  		if value.IsNil() {
   240  			out = append(out, "[]"...)
   241  			return
   242  		}
   243  		out = append(out, '[')
   244  		lBefore := len(out)
   245  		v := value.Index(0)
   246  		out = marshalValue(out, v)
   247  		lObj := len(out) - lBefore + 1 + 16 // 16 随意取的值
   248  		// 解析还需要的空间
   249  		if lNeed := lObj * (value.Len() - 1); cap(out)-len(out) < lNeed {
   250  			out = bsGrow(out, lNeed)
   251  		}
   252  		for i := 1; i < value.Len(); i++ {
   253  			out = append(out, ',')
   254  			v := value.Index(i)
   255  			out = marshalValue(out, v)
   256  		}
   257  		out = append(out, ']')
   258  		return
   259  	case reflect.Struct:
   260  		prv := reflectValueToValue(&value)
   261  		goType := prv.typ
   262  
   263  		tag, err := LoadTagNode(value, goType.Hash)
   264  		if err != nil {
   265  			return
   266  		}
   267  
   268  		store := Store{
   269  			tag: tag,
   270  			obj: prv.ptr, // eface.Value,
   271  		}
   272  		out = marshalStruct(store, out)
   273  		return
   274  	case reflect.Bool:
   275  		if value.Bool() {
   276  			out = append(out, "true"...)
   277  		} else {
   278  			out = append(out, "false"...)
   279  		}
   280  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   281  		out = strconv.AppendUint(out, value.Uint(), 10)
   282  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   283  		out = strconv.AppendInt(out, value.Int(), 10)
   284  	case reflect.Float64:
   285  		out = strconv.AppendFloat(out, value.Float(), 'f', -1, 64)
   286  	case reflect.Float32:
   287  		out = strconv.AppendFloat(out, value.Float(), 'f', -1, 32)
   288  	case reflect.String:
   289  		if value.Type() == jsonNumberType {
   290  			numStr := value.String()
   291  			// TODO: 检查 numStr 的有效性?
   292  			out = append(out, numStr...)
   293  			return
   294  		}
   295  		out = append(out, '"')
   296  		// out = append(out, value.String()...) // TODO 需要转义: \ --> \\
   297  		str := value.String()
   298  		nQuote := strings.Count(str, "\"") // 只处理 " , \ 可以不处理
   299  		if nQuote == 0 {
   300  			out = append(out, str...) // TODO 需要转义: \ --> \\
   301  		} else {
   302  			for {
   303  				i := strings.IndexByte(str, '"')
   304  				if i == -1 {
   305  					out = append(out, str...)
   306  					break
   307  				}
   308  				out = append(out, str[:i]...)
   309  				out = append(out, '\\', '"')
   310  				str = str[i+1:]
   311  			}
   312  		}
   313  		out = append(out, '"')
   314  		return
   315  	default:
   316  		// out = append(out, "null"...)
   317  		panic(fmt.Sprintf("TODO: kind:%d...", value.Kind()))
   318  	}
   319  
   320  	return
   321  }
   322  
   323  var jsonNumberType = reflect.TypeOf(stdjson.Number(""))
   324  
   325  func marshalKey(in []byte, k reflect.Value) (out []byte) {
   326  	out = in
   327  	if k.Kind() == reflect.String {
   328  		// key = k.String()
   329  		out = append(out, '"')
   330  		// out = append(out, k.String()...) // TODO 需要转义: \ --> \\
   331  		str := k.String()
   332  		nQuote := strings.Count(str, "\"") // 只处理 " , \ 可以不处理
   333  		if nQuote == 0 {
   334  			out = append(out, str...) // TODO 需要转义: \ --> \\
   335  		} else {
   336  			for {
   337  				i := strings.IndexByte(str, '"')
   338  				if i == -1 {
   339  					out = append(out, str...)
   340  					break
   341  				}
   342  				out = append(out, str[:i]...)
   343  				out = append(out, '\\', '"')
   344  				str = str[i+1:]
   345  			}
   346  		}
   347  		out = append(out, '"')
   348  		return
   349  	}
   350  	if tm, ok := k.Interface().(encoding.TextMarshaler); ok {
   351  		if k.Kind() == reflect.Pointer && k.IsNil() {
   352  			return
   353  		}
   354  		bs, err := tm.MarshalText()
   355  		if err != nil {
   356  			err = lxterrs.Wrap(err, "MarshalText() got error")
   357  			panic(err)
   358  		}
   359  		// key = string(bs)
   360  		out = append(out, '"')
   361  		out = append(out, bs...)
   362  		out = append(out, '"')
   363  		return
   364  	}
   365  	switch k.Kind() {
   366  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   367  		// key = strconv.FormatInt(k.Int(), 10)
   368  		out = append(out, '"')
   369  		out = strconv.AppendInt(out, k.Int(), 10)
   370  		out = append(out, '"')
   371  		return
   372  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   373  		// key = strconv.FormatUint(k.Uint(), 10)
   374  		out = append(out, '"')
   375  		out = strconv.AppendUint(out, k.Uint(), 10)
   376  		out = append(out, '"')
   377  		return
   378  	}
   379  	err := lxterrs.New("unexpected map key type")
   380  	panic(err)
   381  }