protogen: Treat bytes field as non-nullable #123

Merged
fyrchik merged 2 commits from fyrchik/frostfs-api-go:fix-optional-bytes into master 2024-11-02 14:21:46 +00:00
15 changed files with 283 additions and 61 deletions

View file

@ -691,7 +691,13 @@ func (x *EACLRecord_Target) UnmarshalEasyJSON(in *jlexer.Lexer) {
var list [][]byte var list [][]byte
in.Delim('[') in.Delim('[')
for !in.IsDelim(']') { for !in.IsDelim(']') {
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
list = append(list, f) list = append(list, f)
in.WantComma() in.WantComma()
} }

View file

@ -401,7 +401,13 @@ func (x *Chain) UnmarshalEasyJSON(in *jlexer.Lexer) {
x.Kind = xx x.Kind = xx
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
xx.Raw = f xx.Raw = f
} }
} }

View file

@ -558,7 +558,13 @@ func (x *AddChainResponse_Body) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "chainId": case "chainId":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.ChainId = f x.ChainId = f
} }
} }
@ -974,7 +980,13 @@ func (x *RemoveChainRequest_Body) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "chainId": case "chainId":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.ChainId = f x.ChainId = f
} }
} }

View file

@ -500,7 +500,13 @@ func (x *Container) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "nonce": case "nonce":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Nonce = f x.Nonce = f
} }
case "basicACL": case "basicACL":

View file

@ -1855,7 +1855,13 @@ func (x *NodeInfo) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "publicKey": case "publicKey":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.PublicKey = f x.PublicKey = f
} }
case "addresses": case "addresses":
@ -2279,13 +2285,25 @@ func (x *NetworkConfig_Parameter) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "key": case "key":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Key = f x.Key = f
} }
case "value": case "value":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Value = f x.Value = f
} }
} }

View file

@ -924,7 +924,13 @@ func (x *GetResponse_Body) UnmarshalEasyJSON(in *jlexer.Lexer) {
x.ObjectPart = xx x.ObjectPart = xx
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
xx.Chunk = f xx.Chunk = f
} }
case "splitInfo": case "splitInfo":
@ -1699,7 +1705,13 @@ func (x *PutRequest_Body) UnmarshalEasyJSON(in *jlexer.Lexer) {
x.ObjectPart = xx x.ObjectPart = xx
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
xx.Chunk = f xx.Chunk = f
} }
} }
@ -6254,7 +6266,13 @@ func (x *GetRangeResponse_Body) UnmarshalEasyJSON(in *jlexer.Lexer) {
x.RangePart = xx x.RangePart = xx
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
xx.Chunk = f xx.Chunk = f
} }
case "splitInfo": case "splitInfo":
@ -6802,7 +6820,13 @@ func (x *GetRangeHashRequest_Body) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "salt": case "salt":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Salt = f x.Salt = f
} }
case "type": case "type":
@ -7267,7 +7291,13 @@ func (x *GetRangeHashResponse_Body) UnmarshalEasyJSON(in *jlexer.Lexer) {
var list [][]byte var list [][]byte
in.Delim('[') in.Delim('[')
for !in.IsDelim(']') { for !in.IsDelim(']') {
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
list = append(list, f) list = append(list, f)
in.WantComma() in.WantComma()
} }
@ -8455,7 +8485,13 @@ func (x *PatchRequest_Body_Patch) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "chunk": case "chunk":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Chunk = f x.Chunk = f
} }
} }

View file

@ -1015,7 +1015,13 @@ func (x *Header_Split) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "splitID": case "splitID":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.SplitId = f x.SplitId = f
} }
} }
@ -1436,13 +1442,25 @@ func (x *Header_EC) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "header": case "header":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Header = f x.Header = f
} }
case "parentSplitID": case "parentSplitID":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.ParentSplitId = f x.ParentSplitId = f
} }
case "parentSplitParentID": case "parentSplitParentID":
@ -2347,7 +2365,13 @@ func (x *Object) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "payload": case "payload":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Payload = f x.Payload = f
} }
} }
@ -2552,7 +2576,13 @@ func (x *SplitInfo) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "splitId": case "splitId":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.SplitId = f x.SplitId = f
} }
case "lastPart": case "lastPart":

