ptr type (#6)

This commit is contained in:
guonaihong
2023-03-13 23:33:40 +08:00
committed by GitHub
parent 93291a4d76
commit f7486f581c
10 changed files with 305 additions and 149 deletions
+158
View File
@@ -0,0 +1,158 @@
package json
import (
"bytes"
"fmt"
)
const (
// protobuf message开始
messageStart = "message %s {\n" // ok
messageStartArrayStruct = "message %s {\n" //
messageEndStruct = "}" // TODO
messageStartInlineMapAfter = "%s%s %s = %d;\n" // repeated? int32 id = 4;
messageStartInlineMap = "message %s {\n" // 内联message体开始
messageStartMap = "%s %s%s `%s:\"%s\"`" // 拆开结构体开始, TODO
messageEndMap = "}\n" // 拆开结构体结束, TODO
//messageNilFmt = "%s any `%s:\"%s\"`" //TODO protobuf 暂时忽略
messageStringFmt = "%sstring %s = %d;" //repeated? int32 id = 2;
messageBoolFmt = "%sbool %s = %d;" //repeated? int32 id = 2;
messageFloat64Fmt = "%sfloat64 %s = %d;" //repeated? int32 id = 2;
messageIntFmt = "%sint64 %s = %d;" //repeated? int32 id = 2;
messageSpecifytFmt = "%s %s = %d;" // ok
// json --
startStruct = "type %s struct {\n"
startArrayStruct = "type %s []struct {\n"
endStruct = "}"
startInlineMap = "%s %sstruct {\n" // 内联结构体开始
endInlineMap = "} `%s:\"%s\"`" // 内联结构体结束
startMap = "%s %s%s `%s:\"%s\"`" // 拆开结构体开始
emptyMap = "%s struct {" +
"} `%s:\"%s\"`"
defStructName = "AutoGenerated"
nilFmt = "%s interface{} `%s:\"%s\"`"
stringFmt = "%s %sstring `%s:\"%s\"`"
stringPtrFmt = "%s %s*string `%s:\"%s\"`"
boolFmt = "%s %sbool `%s:\"%s\"`"
boolPtrFmt = "%s %s*bool `%s:\"%s\"`"
float64Fmt = "%s %sfloat64 `%s:\"%s\"`"
float64PtrFmt = "%s %s*float64 `%s:\"%s\"`"
intFmt = "%s %sint `%s:\"%s\"`"
intPtrFmt = "%s %s*int `%s:\"%s\"`"
specifytFmt = "%s %s `%s:\"%s\"`"
)
func (j *JSON) getSpecifytFmt(buf *bytes.Buffer, fieldName string, fieldType string, tagName string, id int, ptr bool) {
if j.IsProtobuf {
buf.WriteString(fmt.Sprintf(messageSpecifytFmt, fieldType, fieldName, id))
return
}
// TODO 指针类型
buf.WriteString(fmt.Sprintf(specifytFmt, fieldName, fieldType, j.Tag, tagName))
}
// 生成结构体或者message的开头
func (j *JSON) getStructStart(buf *bytes.Buffer) {
format := startStruct
if j.IsProtobuf {
format = messageStart
}
buf.WriteString(fmt.Sprintf(format, j.StructName))
return
}
// array 对象外层
func (j *JSON) getArrayStart(buf *bytes.Buffer) {
if j.IsProtobuf {
buf.WriteString(fmt.Sprintf(messageStartArrayStruct, j.StructName))
return
}
buf.WriteString(fmt.Sprintf(startArrayStruct, j.StructName))
}
func (j *JSON) getInt(buf *bytes.Buffer, fieldName string, typePrefix string, tagName string, id int, ptr bool) {
if j.IsProtobuf {
buf.WriteString(fmt.Sprintf(messageIntFmt, typePrefix, fieldName, id))
return
}
format := intFmt
if ptr {
format = intPtrFmt
}
buf.WriteString(fmt.Sprintf(format, fieldName, typePrefix, j.Tag, tagName))
return
}
func (j *JSON) getFloat64(buf *bytes.Buffer, fieldName string, typePrefix string, tagName string, id int, ptr bool) {
if j.IsProtobuf {
buf.WriteString(fmt.Sprintf(messageFloat64Fmt, typePrefix, fieldName, id))
return
}
format := float64Fmt
if ptr {
format = float64PtrFmt
}
buf.WriteString(fmt.Sprintf(format, fieldName, typePrefix, j.Tag, tagName))
return
}
func (j *JSON) getBool(buf *bytes.Buffer, fieldName string, typePrefix string, tagName string, id int, ptr bool) {
if j.IsProtobuf {
buf.WriteString(fmt.Sprintf(messageBoolFmt, typePrefix, fieldName, id))
return
}
format := boolFmt
if ptr {
format = boolPtrFmt
}
buf.WriteString(fmt.Sprintf(format, fieldName, typePrefix, j.Tag, tagName))
return
}
func (j *JSON) getString(buf *bytes.Buffer, fieldName string, typePrefix string, tagName string, id int, ptr bool) {
if j.IsProtobuf {
buf.WriteString(fmt.Sprintf(messageStringFmt, typePrefix, fieldName, id))
return
}
format := stringFmt
if ptr {
format = stringPtrFmt
}
buf.WriteString(fmt.Sprintf(format, fieldName, typePrefix, j.Tag, tagName))
return
}
func (j *JSON) getStartInlineMap(buf *bytes.Buffer, fieldName string, typePrefix string, depth int) {
if j.IsProtobuf {
buf.WriteString(fmt.Sprintf(messageStartInlineMap, fieldName))
return
}
buf.WriteString(fmt.Sprintf(startInlineMap, fieldName, typePrefix))
}
func (j *JSON) getEndInlineMap(buf *bytes.Buffer, fieldName string, typePrefix string, tagName string, depth int, id int) {
if j.IsProtobuf {
buf.WriteString(fmt.Sprintf(messageEndMap))
j.writeIndent(buf, depth)
buf.WriteString(fmt.Sprintf(messageStartInlineMapAfter, typePrefix, fieldName, tagName, id))
return
}
buf.WriteString(fmt.Sprintf(endInlineMap, j.Tag, tagName))
}
+18 -147
View File
@@ -17,12 +17,12 @@ import (
)
type JSON struct {
option.Option
obj any // json/yaml 解成map[string]any 或者[]any
Indent int // 控制输出缩进
buf bytes.Buffer // 存放内联结构体的数据
count map[string]int //记录message里面的最大值
structBuf map[string]*bytes.Buffer // 记录拆分结构体
option.Option // 内嵌配置信息
obj any // json/yaml 解成map[string]any 或者[]any
Indent int // 控制输出缩进
buf bytes.Buffer // 存放内联结构体的数据
count map[string]int // 记录message里面的最大值
structBuf map[string]*bytes.Buffer // 记录拆分结构体
}
type Type interface {
@@ -70,141 +70,6 @@ type Third struct {
}
*/
const (
// protobuf message开始
messageStart = "message %s {\n" // ok
messageStartArrayStruct = "message %s {\n" //
messageEndStruct = "}" // TODO
messageStartInlineMapAfter = "%s%s %s = %d;\n" // repeated? int32 id = 4;
messageStartInlineMap = "message %s {\n" // 内联message体开始
messageStartMap = "%s %s%s `%s:\"%s\"`" // 拆开结构体开始, TODO
messageEndMap = "}\n" // 拆开结构体结束, TODO
//messageNilFmt = "%s any `%s:\"%s\"`" //TODO protobuf 暂时忽略
messageStringFmt = "%sstring %s = %d;" //repeated? int32 id = 2;
messageBoolFmt = "%sbool %s = %d;" //repeated? int32 id = 2;
messageFloat64Fmt = "%sfloat64 %s = %d;" //repeated? int32 id = 2;
messageIntFmt = "%sint64 %s = %d;" //repeated? int32 id = 2;
messageSpecifytFmt = "%s %s = %d;" // ok
// json --
startStruct = "type %s struct {\n"
startArrayStruct = "type %s []struct {\n"
endStruct = "}"
startInlineMap = "%s %sstruct {\n" // 内联结构体开始
endInlineMap = "} `%s:\"%s\"`" // 内联结构体结束
startMap = "%s %s%s `%s:\"%s\"`" // 拆开结构体开始
emptyMap = "%s struct {" +
"} `%s:\"%s\"`"
defStructName = "AutoGenerated"
nilFmt = "%s interface{} `%s:\"%s\"`"
stringFmt = "%s %sstring `%s:\"%s\"`"
boolFmt = "%s %sbool `%s:\"%s\"`"
float64Fmt = "%s %sfloat64 `%s:\"%s\"`"
intFmt = "%s %sint `%s:\"%s\"`"
specifytFmt = "%s %s `%s:\"%s\"`"
)
func (j *JSON) getSpecifytFmt(buf *bytes.Buffer, fieldName string, fieldType string, tagName string, id int) {
if j.IsProtobuf {
buf.WriteString(fmt.Sprintf(messageSpecifytFmt, fieldType, fieldName, id))
return
}
buf.WriteString(fmt.Sprintf(specifytFmt, fieldName, fieldType, j.Tag, tagName))
}
// 生成结构体或者message的开头
func (j *JSON) getStructStart(buf *bytes.Buffer) {
format := startStruct
if j.IsProtobuf {
format = messageStart
}
buf.WriteString(fmt.Sprintf(format, j.StructName))
return
}
// array 对象外层
func (j *JSON) getArrayStart(buf *bytes.Buffer) {
if j.IsProtobuf {
buf.WriteString(fmt.Sprintf(messageStartArrayStruct, j.StructName))
return
}
buf.WriteString(fmt.Sprintf(startArrayStruct, j.StructName))
}
func (j *JSON) getInt(buf *bytes.Buffer, fieldName string, typePrefix string, tagName string, id int) {
if j.IsProtobuf {
buf.WriteString(fmt.Sprintf(messageIntFmt, typePrefix, fieldName, id))
return
}
buf.WriteString(fmt.Sprintf(intFmt, fieldName, typePrefix, j.Tag, tagName))
return
}
func (j *JSON) getFloat64(buf *bytes.Buffer, fieldName string, typePrefix string, tagName string, id int) {
if j.IsProtobuf {
buf.WriteString(fmt.Sprintf(messageFloat64Fmt, typePrefix, fieldName, id))
return
}
buf.WriteString(fmt.Sprintf(float64Fmt, fieldName, typePrefix, j.Tag, tagName))
return
}
func (j *JSON) getBool(buf *bytes.Buffer, fieldName string, typePrefix string, tagName string, id int) {
if j.IsProtobuf {
buf.WriteString(fmt.Sprintf(messageBoolFmt, typePrefix, fieldName, id))
return
}
buf.WriteString(fmt.Sprintf(boolFmt, fieldName, typePrefix, j.Tag, tagName))
return
}
func (j *JSON) getString(buf *bytes.Buffer, fieldName string, typePrefix string, tagName string, id int) {
if j.IsProtobuf {
buf.WriteString(fmt.Sprintf(messageStringFmt, typePrefix, fieldName, id))
return
}
buf.WriteString(fmt.Sprintf(stringFmt, fieldName, typePrefix, j.Tag, tagName))
return
}
func (j *JSON) getStartInlineMap(buf *bytes.Buffer, fieldName string, typePrefix string, depth int) {
if j.IsProtobuf {
// 这里是message 开始和上个普通成员缩进保持一致
// int32 x = 3;
// message xx {
// }
//j.writeIndent(buf, depth)
buf.WriteString(fmt.Sprintf(messageStartInlineMap, fieldName))
return
}
buf.WriteString(fmt.Sprintf(startInlineMap, fieldName, typePrefix))
}
func (j *JSON) getEndInlineMap(buf *bytes.Buffer, fieldName string, typePrefix string, tagName string, depth int, id int) {
if j.IsProtobuf {
buf.WriteString(fmt.Sprintf(messageEndMap))
j.writeIndent(buf, depth)
buf.WriteString(fmt.Sprintf(messageStartInlineMapAfter, typePrefix, fieldName, tagName, id))
return
}
buf.WriteString(fmt.Sprintf(endInlineMap, j.Tag, tagName))
}
func Marshal[T Type](t T, opt ...option.OptionFunc) (b []byte, err error) {
f, err := new(t, opt...)
if err != nil {
@@ -420,11 +285,17 @@ func (f *JSON) marshalValue(key string, obj any, fromArray bool, depth int, buf
fieldName, tagName := name.GetFieldAndTagName(key)
ptr := false
// 字段是否要表示成指针类型
if f.UsePtr[keyPath] {
ptr = true
}
// 重写key的类型
if f.TypeMap != nil {
fieldType, ok := f.TypeMap[keyPath]
if ok {
f.getSpecifytFmt(buf, fieldName, fieldType, tagName, *id)
f.getSpecifytFmt(buf, fieldName, fieldType, tagName, *id, ptr)
return
}
}
@@ -460,20 +331,20 @@ func (f *JSON) marshalValue(key string, obj any, fromArray bool, depth int, buf
}
f.marshalArray(key, v, depth, buf, keyPath+"[0]", id)
case string:
f.getString(buf, fieldName, typePrefix, tagName, *id)
f.getString(buf, fieldName, typePrefix, tagName, *id, ptr)
case float64: //json默认解析的数字是float64类型
// int
if float64(int(v)) == v {
f.getInt(buf, fieldName, typePrefix, tagName, *id)
f.getInt(buf, fieldName, typePrefix, tagName, *id, ptr)
return
}
// float64
f.getFloat64(buf, fieldName, typePrefix, tagName, *id)
f.getFloat64(buf, fieldName, typePrefix, tagName, *id, ptr)
case int: //yaml解析成map[string]any,数值是int类型
f.getInt(buf, fieldName, typePrefix, tagName, *id)
f.getInt(buf, fieldName, typePrefix, tagName, *id, ptr)
case bool:
f.getBool(buf, fieldName, typePrefix, tagName, *id)
f.getBool(buf, fieldName, typePrefix, tagName, *id, ptr)
case nil:
buf.WriteString(fmt.Sprintf(nilFmt, fieldName, f.Tag, tagName))
}
+83
View File
@@ -0,0 +1,83 @@
package json
import (
"bytes"
"encoding/json"
"fmt"
"os"
"testing"
"github.com/antlabs/gstl/mapex"
"github.com/antlabs/tostruct/option"
"github.com/stretchr/testify/assert"
)
const (
dataFormat = "../testdata/json/data%d.json"
needFormat1 = "../testdata/json/need%d.json.0.struct"
needFormat2 = "../testdata/json/need%d.json.1.struct"
needPtrFormat1 = "../testdata/json/need%d.json.0.ptr.struct"
needPtrFormat2 = "../testdata/json/need%d.json.1.ptr.struct"
)
func Test_Gen_Obj_JSONEx(t *testing.T) {
for i := 0; i < 1; i++ {
data, err := os.ReadFile(fmt.Sprintf(dataFormat, i))
assert.NoError(t, err)
need1, err := os.ReadFile(fmt.Sprintf(needFormat1, i))
assert.NoError(t, err)
need2, err := os.ReadFile(fmt.Sprintf(needFormat2, i))
assert.NoError(t, err)
needPtr1, err := os.ReadFile(fmt.Sprintf(needPtrFormat1, i))
assert.NoError(t, err)
needPtr2, err := os.ReadFile(fmt.Sprintf(needPtrFormat2, i))
assert.NoError(t, err)
var m map[string]any
err = json.Unmarshal(data, &m)
assert.NoError(t, err)
keys := mapex.Keys(m)
for i, v := range keys {
keys[i] = "." + v
}
var out bytes.Buffer
got1, err := Marshal(data, option.WithStructName("reqName"), option.WithOutputFmtBefore(&out))
assert.NoError(t, err, out.String())
out.Reset()
got2, err := Marshal(data, option.WithStructName("reqName"), option.WithNotInline(), option.WithOutputFmtBefore(&out))
assert.NoError(t, err, out.String())
need1 = bytes.TrimSpace(need1)
need2 = bytes.TrimSpace(need2)
got1 = bytes.TrimSpace(got1)
got2 = bytes.TrimSpace(got2)
assert.Equal(t, need1, got1)
assert.Equal(t, need2, got2)
gotPtr1, err := Marshal(data, option.WithStructName("reqName"), option.WithOutputFmtBefore(&out), option.WithUsePtrField(keys))
assert.NoError(t, err, out.String())
out.Reset()
gotPtr2, err := Marshal(data, option.WithStructName("reqName"), option.WithNotInline(), option.WithOutputFmtBefore(&out), option.WithUsePtrField(keys))
assert.NoError(t, err, out.String())
needPtr1 = bytes.TrimSpace(needPtr1)
needPtr2 = bytes.TrimSpace(needPtr2)
gotPtr1 = bytes.TrimSpace(gotPtr1)
gotPtr2 = bytes.TrimSpace(gotPtr2)
assert.Equal(t, string(needPtr1), string(gotPtr1))
assert.Equal(t, string(needPtr2), string(gotPtr2))
}
}
+1 -1
View File
@@ -40,7 +40,7 @@ func ValidAndUnmarshal(b []byte) (o map[string]any, a []any, err error) {
}
if err := json.Unmarshal(b, &o); err == nil /*没有错误说明是json 对象字符串*/ {
return o, nil, ErrValid
return o, nil, nil
}
// 可能是array对象
+15 -1
View File
@@ -11,6 +11,7 @@ type OptionFunc func(c *Option)
type Option struct {
IsProtobuf bool
UsePtr map[string]bool
Inline bool
Tag string
StructName string
@@ -107,9 +108,22 @@ func WithOutputFmtBefore(w io.Writer) OptionFunc {
}
}
// 使用protobuf, 仅protobuf包有效
// 使用protobuf, 仅protobuf包有效
func WithProtobuf() OptionFunc {
return func(c *Option) {
c.IsProtobuf = true
}
}
// json/yaml有效
func WithUsePtrField(fieldList []string) OptionFunc {
return func(c *Option) {
if c.UsePtr == nil {
c.UsePtr = make(map[string]bool)
}
for _, v := range fieldList {
c.UsePtr[v] = true
}
}
}
+6
View File
@@ -0,0 +1,6 @@
{
"string": "",
"int": 0,
"float64": 3.1415,
"bool": false
}
+6
View File
@@ -0,0 +1,6 @@
type reqName struct {
Bool *bool `json:"bool"`
Float64 *float64 `json:"float64"`
Int *int `json:"int"`
String *string `json:"string"`
}
+6
View File
@@ -0,0 +1,6 @@
type reqName struct {
Bool bool `json:"bool"`
Float64 float64 `json:"float64"`
Int int `json:"int"`
String string `json:"string"`
}
+6
View File
@@ -0,0 +1,6 @@
type reqName struct {
Bool *bool `json:"bool"`
Float64 *float64 `json:"float64"`
Int *int `json:"int"`
String *string `json:"string"`
}
+6
View File
@@ -0,0 +1,6 @@
type reqName struct {
Bool bool `json:"bool"`
Float64 float64 `json:"float64"`
Int int `json:"int"`
String string `json:"string"`
}