diff --git a/api.go b/api.go index 406715eca..986e7aa05 100644 --- a/api.go +++ b/api.go @@ -94,6 +94,13 @@ type Config struct { // Encode Infinity or Nan float into `null`, instead of returning an error. EncodeNullForInfOrNan bool + + // Uint64 or Int64 into strings on Marshal + Uint64ToString bool + Int64ToString bool + // IntegerExceed53BitToString when intSize == 64, if the value of type integer exceeds 1<<53, + // automatically convert it to a string. + IntegerExceed53BitToString bool } var ( diff --git a/encode_test.go b/encode_test.go index f97244a2c..2cb1ae10f 100644 --- a/encode_test.go +++ b/encode_test.go @@ -1224,4 +1224,395 @@ func TestMarshalInfOrNan(t *testing.T) { assert.NotNil(t, err) assert.True(t, strings.Contains(err.Error(), "json: unsupported value: NaN or ±Infinite")) } +} + +func TestIntegerToString(t *testing.T) { + int64ptr := int64(1) + intptr := int(1) + uintPtr := uint(1) + + uint64Lptr := uint64(9007199254740991) + uint64Eptr := uint64(9007199254740992) + uint64Gptr := uint64(9007199254740993) + uintLptr := uint(9007199254740991) + uintEptr := uint(9007199254740992) + uintGptr := uint(9007199254740993) + + int64Lptr := int64(-9007199254740991) + int64Eptr := int64(-9007199254740992) + int64Gptr := int64(-9007199254740993) + intLptr := int(-9007199254740991) + intEptr := int(-9007199254740992) + intGptr := int(-9007199254740993) + cases := []struct { + name string + val interface{} + exceptUint64ToStr string + exceptInt64ToStr string + exceptExceedToStr string + exceptFalse string + }{ + { + name: "normal_map", + val: map[string]interface{}{ + "int": int(12), + "uint": uint(99), + "int64": int64(34), + "uint64": uint64(56), + "exceedUint": uint(9007199254740993), + "exceedUint64": uint64(9007199254740993), + "eqMaxUint64": uint64(9007199254740992), + "eqMaxUint": uint(9007199254740992), + "lsMaxUint64": uint64(9007199254740991), + "lsMaxUint": uint(9007199254740991), + }, + exceptUint64ToStr: `{"eqMaxUint":9007199254740992,"eqMaxUint64":"9007199254740992",`+ + `"exceedUint":9007199254740993,"exceedUint64":"9007199254740993",`+ + `"int":12,"int64":34,`+ + `"lsMaxUint":9007199254740991,"lsMaxUint64":"9007199254740991",`+ + `"uint":99,"uint64":"56"}`, + exceptInt64ToStr: `{"eqMaxUint":9007199254740992,"eqMaxUint64":9007199254740992,`+ + `"exceedUint":9007199254740993,"exceedUint64":9007199254740993,`+ + `"int":12,"int64":"34",`+ + `"lsMaxUint":9007199254740991,"lsMaxUint64":9007199254740991,`+ + `"uint":99,"uint64":56}`, + exceptExceedToStr: `{"eqMaxUint":9007199254740992,"eqMaxUint64":9007199254740992,`+ + `"exceedUint":"9007199254740993","exceedUint64":"9007199254740993",`+ + `"int":12,"int64":34,`+ + `"lsMaxUint":9007199254740991,"lsMaxUint64":9007199254740991,`+ + `"uint":99,"uint64":56}`, + exceptFalse: `{"eqMaxUint":9007199254740992,"eqMaxUint64":9007199254740992,`+ + `"exceedUint":9007199254740993,"exceedUint64":9007199254740993,`+ + `"int":12,"int64":34,`+ + `"lsMaxUint":9007199254740991,"lsMaxUint64":9007199254740991,`+ + `"uint":99,"uint64":56}`, + }, + { + name: "normal_map_minus", + val: map[string]interface{}{ + "int": int(12), + "int64": int64(34), + "exceedInt": int(-9007199254740993), + "exceedInt64": int64(-9007199254740993), + "eqMaxInt": int(-9007199254740992), + "eqMaxInt64": int64(-9007199254740992), + "lsMaxInt64": int64(-9007199254740991), + "lsMaxInt": int(-9007199254740991), + }, + exceptUint64ToStr: `{"eqMaxInt":-9007199254740992,"eqMaxInt64":-9007199254740992,`+ + `"exceedInt":-9007199254740993,"exceedInt64":-9007199254740993,`+ + `"int":12,"int64":34,`+ + `"lsMaxInt":-9007199254740991,"lsMaxInt64":-9007199254740991}`, + exceptInt64ToStr: `{"eqMaxInt":-9007199254740992,"eqMaxInt64":"-9007199254740992",`+ + `"exceedInt":-9007199254740993,"exceedInt64":"-9007199254740993",`+ + `"int":12,"int64":"34",`+ + `"lsMaxInt":-9007199254740991,"lsMaxInt64":"-9007199254740991"}`, + exceptExceedToStr: `{"eqMaxInt":-9007199254740992,"eqMaxInt64":-9007199254740992,`+ + `"exceedInt":"-9007199254740993","exceedInt64":"-9007199254740993",`+ + `"int":12,"int64":34,`+ + `"lsMaxInt":-9007199254740991,"lsMaxInt64":-9007199254740991}`, + exceptFalse: `{"eqMaxInt":-9007199254740992,"eqMaxInt64":-9007199254740992,`+ + `"exceedInt":-9007199254740993,"exceedInt64":-9007199254740993,`+ + `"int":12,"int64":34,`+ + `"lsMaxInt":-9007199254740991,"lsMaxInt64":-9007199254740991}`, + }, + { + name: "int64_key_map", + val: map[int64]interface{}{ + int64(1): 1, + int64(2): 2, + int64(3): 3, + int64(4): 4, + }, + exceptUint64ToStr: `{"1":1,"2":2,"3":3,"4":4}`, + exceptInt64ToStr: `{"1":1,"2":2,"3":3,"4":4}`, + exceptExceedToStr: `{"1":1,"2":2,"3":3,"4":4}`, + exceptFalse: `{"1":1,"2":2,"3":3,"4":4}`, + }, + { + name: "minus_int64_key_map", + val: map[int64]interface{}{ + int64(-9007199254740991): 1, + int64(-9007199254740992): 2, + int64(-9007199254740993): 3, + }, + exceptUint64ToStr: `{"-9007199254740991":1,"-9007199254740992":2,"-9007199254740993":3}`, + exceptInt64ToStr: `{"-9007199254740991":1,"-9007199254740992":2,"-9007199254740993":3}`, + exceptExceedToStr: `{"-9007199254740991":1,"-9007199254740992":2,"-9007199254740993":3}`, + exceptFalse: `{"-9007199254740991":1,"-9007199254740992":2,"-9007199254740993":3}`, + }, + { + name: "uint64_key_map", + val: map[uint64]interface{}{ + uint64(12): 1, + uint64(99): 1, + uint64(34): 1, + uint64(9007199254740991): 1, + uint64(9007199254740992): 1, + uint64(9007199254740993): 1, + }, + exceptUint64ToStr: `{"12":1,"34":1,"9007199254740991":1,"9007199254740992":1,"9007199254740993":1,"99":1}`, + exceptInt64ToStr: `{"12":1,"34":1,"9007199254740991":1,"9007199254740992":1,"9007199254740993":1,"99":1}`, + exceptExceedToStr: `{"12":1,"34":1,"9007199254740991":1,"9007199254740992":1,"9007199254740993":1,"99":1}`, + exceptFalse: `{"12":1,"34":1,"9007199254740991":1,"9007199254740992":1,"9007199254740993":1,"99":1}`, + }, + { + name: "uint_key_map", + val: map[uint]interface{}{ + uint(12): int(12), + uint(99): uint(99), + uint(34): int64(34), + uint(56): uint64(56), + uint(9007199254740991): uint64(10), + uint(9007199254740992): uint64(10), + uint(9007199254740993): uint64(10), + }, + exceptUint64ToStr: `{"12":12,"34":34,"56":"56","9007199254740991":"10","9007199254740992":"10","9007199254740993":"10","99":99}`, + exceptInt64ToStr: `{"12":12,"34":"34","56":56,"9007199254740991":10,"9007199254740992":10,"9007199254740993":10,"99":99}`, + exceptExceedToStr: `{"12":12,"34":34,"56":56,"9007199254740991":10,"9007199254740992":10,"9007199254740993":10,"99":99}`, + exceptFalse: `{"12":12,"34":34,"56":56,"9007199254740991":10,"9007199254740992":10,"9007199254740993":10,"99":99}`, + }, + { + name: "normal_struct", + val: struct { + Int int `json:"int"` + Int64 int64 `json:"int64"` + Uint uint `json:"uint"` + UintL uint `json:"uintl"` + UintE uint `json:"uinte"` + UintG uint `json:"uintg"` + Uint64 uint64 `json:"uint64"` + Uint64L uint64 `json:"uint64l"` + Uint64E uint64 `json:"uint64e"` + Uint64G uint64 `json:"uint64g"` + }{ + Int: int(1), + Int64: int64(2), + Uint: uint(1), + UintL: uint(9007199254740991), + UintE: uint(9007199254740992), + UintG: uint(9007199254740993), + Uint64: uint64(1), + Uint64L: uint64(9007199254740991), + Uint64E: uint64(9007199254740992), + Uint64G: uint64(9007199254740993), + }, + exceptUint64ToStr: `{"int":1,"int64":2,`+ + `"uint":1,"uintl":9007199254740991,"uinte":9007199254740992,"uintg":9007199254740993,`+ + `"uint64":"1","uint64l":"9007199254740991","uint64e":"9007199254740992","uint64g":"9007199254740993"}`, + exceptInt64ToStr: `{"int":1,"int64":"2",`+ + `"uint":1,"uintl":9007199254740991,"uinte":9007199254740992,"uintg":9007199254740993,`+ + `"uint64":1,"uint64l":9007199254740991,"uint64e":9007199254740992,"uint64g":9007199254740993}`, + exceptExceedToStr: `{"int":1,"int64":2,`+ + `"uint":1,"uintl":9007199254740991,"uinte":9007199254740992,"uintg":"9007199254740993",`+ + `"uint64":1,"uint64l":9007199254740991,"uint64e":9007199254740992,"uint64g":"9007199254740993"}`, + exceptFalse: `{"int":1,"int64":2,`+ + `"uint":1,"uintl":9007199254740991,"uinte":9007199254740992,"uintg":9007199254740993,`+ + `"uint64":1,"uint64l":9007199254740991,"uint64e":9007199254740992,"uint64g":9007199254740993}`, + }, + { + name: "minus_struct", + val: struct { + Int int `json:"int"` + IntL int `json:"intl"` + IntE int `json:"inte"` + IntG int `json:"intg"` + Int64 int64 `json:"int64"` + Int64L int64 `json:"int64l"` + Int64E int64 `json:"int64e"` + Int64G int64 `json:"int64g"` + }{ + Int: 10, + IntL: int(-9007199254740991), + IntE: int(-9007199254740992), + IntG: int(-9007199254740993), + Int64: int64(1), + Int64L: int64(-9007199254740991), + Int64E: int64(-9007199254740992), + Int64G: int64(-9007199254740993), + }, + exceptUint64ToStr: `{"int":10,"intl":-9007199254740991,"inte":-9007199254740992,"intg":-9007199254740993,`+ + `"int64":1,"int64l":-9007199254740991,"int64e":-9007199254740992,"int64g":-9007199254740993}`, + exceptInt64ToStr: `{"int":10,"intl":-9007199254740991,"inte":-9007199254740992,"intg":-9007199254740993,`+ + `"int64":"1","int64l":"-9007199254740991","int64e":"-9007199254740992","int64g":"-9007199254740993"}`, + exceptExceedToStr: `{"int":10,"intl":-9007199254740991,"inte":-9007199254740992,"intg":"-9007199254740993",`+ + `"int64":1,"int64l":-9007199254740991,"int64e":-9007199254740992,"int64g":"-9007199254740993"}`, + exceptFalse: `{"int":10,"intl":-9007199254740991,"inte":-9007199254740992,"intg":-9007199254740993,`+ + `"int64":1,"int64l":-9007199254740991,"int64e":-9007199254740992,"int64g":-9007199254740993}`, + }, + { + name: "normal_slice", + val: []interface{}{ + int(12), uint(99), int64(34), uint64(56), uint(9007199254740991), uint(9007199254740992), uint(9007199254740993), + uint64(9007199254740991), uint64(9007199254740992), uint64(9007199254740993), + }, + exceptUint64ToStr: `[12,99,34,"56",`+ + `9007199254740991,9007199254740992,9007199254740993,`+ + `"9007199254740991","9007199254740992","9007199254740993"]`, + exceptInt64ToStr: `[12,99,"34",56,`+ + `9007199254740991,9007199254740992,9007199254740993,`+ + `9007199254740991,9007199254740992,9007199254740993]`, + exceptExceedToStr: `[12,99,34,56,`+ + `9007199254740991,9007199254740992,"9007199254740993",`+ + `9007199254740991,9007199254740992,"9007199254740993"]`, + exceptFalse: `[12,99,34,56,`+ + `9007199254740991,9007199254740992,9007199254740993,`+ + `9007199254740991,9007199254740992,9007199254740993]`, + }, + { + name: "minus_normal_slice", + val: []interface{}{ + int(12), int64(99), + int(-9007199254740991), int(-9007199254740992), int(-9007199254740993), + int64(-9007199254740991), int64(-9007199254740992), int64(-9007199254740993), + }, + exceptUint64ToStr: `[12,99,`+ + `-9007199254740991,-9007199254740992,-9007199254740993,`+ + `-9007199254740991,-9007199254740992,-9007199254740993]`, + exceptInt64ToStr: `[12,"99",`+ + `-9007199254740991,-9007199254740992,-9007199254740993,`+ + `"-9007199254740991","-9007199254740992","-9007199254740993"]`, + exceptExceedToStr: `[12,99,`+ + `-9007199254740991,-9007199254740992,"-9007199254740993",`+ + `-9007199254740991,-9007199254740992,"-9007199254740993"]`, + exceptFalse: `[12,99,`+ + `-9007199254740991,-9007199254740992,-9007199254740993,`+ + `-9007199254740991,-9007199254740992,-9007199254740993]`, + }, + { + name: "single_int64", + val: int64(34), + exceptUint64ToStr: `34`, + exceptInt64ToStr: `"34"`, + exceptExceedToStr: `34`, + exceptFalse: `34`, + }, + { + name: "minus_single_int64", + val: int64(-9007199254740993), + exceptUint64ToStr: `-9007199254740993`, + exceptInt64ToStr: `"-9007199254740993"`, + exceptExceedToStr: `"-9007199254740993"`, + exceptFalse: `-9007199254740993`, + }, + { + name: "single_uint64", + val: uint64(56), + exceptUint64ToStr: `"56"`, + exceptInt64ToStr: `56`, + exceptExceedToStr: `56`, + exceptFalse: `56`, + }, + { + name: "single_uint64g", + val: uint64(9007199254740993), + exceptUint64ToStr: `"9007199254740993"`, + exceptInt64ToStr: `9007199254740993`, + exceptExceedToStr: `"9007199254740993"`, + exceptFalse: `9007199254740993`, + }, + { + name: "single_uintg", + val: uint64(9007199254740993), + exceptUint64ToStr: `"9007199254740993"`, + exceptInt64ToStr: `9007199254740993`, + exceptExceedToStr: `"9007199254740993"`, + exceptFalse: `9007199254740993`, + }, + { + name: "minus_struct_ptr_val", + val: struct { + Int *int `json:"int"` + IntL *int `json:"intl"` + IntE *int `json:"inte"` + IntG *int `json:"intg"` + Int64L *int64 `json:"int64l"` + Int64E *int64 `json:"int64e"` + Int64G *int64 `json:"int64g"` + }{ + Int: &intptr, + IntL: &intLptr, + IntE: &intEptr, + IntG: &intGptr, + Int64L: &int64Lptr, + Int64E: &int64Eptr, + Int64G: &int64Gptr, + }, + exceptUint64ToStr: `{"int":1,`+ + `"intl":-9007199254740991,"inte":-9007199254740992,"intg":-9007199254740993,`+ + `"int64l":-9007199254740991,"int64e":-9007199254740992,"int64g":-9007199254740993}`, + exceptInt64ToStr: `{"int":1,`+ + `"intl":-9007199254740991,"inte":-9007199254740992,"intg":-9007199254740993,`+ + `"int64l":"-9007199254740991","int64e":"-9007199254740992","int64g":"-9007199254740993"}`, + exceptExceedToStr: `{"int":1,`+ + `"intl":-9007199254740991,"inte":-9007199254740992,"intg":"-9007199254740993",`+ + `"int64l":-9007199254740991,"int64e":-9007199254740992,"int64g":"-9007199254740993"}`, + exceptFalse: `{"int":1,`+ + `"intl":-9007199254740991,"inte":-9007199254740992,"intg":-9007199254740993,`+ + `"int64l":-9007199254740991,"int64e":-9007199254740992,"int64g":-9007199254740993}`, + }, + { + name: "normal_struct_ptr_val", + val: struct { + Int *int `json:"int"` + Int64 *int64 `json:"int64"` + Uint *uint `json:"uint"` + UintL *uint `json:"uintl"` + UintE *uint `json:"uinte"` + UintG *uint `json:"uintg"` + Uint64L *uint64 `json:"uint64l"` + Uint64E *uint64 `json:"uint64e"` + Uint64G *uint64 `json:"uint64g"` + }{ + Int: &intptr, + Int64: &int64ptr, + Uint: &uintPtr, + UintL: &uintLptr, + UintE: &uintEptr, + UintG: &uintGptr, + Uint64L: &uint64Lptr, + Uint64E: &uint64Eptr, + Uint64G: &uint64Gptr, + }, + exceptUint64ToStr: `{"int":1,"int64":1,"uint":1,`+ + `"uintl":9007199254740991,"uinte":9007199254740992,"uintg":9007199254740993,`+ + `"uint64l":"9007199254740991","uint64e":"9007199254740992","uint64g":"9007199254740993"}`, + exceptInt64ToStr: `{"int":1,"int64":"1","uint":1,`+ + `"uintl":9007199254740991,"uinte":9007199254740992,"uintg":9007199254740993,`+ + `"uint64l":9007199254740991,"uint64e":9007199254740992,"uint64g":9007199254740993}`, + exceptExceedToStr: `{"int":1,"int64":1,"uint":1,`+ + `"uintl":9007199254740991,"uinte":9007199254740992,"uintg":"9007199254740993",`+ + `"uint64l":9007199254740991,"uint64e":9007199254740992,"uint64g":"9007199254740993"}`, + exceptFalse: `{"int":1,"int64":1,"uint":1,`+ + `"uintl":9007199254740991,"uinte":9007199254740992,"uintg":9007199254740993,`+ + `"uint64l":9007199254740991,"uint64e":9007199254740992,"uint64g":9007199254740993}`, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + t.Run("uint64ToStr", func(t *testing.T) { + b, e := Config{Uint64ToString: true, SortMapKeys: true}.Froze().Marshal(c.val) + assert.Nil(t, e) + assert.Equal(t, c.exceptUint64ToStr, string(b)) + }) + + t.Run("int64ToStr", func(t *testing.T) { + b, e := Config{Int64ToString: true, SortMapKeys: true}.Froze().Marshal(c.val) + assert.Nil(t, e) + assert.Equal(t, c.exceptInt64ToStr, string(b)) + }) + t.Run("uintExceedToStr", func(t *testing.T) { + b, e := Config{IntegerExceed53BitToString: true, SortMapKeys: true}.Froze().Marshal(c.val) + assert.Nil(t, e) + assert.Equal(t, c.exceptExceedToStr, string(b)) + }) + + t.Run("noIntegerToStr", func(t *testing.T) { + b, e := Config{SortMapKeys: true}.Froze().Marshal(c.val) + assert.Nil(t, e) + assert.Equal(t, c.exceptFalse, string(b)) + }) + }) + } } \ No newline at end of file diff --git a/encoder/encoder_native.go b/encoder/encoder_native.go index b300ebf08..861ec36bb 100644 --- a/encoder/encoder_native.go +++ b/encoder/encoder_native.go @@ -73,6 +73,13 @@ const ( // Encode Infinity or Nan float into `null`, instead of returning an error. EncodeNullForInfOrNan Options = encoder.EncodeNullForInfOrNan + + // Uint64 or Int64 into strings on Marshal + Uint64ToString Options = encoder.Uint64ToString + Int64ToString Options = encoder.Int64ToString + // IntegerExceed53BitToString when intSize == 64, if the value of type integer exceeds 1<<53, + // automatically convert it to a string. + IntegerExceed53BitToString Options = encoder.IntegerExceed53BitToString ) diff --git a/internal/encoder/alg/opts.go b/internal/encoder/alg/opts.go index c19e2de4e..a6b8aecf6 100644 --- a/internal/encoder/alg/opts.go +++ b/internal/encoder/alg/opts.go @@ -25,7 +25,10 @@ const ( BitValidateString BitNoValidateJSONMarshaler BitNoEncoderNewline - BitEncodeNullForInfOrNan + BitEncodeNullForInfOrNan + BitUint64ToString + BitInt64ToString + BitIntegerExceed53BitToString BitPointerValue = 63 ) diff --git a/internal/encoder/compiler.go b/internal/encoder/compiler.go index 902fbc98b..031e94ae4 100644 --- a/internal/encoder/compiler.go +++ b/internal/encoder/compiler.go @@ -179,7 +179,7 @@ func (self *Compiler) compileOps(p *ir.Program, sp int, vt reflect.Type) { case reflect.Bool: p.Add(ir.OP_bool) case reflect.Int: - p.Add(ir.OP_int()) + p.Add(ir.OP_int(), ir.OP_i) case reflect.Int8: p.Add(ir.OP_i8) case reflect.Int16: @@ -189,7 +189,7 @@ func (self *Compiler) compileOps(p *ir.Program, sp int, vt reflect.Type) { case reflect.Int64: p.Add(ir.OP_i64) case reflect.Uint: - p.Add(ir.OP_uint()) + p.Add(ir.OP_uint(), ir.OP_u) case reflect.Uint8: p.Add(ir.OP_u8) case reflect.Uint16: @@ -301,7 +301,7 @@ func (self *Compiler) compileMapBodyTextKey(p *ir.Program, vk reflect.Type) { case reflect.Bool: p.Key(ir.OP_bool) case reflect.Int: - p.Key(ir.OP_int()) + p.Key(ir.OP_int(), ir.OP_i) case reflect.Int8: p.Key(ir.OP_i8) case reflect.Int16: @@ -311,7 +311,7 @@ func (self *Compiler) compileMapBodyTextKey(p *ir.Program, vk reflect.Type) { case reflect.Int64: p.Key(ir.OP_i64) case reflect.Uint: - p.Key(ir.OP_uint()) + p.Key(ir.OP_uint(), ir.OP_u) case reflect.Uint8: p.Key(ir.OP_u8) case reflect.Uint16: diff --git a/internal/encoder/encoder.go b/internal/encoder/encoder.go index 4cba1a168..06b39c082 100644 --- a/internal/encoder/encoder.go +++ b/internal/encoder/encoder.go @@ -73,6 +73,13 @@ const ( // Encode Infinity or Nan float into `null`, instead of returning an error. EncodeNullForInfOrNan Options = 1 << alg.BitEncodeNullForInfOrNan + + // Uint64 or Int64 into strings on Marshal + Uint64ToString Options = 1 << alg.BitUint64ToString + Int64ToString Options = 1 << alg.BitInt64ToString + // IntegerExceed53BitToString when intSize == 64, if the value of type integer exceeds 1<<53, + // automatically convert it to a string. + IntegerExceed53BitToString Options = 1 << alg.BitIntegerExceed53BitToString ) // Encoder represents a specific set of encoder configurations. diff --git a/internal/encoder/ir/op.go b/internal/encoder/ir/op.go index a0c693f00..fdc4161db 100644 --- a/internal/encoder/ir/op.go +++ b/internal/encoder/ir/op.go @@ -38,10 +38,12 @@ const ( OP_i16 OP_i32 OP_i64 + OP_i OP_u8 OP_u16 OP_u32 OP_u64 + OP_u OP_f32 OP_f64 OP_str @@ -99,10 +101,12 @@ var OpNames = [256]string{ OP_i16: "i16", OP_i32: "i32", OP_i64: "i64", + OP_i: "i", OP_u8: "u8", OP_u16: "u16", OP_u32: "u32", OP_u64: "u64", + OP_u: "u", OP_f32: "f32", OP_f64: "f64", OP_str: "str", @@ -197,12 +201,26 @@ func OP_is_zero_ints() Op { type Instr struct { o Op + co Op + mapKey bool u int // union {op: 8, _: 8, vi: 48}, vi maybe int or len(str) p unsafe.Pointer // maybe GoString.Ptr, or *GoType } -func NewInsOp(op Op) Instr { - return Instr{o: op} +func NewInsOp(op Op, compatOp ...Op) Instr { + i := Instr{o: op, co: op} + if len(compatOp) == 1 { + i.co = compatOp[0] + } + return i +} + +func NewInsKeyOp(op Op, compatOp ...Op) Instr { + i := Instr{o: op, co: op, mapKey: true} + if len(compatOp) == 1 { + i.co = compatOp[0] + } + return i } func NewInsVi(op Op, vi int) Instr { @@ -255,6 +273,14 @@ func (self Instr) Op() Op { return Op(self.o) } +func (self Instr) CompatOp() Op { + return Op(self.co) +} + +func (self Instr) IsMapKey() bool { + return self.mapKey +} + func (self Instr) Vi() int { return self.u } @@ -410,14 +436,14 @@ func (self Program) Rel(v []int) { } } -func (self *Program) Add(op Op) { - *self = append(*self, NewInsOp(op)) +func (self *Program) Add(op Op, co ...Op) { + *self = append(*self, NewInsOp(op, co...)) } -func (self *Program) Key(op Op) { +func (self *Program) Key(op Op, co ...Op) { *self = append(*self, NewInsVi(OP_byte, '"'), - NewInsOp(op), + NewInsKeyOp(op, co...), NewInsVi(OP_byte, '"'), ) } diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index b75ba807a..4320f6d90 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -34,6 +34,11 @@ const ( _S_init ) +const ( + _IMax_53 = 1<<53 + _IMin_53 = -1<<53 +) + var ( _T_json_Marshaler = rt.UnpackType(vars.JsonMarshalerType) _T_encoding_TextMarshaler = rt.UnpackType(vars.EncodingTextMarshalerType) @@ -140,8 +145,28 @@ func Execute(b *[]byte, p unsafe.Pointer, s *vars.Stack, flags uint64, prog *ir. v := *(*int32)(p) buf = alg.I64toa(buf, int64(v)) case ir.OP_i64: + if ins.IsMapKey() { + v := *(*int64)(p) + buf = alg.I64toa(buf, int64(v)) + continue + } + quote := false v := *(*int64)(p) + + if (ins.CompatOp() == ir.OP_i64 && // current value type == int64 + flags&(1< int64(_IMax_53) || v < int64(_IMin_53)) && + flags&(1< uint64(_IMax_53) && + flags&(1<