View file

@ -390,7 +390,13 @@ func (x *ObjectID) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "value": case "value":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Value = f x.Value = f
} }
} }
@ -529,7 +535,13 @@ func (x *ContainerID) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "value": case "value":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Value = f x.Value = f
} }
} }
@ -668,7 +680,13 @@ func (x *OwnerID) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "value": case "value":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Value = f x.Value = f
} }
} }
@ -1063,13 +1081,25 @@ func (x *Signature) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "key": case "key":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Key = f x.Key = f
} }
case "signature": case "signature":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Sign = f x.Sign = f
} }
case "scheme": case "scheme":
@ -1264,13 +1294,25 @@ func (x *SignatureRFC6979) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "key": case "key":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Key = f x.Key = f
} }
case "signature": case "signature":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Sign = f x.Sign = f
} }
} }
@ -1466,7 +1508,13 @@ func (x *Checksum) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "sum": case "sum":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Sum = f x.Sum = f
} }
} }

View file

@ -598,13 +598,25 @@ func (x *CreateResponse_Body) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "id": case "id":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Id = f x.Id = f
} }
case "sessionKey": case "sessionKey":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.SessionKey = f x.SessionKey = f
} }
} }

View file

@ -1284,7 +1284,13 @@ func (x *SessionToken_Body) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "id": case "id":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Id = f x.Id = f
} }
case "ownerID": case "ownerID":
@ -1304,7 +1310,13 @@ func (x *SessionToken_Body) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "sessionKey": case "sessionKey":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.SessionKey = f x.SessionKey = f
} }
case "object": case "object":

View file

@ -439,7 +439,13 @@ func (x *Status_Detail) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "value": case "value":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.Value = f x.Value = f
} }
} }

View file

@ -231,7 +231,13 @@ func (x *Tombstone) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "splitID": case "splitID":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.SplitId = f x.SplitId = f
} }
case "members": case "members":

View file

@ -50,9 +50,6 @@ func TestStableMarshalSingle(t *testing.T) {
var actualFrostfs generated.Primitives var actualFrostfs generated.Primitives
require.NoError(t, actualFrostfs.UnmarshalJSON(r)) require.NoError(t, actualFrostfs.UnmarshalJSON(r))
if len(actualFrostfs.FieldA) == 0 {
actualFrostfs.FieldA = nil
}
require.Equal(t, input, &actualFrostfs) require.Equal(t, input, &actualFrostfs)
primitivesEqual(t, input, &actual) primitivesEqual(t, input, &actual)
@ -110,9 +107,6 @@ func TestStableMarshalSingle(t *testing.T) {
var actualFrostfs generated.Primitives var actualFrostfs generated.Primitives
require.NoError(t, actualFrostfs.UnmarshalJSON(r)) require.NoError(t, actualFrostfs.UnmarshalJSON(r))
if len(actualFrostfs.FieldA) == 0 {
actualFrostfs.FieldA = nil
}
require.Equal(t, tc.input, &actualFrostfs) require.Equal(t, tc.input, &actualFrostfs)
primitivesEqual(t, tc.input, &actual) primitivesEqual(t, tc.input, &actual)
@ -124,9 +118,7 @@ func TestStableMarshalSingle(t *testing.T) {
func primitivesEqual(t *testing.T, a *generated.Primitives, b *test.Primitives) { func primitivesEqual(t *testing.T, a *generated.Primitives, b *test.Primitives) {
// Compare each field directly, because proto-generated code has private fields. // Compare each field directly, because proto-generated code has private fields.
require.Equal(t, len(a.FieldA), len(b.FieldA)) require.Equal(t, len(a.FieldA), len(b.FieldA))
if len(a.FieldA) != 0 { require.Equal(t, a.FieldA, b.FieldA)
require.Equal(t, a.FieldA, b.FieldA)
}
require.Equal(t, a.FieldB, b.FieldB) require.Equal(t, a.FieldB, b.FieldB)
require.Equal(t, a.FieldC, b.FieldC) require.Equal(t, a.FieldC, b.FieldC)
require.Equal(t, a.FieldD, b.FieldD) require.Equal(t, a.FieldD, b.FieldD)

View file

@ -771,7 +771,13 @@ func (x *Primitives) UnmarshalEasyJSON(in *jlexer.Lexer) {
case "fieldA": case "fieldA":
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
x.FieldA = f x.FieldA = f
} }
case "fieldB": case "fieldB":
@ -903,7 +909,13 @@ func (x *Primitives) UnmarshalEasyJSON(in *jlexer.Lexer) {
x.FieldM = xx x.FieldM = xx
{ {
var f []byte var f []byte
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
xx.FieldMa = f xx.FieldMa = f
} }
case "fieldMe": case "fieldMe":
@ -1520,7 +1532,13 @@ func (x *RepPrimitives) UnmarshalEasyJSON(in *jlexer.Lexer) {
var list [][]byte var list [][]byte
in.Delim('[') in.Delim('[')
for !in.IsDelim(']') { for !in.IsDelim(']') {
f = in.Bytes() {
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
f = tmp
}
list = append(list, f) list = append(list, f)
in.WantComma() in.WantComma()
} }

View file

@ -70,6 +70,24 @@ func emitJSONParseInteger(g *protogen.GeneratedFile, ident string, method string
g.P(ident, " := ", typ, "(v)") g.P(ident, " := ", typ, "(v)")
} }
func emitJSONReadEnum(g *protogen.GeneratedFile, name string, enumType string) {
g.P(`switch v := in.Interface().(type) {
case string:
if vv, ok := `+enumType+`_value[v]; ok {
`+name+` = `+enumType+`(vv)
break
}
vv, err := `, strconvPackage.Ident("ParseInt"), `(v, 10, 32)
if err != nil {
in.AddError(err)
return
}
`+name+` = `+enumType+`(vv)
case float64:
`+name+` = `+enumType+`(v)
}`)
}
func emitJSONFieldRead(g *protogen.GeneratedFile, f *protogen.Field, name string) { func emitJSONFieldRead(g *protogen.GeneratedFile, f *protogen.Field, name string) {
g.P("{") g.P("{")
defer g.P("}") defer g.P("}")
@ -94,21 +112,7 @@ func emitJSONFieldRead(g *protogen.GeneratedFile, f *protogen.Field, name string
enumType := fieldType(g, f).String() enumType := fieldType(g, f).String()
g.P("var parsedValue " + enumType) g.P("var parsedValue " + enumType)
g.P(`switch v := in.Interface().(type) { emitJSONReadEnum(g, "parsedValue", enumType)
case string:
if vv, ok := `+enumType+`_value[v]; ok {
parsedValue = `+enumType+`(vv)
break
}
vv, err := `, strconvPackage.Ident("ParseInt"), `(v, 10, 32)
if err != nil {
in.AddError(err)
return
}
parsedValue = `+enumType+`(vv)
case float64:
parsedValue = `+enumType+`(v)
}`)
template = "%s = parsedValue" template = "%s = parsedValue"
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
emitJSONParseInteger(g, "pv", "ParseInt", 32, "int32") emitJSONParseInteger(g, "pv", "ParseInt", 32, "int32")
@ -129,7 +133,17 @@ func emitJSONFieldRead(g *protogen.GeneratedFile, f *protogen.Field, name string
case protoreflect.StringKind: case protoreflect.StringKind:
template = "%s = in.String()" template = "%s = in.String()"
case protoreflect.BytesKind: case protoreflect.BytesKind:
template = "%s = in.Bytes()" // Since some time ago proto3 support optional keyword, thus the presence is not tracked by default:
// https://github.com/protocolbuffers/protobuf-go/blob/fb995f184a1719ec42b247a3771d1036d92adf67/internal/impl/message_reflect_field.go#L327
// We do not explicitly support `optional` keyword, protoc will fail on such fileds.
// Thus, treat empty string as `[]byte(nil)`.
template = `{
tmp := in.Bytes()
if len(tmp) == 0 {
tmp = nil
}
%s = tmp
}`
case protoreflect.MessageKind: case protoreflect.MessageKind:
if f.Desc.IsList() { if f.Desc.IsList() {
g.P("f = ", fieldType(g, f)[2:], "{}") g.P("f = ", fieldType(g, f)[2:], "{}")