From 0e9211ceab6ff34f1f07a25146a3d17887edf6ee Mon Sep 17 00:00:00 2001 From: tdakkota Date: Tue, 16 May 2023 06:36:16 +0300 Subject: [PATCH 1/7] feat(gen): generate `ogen` handler -> gRPC wrapper --- cmd/protoc-gen-oas/main.go | 7 + go.mod | 8 +- go.sum | 12 +- internal/gen/_template/handler.tmpl | 71 ++++++ internal/gen/_template/header.tmpl | 10 + internal/gen/_template/messages.tmpl | 151 +++++++++++++ internal/gen/generator.go | 34 +++ internal/gen/generator_test.go | 1 + internal/gen/httprule.go | 8 +- internal/gen/mapping.go | 130 +++++++++++ internal/gen/proxy.go | 316 +++++++++++++++++++++++++++ internal/gen/schema.go | 7 +- internal/gen/template.go | 92 ++++++++ 13 files changed, 833 insertions(+), 14 deletions(-) create mode 100644 internal/gen/_template/handler.tmpl create mode 100644 internal/gen/_template/header.tmpl create mode 100644 internal/gen/_template/messages.tmpl create mode 100644 internal/gen/mapping.go create mode 100644 internal/gen/proxy.go create mode 100644 internal/gen/template.go diff --git a/cmd/protoc-gen-oas/main.go b/cmd/protoc-gen-oas/main.go index 25145db..0e643d5 100644 --- a/cmd/protoc-gen-oas/main.go +++ b/cmd/protoc-gen-oas/main.go @@ -22,6 +22,7 @@ func run() error { version := set.String("version", "", "Version") indent := set.Int("indent", 2, "Indent") filename := set.String("filename", "openapi", "Filename") + proxy := set.Bool("proxy", false, "Generate generate gRPC proxy based on ogen") if err := set.Parse(os.Args[1:]); err != nil { return errors.Wrap(err, "parse args") @@ -56,6 +57,12 @@ func run() error { return err } + if *proxy { + if err := g.WriteProxy(plugin); err != nil { + return errors.Wrap(err, "write proxy") + } + } + return nil } diff --git a/go.mod b/go.mod index 835ced9..4087db0 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,9 @@ require ( github.com/go-faster/yaml v0.4.6 github.com/ogen-go/ogen v1.6.0 github.com/stretchr/testify v1.9.0 - golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 - google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda + golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c + golang.org/x/tools v0.26.0 + google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 google.golang.org/protobuf v1.35.1 ) @@ -19,7 +20,6 @@ require ( github.com/fatih/color v1.18.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-faster/jx v1.1.0 // indirect - github.com/google/go-cmp v0.5.9 // indirect github.com/google/uuid v1.6.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -27,7 +27,9 @@ require ( github.com/segmentio/asm v1.2.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect + golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.30.0 // indirect + golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/text v0.19.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 16db36d..1180cb1 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,8 @@ github.com/go-faster/sdk v0.15.1 h1:zMIxy4eU5WRF5H3UM8FLSMU8XVRETV4gxpwVfW/v9p4= github.com/go-faster/sdk v0.15.1/go.mod h1:F9wNhIXkmuMXsGetkc2VIMBKVBoC1J3PNnRLj4PDiFk= github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I= github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -43,8 +43,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= -golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= +golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= @@ -59,8 +59,8 @@ golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= -google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda h1:b6F6WIV4xHHD0FA4oIyzU6mHWg2WI2X1RBehwa5QN38= -google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda/go.mod h1:AHcE/gZH76Bk/ROZhQphlRoWo5xKDEtz3eVEO1LfA8c= +google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 h1:2oV8dfuIkM1Ti7DwXc0BJfnwr9csz4TDXI9EmiI+Rbw= +google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38/go.mod h1:vuAjtvlwkDKF6L1GQ0SokiRLCGFfeBUXWr/aFFkHACc= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/gen/_template/handler.tmpl b/internal/gen/_template/handler.tmpl new file mode 100644 index 0000000..98053fe --- /dev/null +++ b/internal/gen/_template/handler.tmpl @@ -0,0 +1,71 @@ +{{ define "handler" }} +{{- template "header" $ }} + +// WrapperHandler is an oas.Handler implementation that maps request to gRPC server. +type WrapperHandler struct { +{{- range $s := $.Services }} + {{ $s.ProtoName }} {{ $s.ProtoServer }} +{{- end }} +} + +var _ oas.Handler = (*WrapperHandler)(nil) + +{{- range $s := $.Services }}{{- range $m := $s.Methods }} +// {{ $m.OgenName }} maps request to {{ $s.ProtoName }}.{{ $m.ProtoName }}. +func (h *WrapperHandler) {{ $m.OgenName }}(ctx context.Context, + {{- if $m.Input.HasParams }}params {{ $m.ParamsType }},{{- end -}} + {{- if $m.Input.Body }}req {{ $m.Input.Body.OgenType }},{{- end -}} +)(resp {{ $m.Output.OgenType }}, _ error) { + input := new({{ $m.Input.ProtoType }}) + {{- if $m.Input.HasParams }} + h.map{{ $m.OgenName }}Params(input, params) + {{- end }} + {{- if $m.Input.Body }} + h.map{{ $m.OgenName }}BodyInput(input, req) + {{- end }} + output, err := h.{{ $s.ProtoName }}.{{ $m.ProtoName }}(ctx, input) + if err != nil { + return resp, err + } + return h.map{{ $m.OgenName }}Output(output), nil +} + +{{ if $m.Input.HasParams -}} +func (h *WrapperHandler) map{{ $m.OgenName }}Params(pm *{{ $m.Input.ProtoType }}, om {{ $m.ParamsType }}) { + {{- range $p := $m.Input.Path }} + {{- template "map_value_from" $p.Elem }} + {{- end }} +} +{{- end }} + +{{ with $body := $m.Input.Body -}} +func (h *WrapperHandler) map{{ $m.OgenName }}BodyInput(pm *{{ $m.Input.ProtoType }}, om {{ $body.OgenType }}) { +{{- if $m.Input.AllInBody }} + {{- if $body.PassByPointer }} + pm.FromOpenAPI(*om) + {{- else }} + pm.FromOpenAPI(om) + {{- end }} +{{- else if $body.Field -}} + {{- template "map_value_from" $body.Field.Elem }} +{{- end }} +} +{{- end }} + +func (h *WrapperHandler) map{{ $m.OgenName }}Output(pm *{{ $m.Output.ProtoType }}) (om {{ $m.Output.OgenType }}) { +{{- if $m.Output.AllInBody }} + respVal := pm.ToOpenAPI() + {{- if $m.Output.PassByPointer }} + return &respVal + {{- else }} + return respVal + {{- end }} +{{- else }} + {{ template "map_value_to" $m.Output.Field.Elem }} + return resp +{{- end }} +} + +{{ end }}{{- end }} + +{{- end }} diff --git a/internal/gen/_template/header.tmpl b/internal/gen/_template/header.tmpl new file mode 100644 index 0000000..4b5e5ad --- /dev/null +++ b/internal/gen/_template/header.tmpl @@ -0,0 +1,10 @@ +{{ define "header" }} +// Code generated by protoc-gen-oas, DO NOT EDIT. +package {{ $.PackageName }} + +import ( + {{- range $i := $.Imports }} + {{ $i.Name }} {{ $i.Path }} + {{- end }} +) +{{ end }} diff --git a/internal/gen/_template/messages.tmpl b/internal/gen/_template/messages.tmpl new file mode 100644 index 0000000..cfc16f2 --- /dev/null +++ b/internal/gen/_template/messages.tmpl @@ -0,0 +1,151 @@ +{{ define "messages" }} +{{- template "header" $ }} + +func indirectOf[P ~*T, T any](p P) (zero T) { + return zero +} + +func elemOf[S ~[]T, T any](s S) (zero T) { + return zero +} + +func valueOf[M ~map[K]V, K comparable, V any](m M) (zero V) { + return zero +} + +func initPtr[P ~*T, T any](p *P) { + var zero T + *p = &zero +} + +func insertMap[M ~map[K]V, K comparable, V any](m *M, k K, v V) { + if *m == nil { + *m = make(M) + } + (*m)[k] = v +} + +{{ range $m := $.Messages }} +func (pm *{{ $m.ProtoType }}) FromOpenAPI(om {{ $m.OgenType }}) { + {{- range $f := $m.Fields -}} + {{ template "map_value_from" $f.Elem }} + {{ end -}} +} + +func (pm *{{ $m.ProtoType }}) ToOpenAPI() (om {{ $m.OgenType }}) { + {{- range $f := $m.Fields -}} + {{ template "map_value_to" $f.Elem }} + {{ end -}} + return om +} +{{ end }} + +{{ range $e := $.Enums }} +func (pm *{{ $e.ProtoType }}) FromOpenAPI(om {{ $e.OgenType }}) { + idx := {{ $e.EnumValueMap }}[string(om)] + *pm = {{ $e.ProtoType }}(idx) +} + +func (pm {{ $e.ProtoType }}) ToOpenAPI() {{ $e.OgenType }} { + name := {{ $e.EnumNameMap }}[int32(pm)] + return {{ $e.OgenType }}(name) +} +{{ end }} + +{{- end }} + + +{{ define "map_value_to" }} +{{ $t := $.Ogen }} +{{- if $.CheckProtoForNil -}} if {{ $.ProtoSel }} != nil {{- end }} { + {{- if $t.IsPointer }} + ogenVal := indirectOf({{ $.OgenSel }}) + {{- $elem := field_elem $t.PointerTo $.Proto "ogenVal" $.ProtoSel -}} + {{ template "map_value_to" $elem }} + {{ $.OgenSel }} = &ogenVal + {{- else if $t.IsGeneric }} + ogenVal := {{ $.OgenSel }}.Value + {{- $elem := field_elem $t.GenericOf $.Proto "ogenVal" $.ProtoSel -}} + {{ template "map_value_to" $elem }} + {{ $.OgenSel }}.SetTo(ogenVal) + {{- else if $t.IsArray }} + for _, protoVal := range {{ $.ProtoSel }} { + ogenElem := elemOf({{ $.OgenSel }}) + + {{- $elem := field_elem $t.Item $.Proto "ogenElem" "protoVal" -}} + {{ template "map_value_to" $elem }} + + {{ $.OgenSel }} = append({{ $.OgenSel }}, ogenElem) + } + {{- else if $t.IsMap }} + for key, protoVal := range {{ $.ProtoSel }} { + ogenElem := valueOf({{ $.OgenSel }}) + + {{- $elem := field_elem $t.Item $.Proto "ogenElem" "protoVal" -}} + {{ template "map_value_to" $elem }} + + insertMap(&{{ $.OgenSel }}, key, ogenElem) + } + {{- else if or ($t.IsStruct) ($t.IsAlias) }} + {{ $.OgenSel }} = {{ $.ProtoSel }}.ToOpenAPI() + {{- else if $t.IsEnum }} + {{ $.OgenSel }} = {{ $.ProtoSel }}.ToOpenAPI() + {{- else if $t.IsPrimitive }} + {{- if $.Ptr }} + {{ $.OgenSel }} = *{{ $.ProtoSel }} + {{- else }} + {{ $.OgenSel }} = {{ $.ProtoSel }} + {{- end }} + {{- else }} + {{ errorf "unsupported kind: %s" $t.Kind }} + {{- end }} +} +{{- end }} + +{{ define "map_value_from" }} + {{- $t := $.Ogen }} + {{- if $t.IsPointer }} + if {{ $.OgenSel }} != nil { + ogenVal := *{{ $.OgenSel }} + {{- $elem := field_elem $t.PointerTo $.Proto "ogenVal" $.ProtoSel -}} + {{ template "map_value_from" $elem }} + } + {{- else if $t.IsGeneric }} + if ogenVal, ok := {{ $.OgenSel }}.Get(); ok { + {{- $elem := field_elem $t.GenericOf $.Proto "ogenVal" $.ProtoSel -}} + {{ template "map_value_from" $elem }} + } + {{- else if $t.IsArray }} + for _, ogenVal := range {{ $.OgenSel }} { + protoVal := elemOf({{ $.ProtoSel }}) + + {{- $elem := field_elem $t.Item $.Proto "ogenVal" "protoVal" -}} + {{ template "map_value_from" $elem }} + + {{ $.ProtoSel }} = append({{ $.ProtoSel }}, protoVal) + } + {{- else if $t.IsMap }} + for key, ogenVal := range {{ $.OgenSel }} { + protoVal := valueOf({{ $.ProtoSel }}) + + {{- $elem := field_elem $t.Item $.Proto "ogenVal" "protoVal" -}} + {{ template "map_value_from" $elem }} + + insertMap(&{{ $.ProtoSel }}, key, protoVal) + } + {{- else if or ($t.IsStruct) ($t.IsAlias) }} + {{ $.ProtoSel }} = new({{ $.ProtoType }}) + {{ $.ProtoSel }}.FromOpenAPI({{ $.OgenSel }}) + {{- else if $t.IsEnum }} + {{ $.ProtoSel }} = new({{ $.ProtoType }}) + {{ $.ProtoSel }}.FromOpenAPI({{ $.OgenSel }}) + {{- else if $t.IsPrimitive }} + {{- if $.Ptr }} + {{ $.ProtoSel }} = &{{ $.OgenSel }} + {{- else }} + {{ $.ProtoSel }} = {{ $.OgenSel }} + {{- end }} + {{- else }} + {{ errorf "unsupported kind: %s" $t.Kind }} + {{- end }} +{{- end }} diff --git a/internal/gen/generator.go b/internal/gen/generator.go index ac894ec..90005f6 100644 --- a/internal/gen/generator.go +++ b/internal/gen/generator.go @@ -50,6 +50,19 @@ func NewGenerator(files []*protogen.File, opts ...GeneratorOption) (*Generator, g.spec.AddPathItem(tmpl, pi) } + ms, ok := g.ops[tmpl] + if !ok { + ms = &methodSet{ + Methods: map[string]methodRule{}, + } + g.ops[tmpl] = ms + } + ms.Methods[rule.Method] = methodRule{ + Rule: rule, + Method: m, + Service: s, + } + var to **ogen.Operation switch rule.Method { case http.MethodGet: @@ -98,12 +111,28 @@ func NewGenerator(files []*protogen.File, opts ...GeneratorOption) (*Generator, return g, nil } +type methodSet struct { + Template pathTemplate + // HTTP Method -> RPC Method. + Methods map[string]methodRule +} + +type methodRule struct { + Rule HTTPRule + Method *protogen.Method + Service *protogen.Service +} + // Generator instance. type Generator struct { spec *ogen.Spec indent int requests map[string]struct{} descriptorNames map[string]struct{} + + messages map[string]*protogen.Message + enums map[string]*protogen.Enum + ops map[string]*methodSet } // YAML returns OpenAPI specification bytes. @@ -128,8 +157,13 @@ func (g *Generator) JSON() ([]byte, error) { func (g *Generator) init() { g.spec = ogen.NewSpec() g.spec.Init() + g.requests = make(map[string]struct{}) g.descriptorNames = make(map[string]struct{}) + + g.messages = map[string]*protogen.Message{} + g.enums = map[string]*protogen.Enum{} + g.ops = map[string]*methodSet{} } func (g *Generator) mkMethod(rule HTTPRule, m *protogen.Method, deprecated bool) (string, *ogen.Operation, error) { diff --git a/internal/gen/generator_test.go b/internal/gen/generator_test.go index aec940a..e8aaee4 100644 --- a/internal/gen/generator_test.go +++ b/internal/gen/generator_test.go @@ -12,6 +12,7 @@ import ( "google.golang.org/protobuf/types/pluginpb" "github.com/go-faster/sdk/gold" + "github.com/ogen-go/ogen/openapi/parser" ) diff --git a/internal/gen/httprule.go b/internal/gen/httprule.go index d9b920d..4655050 100644 --- a/internal/gen/httprule.go +++ b/internal/gen/httprule.go @@ -35,8 +35,8 @@ func collectRules(opts protoreflect.ProtoMessage) (rules []HTTPRule) { return } rules = append(rules, HTTPRule{ - Method: method(rule), - Path: path(rule), + Method: ruleMethod(rule), + Path: rulePath(rule), Body: rule.Body, Additional: additional, }) @@ -49,7 +49,7 @@ func collectRules(opts protoreflect.ProtoMessage) (rules []HTTPRule) { return rules } -func method(httpRule *annotations.HttpRule) string { +func ruleMethod(httpRule *annotations.HttpRule) string { switch httpRule.Pattern.(type) { case *annotations.HttpRule_Get: return http.MethodGet @@ -71,7 +71,7 @@ func method(httpRule *annotations.HttpRule) string { } } -func path(httpRule *annotations.HttpRule) string { +func rulePath(httpRule *annotations.HttpRule) string { switch pattern := httpRule.Pattern.(type) { case *annotations.HttpRule_Get: return pattern.Get diff --git a/internal/gen/mapping.go b/internal/gen/mapping.go new file mode 100644 index 0000000..bc6cd23 --- /dev/null +++ b/internal/gen/mapping.go @@ -0,0 +1,130 @@ +package gen + +import ( + "google.golang.org/protobuf/compiler/protogen" + + "github.com/ogen-go/ogen/gen/ir" +) + +type packageImport struct { + Name protogen.GoPackageName + Path protogen.GoImportPath +} + +// TemplateConfig is a mapping template config. +type TemplateConfig struct { + Imports []packageImport + PackageName protogen.GoPackageName + Mapping +} + +// Mapping defines gRPC <-> OpenAPI mapping. +type Mapping struct { + Services []ServiceMapping + Messages []MessageMapping + Enums []EnumMapping +} + +// ServiceMapping defines gRPC service <-> OpenAPI operations mapping. +type ServiceMapping struct { + ProtoName string + ProtoServer string + Methods []MethodMapping +} + +// MethodMapping defines gRPC method <-> OpenAPI operation mapping. +type MethodMapping struct { + ProtoName string + OgenName string + OperationID string + ParamsType string + Input InputMapping + Output OutputMapping +} + +// InputMapping defines method input mapping. +type InputMapping struct { + ProtoType string + Path []FieldMapping + Query []FieldMapping + Body *BodyMapping +} + +// HasParams returns true if operation has any parameters. +func (m InputMapping) HasParams() bool { + return len(m.Path)+len(m.Query) > 0 +} + +// AllInBody returns true if whole message is inside the body. +func (m InputMapping) AllInBody() bool { + b := m.Body + return b != nil && b.Field == nil && !m.HasParams() +} + +// BodyMapping defines body mapping +type BodyMapping struct { + OgenType string + Ogen *ir.Request + Proto *protogen.Message + Field *FieldMapping +} + +// PassByPointer returns true if request is passed by pointer. +func (m BodyMapping) PassByPointer() bool { + return m.Ogen.Type.DoPassByPointer() +} + +// OutputMapping defines method output mapping. +type OutputMapping struct { + ProtoType string + OgenType string + Ogen *ir.Type + Proto *protogen.Message + Field *FieldMapping +} + +// AllInBody returns true if whole message is inside the body. +func (m OutputMapping) AllInBody() bool { + return m.Field == nil +} + +// PassByPointer returns true if request is passed by pointer. +func (m OutputMapping) PassByPointer() bool { + return m.Ogen.DoPassByPointer() +} + +// FieldMapping defines mapping between protobuf and ogen type fields. +type FieldMapping struct { + OgenName string + OgenType *ir.Type + Proto *protogen.Field +} + +// Elem returns elem for this field. +func (m FieldMapping) Elem() FieldElem { + ogenSel := "om" + if n := m.OgenName; n != "" { + ogenSel += "." + n + } + return FieldElem{ + Ogen: m.OgenType, + Proto: m.Proto, + OgenSel: ogenSel, + ProtoSel: "pm." + m.Proto.GoName, + } +} + +// MessageMapping defines message mapping. +type MessageMapping struct { + ProtoType string + OgenType string + Fields []FieldMapping +} + +// EnumMapping defines Enum mapping. +type EnumMapping struct { + ProtoType string + OgenType string + EnumNameMap string + EnumValueMap string +} diff --git a/internal/gen/proxy.go b/internal/gen/proxy.go new file mode 100644 index 0000000..50c90f0 --- /dev/null +++ b/internal/gen/proxy.go @@ -0,0 +1,316 @@ +package gen + +import ( + "bytes" + "fmt" + "os" + "path" + "strings" + "sync" + + "github.com/go-faster/errors" + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" + goimports "golang.org/x/tools/imports" + "google.golang.org/protobuf/compiler/protogen" + + "github.com/ogen-go/ogen/gen" + "github.com/ogen-go/ogen/gen/ir" + "github.com/ogen-go/ogen/jsonschema" +) + +type protocFS struct { + mux sync.Mutex + plugin *protogen.Plugin + importPath protogen.GoImportPath + dir string +} + +func (fs *protocFS) WriteFile(baseName string, source []byte) error { + fs.mux.Lock() + defer fs.mux.Unlock() + + // TODO(tdakkota): make output configurable + file := fs.plugin.NewGeneratedFile(path.Join(fs.dir, baseName), fs.importPath) + _, err := file.Write(source) + return err +} + +// WriteProxy runs ogen and generates ogen -> gRPC proxy. +func (g *Generator) WriteProxy(plugin *protogen.Plugin) error { + var out packageImport + for _, f := range plugin.Files { + if f.Generate { + out = packageImport{ + Name: f.GoPackageName, + Path: f.GoImportPath, + } + break + } + } + + imports := map[protogen.GoImportPath]packageImport{} + for _, f := range plugin.Files { + importPath := f.GoImportPath + if out.Path != importPath { + imports[importPath] = packageImport{ + Name: f.GoPackageName, + Path: importPath, + } + } + } + + og, err := gen.NewGenerator(g.spec, gen.Options{}) + if err != nil { + return err + } + + // TODO(tdakkota): make output configurable + oasPath := out.Path + "/oas" + fs := &protocFS{ + plugin: plugin, + importPath: oasPath, + dir: "oas", + } + if err := og.WriteSource(fs, "oas"); err != nil { + return errors.Wrap(err, "write ogen files") + } + imports[oasPath] = packageImport{ + Name: "oas", + Path: oasPath, + } + + mapping, err := g.mapSpec(og) + if err != nil { + return errors.Wrap(err, "map spec") + } + + tmpl := vendoredTemplates() + type generatedFile struct { + tmpl, name string + } + for _, file := range []generatedFile{ + {"messages", "messages.gen.go"}, + {"handler", "handler.gen.go"}, + } { + data := TemplateConfig{ + PackageName: out.Name, + Imports: maps.Values(imports), + Mapping: mapping, + } + + var buf bytes.Buffer + if err := tmpl.ExecuteTemplate(&buf, file.tmpl, data); err != nil { + return errors.Wrap(err, "execute template") + } + + formatted, err := goimports.Process(file.name, buf.Bytes(), nil) + if err != nil { + _ = os.WriteFile(file.name+".dump", buf.Bytes(), 0o600) + return errors.Wrap(err, "format mapping") + } + + f := plugin.NewGeneratedFile(file.name, out.Path) + if _, err := f.Write(formatted); err != nil { + return err + } + } + + return nil +} + +func (g *Generator) mapSpec(og *gen.Generator) (mapping Mapping, _ error) { + refName := func(ref jsonschema.Ref) string { + idx := strings.LastIndexByte(ref.Ptr, '/') + if idx < 0 { + panic(fmt.Sprintf("unexpected ref: %q", ref)) + } + return ref.Ptr[idx+1:] + } + + for _, typ := range og.Types() { + s := typ.Schema + if s == nil || s.Ref.IsZero() { + continue + } + + name := refName(s.Ref) + if m, ok := g.messages[name]; ok { + mapping.Messages = append(mapping.Messages, g.mapMessage(typ, m)) + continue + } + if e, ok := g.enums[name]; ok { + mapping.Enums = append(mapping.Enums, g.mapEnum(typ, e)) + continue + } + } + + services := map[*protogen.Service][]MethodMapping{} + for _, op := range og.Operations() { + tmpl := op.Spec.Path.String() + ms, ok := g.ops[tmpl] + if !ok { + panic(fmt.Sprintf("unknown path %q", tmpl)) + } + + httpMethod := strings.ToUpper(op.Spec.HTTPMethod) + rule, ok := ms.Methods[httpMethod] + if !ok { + panic(fmt.Sprintf("can't find gRPC method for %s %s", httpMethod, op.Spec.Path)) + } + + services[rule.Service] = append(services[rule.Service], g.mapMethod(op, rule)) + } + + for s, m := range services { + slices.SortStableFunc(m, func(a, b MethodMapping) bool { + return a.ProtoName < b.ProtoName + }) + mapping.Services = append(mapping.Services, ServiceMapping{ + ProtoName: s.GoName, + ProtoServer: s.GoName + "Server", + Methods: m, + }) + } + + // Ensure output is stable. + slices.SortStableFunc(mapping.Messages, func(a, b MessageMapping) bool { + return a.ProtoType < b.ProtoType + }) + slices.SortStableFunc(mapping.Enums, func(a, b EnumMapping) bool { + return a.ProtoType < b.ProtoType + }) + slices.SortStableFunc(mapping.Services, func(a, b ServiceMapping) bool { + return a.ProtoName < b.ProtoName + }) + return mapping, nil +} + +func qualifiedOgenType(pkg, typ string) string { + var prefix string +loop: + for i, c := range []byte(typ) { + switch c { + case '*', '[', ']': + default: + prefix = typ[:i] + typ = typ[i:] + break loop + } + } + return prefix + pkg + "." + typ +} + +func (g *Generator) mapMethod(ogenOp *ir.Operation, mr methodRule) MethodMapping { + input := g.mapInput(mr.Rule.Body, ogenOp, mr.Method.Input) + output := OutputMapping{ + ProtoType: mr.Method.Output.GoIdent.GoName, + OgenType: qualifiedOgenType("oas", ogenOp.Responses.GoType()), + Ogen: ogenOp.Responses.Type, + Proto: mr.Method.Output, + } + if b := mr.Rule.ResponseBody; b != "" && b != "*" { + output.Field = g.mapSelector(b, ogenOp.Responses.Type, mr.Method.Output) + } + m := MethodMapping{ + ProtoName: mr.Method.GoName, + OgenName: ogenOp.Name, + OperationID: ogenOp.Spec.OperationID, + ParamsType: qualifiedOgenType("oas", ogenOp.Name+"Params"), + Input: input, + Output: output, + } + return m +} + +func (g *Generator) mapInput(bodySel string, ogenOp *ir.Operation, msg *protogen.Message) (input InputMapping) { + input.ProtoType = msg.GoIdent.GoName + + pathParams := map[string]*ir.Parameter{} + for _, p := range ogenOp.Params { + if p.Spec.In.Path() { + pathParams[p.Spec.Name] = p + continue + } + } + + for _, f := range msg.Fields { + jsonName := f.Desc.JSONName() + p, ok := pathParams[jsonName] + if !ok { + continue + } + input.Path = append(input.Path, FieldMapping{ + OgenName: p.Name, + OgenType: p.Type, + Proto: f, + }) + } + + if req := ogenOp.Request; req != nil { + body := &BodyMapping{ + OgenType: qualifiedOgenType("oas", req.GoType()), + Proto: msg, + Ogen: req, + } + if b := bodySel; b != "" && b != "*" { + body.Field = g.mapSelector(b, ogenOp.Request.Type, msg) + } + input.Body = body + } + + return input +} + +func (g *Generator) mapSelector(sel string, ogenType *ir.Type, protoType *protogen.Message) *FieldMapping { + idx := slices.IndexFunc(protoType.Fields, func(f *protogen.Field) bool { + return f.Desc.TextName() == sel + }) + f := protoType.Fields[idx] + return &FieldMapping{ + OgenType: ogenType, + Proto: f, + } +} + +func (g *Generator) mapMessage(ogenType *ir.Type, protoType *protogen.Message) MessageMapping { + m := MessageMapping{ + ProtoType: protoType.GoIdent.GoName, + OgenType: qualifiedOgenType("oas", ogenType.Go()), + } + + ogenFields := make(map[string]*ir.Field, len(ogenType.Fields)) + for _, f := range ogenType.Fields { + ogenFields[f.Tag.JSON] = f + } + + for _, protoField := range protoType.Fields { + if o := protoField.Desc.ContainingOneof(); o != nil && !o.IsSynthetic() { + // FIXME(tdakkota): Skip oneOfs: we don't support them yet. + continue + } + jsonName := protoField.Desc.JSONName() + + ogenField, ok := ogenFields[jsonName] + if !ok { + panic(fmt.Sprintf("unknown JSON field %q (%s)", jsonName, protoField.Desc.FullName())) + } + + m.Fields = append(m.Fields, FieldMapping{ + OgenName: ogenField.Name, + OgenType: ogenField.Type, + Proto: protoField, + }) + } + return m +} + +func (g *Generator) mapEnum(o *ir.Type, p *protogen.Enum) EnumMapping { + protoType := p.GoIdent.GoName + return EnumMapping{ + ProtoType: protoType, + OgenType: qualifiedOgenType("oas", o.Go()), + EnumNameMap: protoType + "_name", + EnumValueMap: protoType + "_value", + } +} diff --git a/internal/gen/schema.go b/internal/gen/schema.go index f0bb909..e3342e4 100644 --- a/internal/gen/schema.go +++ b/internal/gen/schema.go @@ -3,6 +3,7 @@ package gen import ( "encoding/json" "fmt" + "strconv" "strings" "google.golang.org/protobuf/compiler/protogen" @@ -19,6 +20,8 @@ func (g *Generator) mkEnum(e *protogen.Enum) { name := descriptorName(e.Desc) g.spec.AddSchema(name, s) + + g.enums[name] = e } func enum(ed protoreflect.EnumDescriptor) []json.RawMessage { @@ -30,7 +33,8 @@ func enum(ed protoreflect.EnumDescriptor) []json.RawMessage { enum := make([]json.RawMessage, 0, values.Len()) for i := 0; i < values.Len(); i++ { - val := []byte(values.Get(i).Name()) + name := values.Get(i).Name() + val := strconv.AppendQuote(nil, string(name)) enum = append(enum, val) } @@ -89,6 +93,7 @@ func (g *Generator) mkSchema(msg *protogen.Message) error { name := descriptorName(msg.Desc) g.spec.AddSchema(name, s) + g.messages[name] = msg return nil } diff --git a/internal/gen/template.go b/internal/gen/template.go new file mode 100644 index 0000000..1c65162 --- /dev/null +++ b/internal/gen/template.go @@ -0,0 +1,92 @@ +package gen + +import ( + "embed" + "fmt" + "sync" + "text/template" + + "github.com/go-faster/errors" + "google.golang.org/protobuf/compiler/protogen" + "google.golang.org/protobuf/reflect/protoreflect" + + "github.com/ogen-go/ogen/gen/ir" +) + +type FieldElem struct { + Ogen *ir.Type + Proto *protogen.Field + OgenSel string + ProtoSel string +} + +// CheckProtoForNil whether mapper should check field for nil. +func (f FieldElem) CheckProtoForNil() bool { + return (f.Ogen.IsGeneric() && f.Ogen.GenericOf.IsMap()) || + (f.Ptr() && f.Ogen.Is(ir.KindPointer, ir.KindGeneric)) +} + +// ProtoType returns proto message or enum name. +func (f FieldElem) ProtoType() string { + var protoType func(f *protogen.Field) string + protoType = func(f *protogen.Field) string { + d := f.Desc + switch kind := d.Kind(); kind { + case protoreflect.MessageKind: + m := f.Message + if d.IsMap() { + return protoType(m.Fields[1]) + } + return m.GoIdent.GoName + case protoreflect.EnumKind: + return f.Enum.GoIdent.GoName + default: + panic(fmt.Sprintf("unexpected kind %q", kind)) + } + } + return protoType(f.Proto) +} + +// Ptr whether to use pointer when setting field. +func (f FieldElem) Ptr() bool { + fdesc := f.Proto.Desc + return fdesc.HasPresence() && + fdesc.Kind() != protoreflect.BytesKind +} + +//go:embed _template/* +var templates embed.FS + +var _templates struct { + sync.Once + val *template.Template +} + +// vendoredTemplates parses and returns vendored code generation templates. +func vendoredTemplates() *template.Template { + _templates.Do(func() { + tmpl := template.New("templates").Funcs(template.FuncMap{ + "field_elem": func( + o *ir.Type, + p *protogen.Field, + ogenSel string, + protoSel string, + ) FieldElem { + return FieldElem{ + Ogen: o, + Proto: p, + OgenSel: ogenSel, + ProtoSel: protoSel, + } + }, + "errorf": func(format string, args ...any) (any, error) { + return nil, errors.Errorf(format, args...) + }, + }) + tmpl = template.Must(tmpl.ParseFS(templates, + "_template/*.tmpl", + )) + _templates.val = tmpl + }) + return _templates.val +} From 0dd25696b222ffcba686e28d0c96460fd6413bf3 Mon Sep 17 00:00:00 2001 From: tdakkota Date: Fri, 19 May 2023 13:14:34 +0300 Subject: [PATCH 2/7] test: add integration test schema --- go.mod | 11 +- go.sum | 15 + integration/Makefile | 9 + integration/google/api/annotations.proto | 31 + integration/google/api/http.proto | 379 ++++ integration/google/protobuf/descriptor.proto | 1029 +++++++++ integration/proxy.proto | 123 ++ integration/proxypb/handler.gen.go | 77 + integration/proxypb/messages.gen.go | 697 ++++++ integration/proxypb/oas/oas_cfg_gen.go | 276 +++ integration/proxypb/oas/oas_client_gen.go | 329 +++ integration/proxypb/oas/oas_handlers_gen.go | 333 +++ integration/proxypb/oas/oas_json_gen.go | 1912 +++++++++++++++++ integration/proxypb/oas/oas_middleware_gen.go | 10 + integration/proxypb/oas/oas_parameters_gen.go | 81 + .../proxypb/oas/oas_request_decoders_gen.go | 154 ++ .../proxypb/oas/oas_request_encoders_gen.go | 46 + .../proxypb/oas/oas_response_decoders_gen.go | 138 ++ .../proxypb/oas/oas_response_encoders_gen.go | 54 + integration/proxypb/oas/oas_router_gen.go | 291 +++ integration/proxypb/oas/oas_schemas_gen.go | 1450 +++++++++++++ integration/proxypb/oas/oas_server_gen.go | 42 + .../proxypb/oas/oas_unimplemented_gen.go | 35 + integration/proxypb/oas/oas_validators_gen.go | 158 ++ integration/proxypb/openapi.yaml | 248 +++ integration/proxypb/proxy.pb.go | 1210 +++++++++++ integration/proxypb/proxy_grpc.pb.go | 183 ++ internal/gen/proxy.go | 17 +- 28 files changed, 9328 insertions(+), 10 deletions(-) create mode 100644 integration/Makefile create mode 100644 integration/google/api/annotations.proto create mode 100644 integration/google/api/http.proto create mode 100644 integration/google/protobuf/descriptor.proto create mode 100644 integration/proxy.proto create mode 100644 integration/proxypb/handler.gen.go create mode 100644 integration/proxypb/messages.gen.go create mode 100644 integration/proxypb/oas/oas_cfg_gen.go create mode 100644 integration/proxypb/oas/oas_client_gen.go create mode 100644 integration/proxypb/oas/oas_handlers_gen.go create mode 100644 integration/proxypb/oas/oas_json_gen.go create mode 100644 integration/proxypb/oas/oas_middleware_gen.go create mode 100644 integration/proxypb/oas/oas_parameters_gen.go create mode 100644 integration/proxypb/oas/oas_request_decoders_gen.go create mode 100644 integration/proxypb/oas/oas_request_encoders_gen.go create mode 100644 integration/proxypb/oas/oas_response_decoders_gen.go create mode 100644 integration/proxypb/oas/oas_response_encoders_gen.go create mode 100644 integration/proxypb/oas/oas_router_gen.go create mode 100644 integration/proxypb/oas/oas_schemas_gen.go create mode 100644 integration/proxypb/oas/oas_server_gen.go create mode 100644 integration/proxypb/oas/oas_unimplemented_gen.go create mode 100644 integration/proxypb/oas/oas_validators_gen.go create mode 100644 integration/proxypb/openapi.yaml create mode 100644 integration/proxypb/proxy.pb.go create mode 100644 integration/proxypb/proxy_grpc.pb.go diff --git a/go.mod b/go.mod index 4087db0..7e7384d 100644 --- a/go.mod +++ b/go.mod @@ -4,13 +4,19 @@ go 1.22.0 require ( github.com/go-faster/errors v0.7.1 + github.com/go-faster/jx v1.1.0 github.com/go-faster/sdk v0.15.1 github.com/go-faster/yaml v0.4.6 github.com/ogen-go/ogen v1.6.0 github.com/stretchr/testify v1.9.0 + go.opentelemetry.io/otel v1.31.0 + go.opentelemetry.io/otel/metric v1.31.0 + go.opentelemetry.io/otel/trace v1.31.0 + go.uber.org/multierr v1.11.0 golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c golang.org/x/tools v0.26.0 google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 + google.golang.org/grpc v1.67.1 google.golang.org/protobuf v1.35.1 ) @@ -19,19 +25,20 @@ require ( github.com/dlclark/regexp2 v1.11.4 // indirect github.com/fatih/color v1.18.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect - github.com/go-faster/jx v1.1.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/segmentio/asm v1.2.0 // indirect - go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.30.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/text v0.19.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 1180cb1..8e7950b 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,11 @@ github.com/go-faster/sdk v0.15.1 h1:zMIxy4eU5WRF5H3UM8FLSMU8XVRETV4gxpwVfW/v9p4= github.com/go-faster/sdk v0.15.1/go.mod h1:F9wNhIXkmuMXsGetkc2VIMBKVBoC1J3PNnRLj4PDiFk= github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I= github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -37,6 +42,12 @@ github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -61,6 +72,10 @@ golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 h1:2oV8dfuIkM1Ti7DwXc0BJfnwr9csz4TDXI9EmiI+Rbw= google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38/go.mod h1:vuAjtvlwkDKF6L1GQ0SokiRLCGFfeBUXWr/aFFkHACc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/integration/Makefile b/integration/Makefile new file mode 100644 index 0000000..5aa0208 --- /dev/null +++ b/integration/Makefile @@ -0,0 +1,9 @@ +generate-proxy: + go install -v ../cmd/protoc-gen-oas + mkdir -pv ./proxypb + protoc -I . \ + --oas_out=proxypb --oas_opt=proxy=true --oas_opt=paths=source_relative \ + --go_out=proxypb --go_opt=paths=source_relative \ + --go-grpc_out=proxypb --go-grpc_opt=paths=source_relative \ + proxy.proto +.PHONY: generate-proxy diff --git a/integration/google/api/annotations.proto b/integration/google/api/annotations.proto new file mode 100644 index 0000000..efdab3d --- /dev/null +++ b/integration/google/api/annotations.proto @@ -0,0 +1,31 @@ +// Copyright 2015 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/api/http.proto"; +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "AnnotationsProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +extend google.protobuf.MethodOptions { + // See `HttpRule`. + HttpRule http = 72295728; +} diff --git a/integration/google/api/http.proto b/integration/google/api/http.proto new file mode 100644 index 0000000..31d867a --- /dev/null +++ b/integration/google/api/http.proto @@ -0,0 +1,379 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "HttpProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Defines the HTTP configuration for an API service. It contains a list of +// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method +// to one or more HTTP REST API methods. +message Http { + // A list of HTTP configuration rules that apply to individual API methods. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated HttpRule rules = 1; + + // When set to true, URL path parameters will be fully URI-decoded except in + // cases of single segment matches in reserved expansion, where "%2F" will be + // left encoded. + // + // The default behavior is to not decode RFC 6570 reserved characters in multi + // segment matches. + bool fully_decode_reserved_expansion = 2; +} + +// # gRPC Transcoding +// +// gRPC Transcoding is a feature for mapping between a gRPC method and one or +// more HTTP REST endpoints. It allows developers to build a single API service +// that supports both gRPC APIs and REST APIs. Many systems, including [Google +// APIs](https://github.com/googleapis/googleapis), +// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC +// Gateway](https://github.com/grpc-ecosystem/grpc-gateway), +// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature +// and use it for large scale production services. +// +// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies +// how different portions of the gRPC request message are mapped to the URL +// path, URL query parameters, and HTTP request body. It also controls how the +// gRPC response message is mapped to the HTTP response body. `HttpRule` is +// typically specified as an `google.api.http` annotation on the gRPC method. +// +// Each mapping specifies a URL path template and an HTTP method. The path +// template may refer to one or more fields in the gRPC request message, as long +// as each field is a non-repeated field with a primitive (non-message) type. +// The path template controls how fields of the request message are mapped to +// the URL path. +// +// Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/{name=messages/*}" +// }; +// } +// } +// message GetMessageRequest { +// string name = 1; // Mapped to URL path. +// } +// message Message { +// string text = 1; // The resource content. +// } +// +// This enables an HTTP REST to gRPC mapping as below: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` +// +// Any fields in the request message which are not bound by the path template +// automatically become HTTP query parameters if there is no HTTP request body. +// For example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get:"/v1/messages/{message_id}" +// }; +// } +// } +// message GetMessageRequest { +// message SubMessage { +// string subfield = 1; +// } +// string message_id = 1; // Mapped to URL path. +// int64 revision = 2; // Mapped to URL query parameter `revision`. +// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. +// } +// +// This enables a HTTP JSON to RPC mapping as below: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | +// `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: +// "foo"))` +// +// Note that fields which are mapped to URL query parameters must have a +// primitive type or a repeated primitive type or a non-repeated message type. +// In the case of a repeated type, the parameter can be repeated in the URL +// as `...?param=A¶m=B`. In the case of a message type, each field of the +// message is mapped to a separate parameter, such as +// `...?foo.a=A&foo.b=B&foo.c=C`. +// +// For HTTP methods that allow a request body, the `body` field +// specifies the mapping. Consider a REST update method on the +// message resource collection: +// +// service Messaging { +// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "message" +// }; +// } +// } +// message UpdateMessageRequest { +// string message_id = 1; // mapped to the URL +// Message message = 2; // mapped to the body +// } +// +// The following HTTP JSON to RPC mapping is enabled, where the +// representation of the JSON in the request body is determined by +// protos JSON encoding: +// +// HTTP | gRPC +// -----|----- +// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +// "123456" message { text: "Hi!" })` +// +// The special name `*` can be used in the body mapping to define that +// every field not bound by the path template should be mapped to the +// request body. This enables the following alternative definition of +// the update method: +// +// service Messaging { +// rpc UpdateMessage(Message) returns (Message) { +// option (google.api.http) = { +// patch: "/v1/messages/{message_id}" +// body: "*" +// }; +// } +// } +// message Message { +// string message_id = 1; +// string text = 2; +// } +// +// +// The following HTTP JSON to RPC mapping is enabled: +// +// HTTP | gRPC +// -----|----- +// `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: +// "123456" text: "Hi!")` +// +// Note that when using `*` in the body mapping, it is not possible to +// have HTTP parameters, as all fields not bound by the path end in +// the body. This makes this option more rarely used in practice when +// defining REST APIs. The common usage of `*` is in custom methods +// which don't use the URL at all for transferring data. +// +// It is possible to define multiple HTTP methods for one RPC by using +// the `additional_bindings` option. Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/messages/{message_id}" +// additional_bindings { +// get: "/v1/users/{user_id}/messages/{message_id}" +// } +// }; +// } +// } +// message GetMessageRequest { +// string message_id = 1; +// string user_id = 2; +// } +// +// This enables the following two alternative HTTP JSON to RPC mappings: +// +// HTTP | gRPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` +// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: +// "123456")` +// +// ## Rules for HTTP mapping +// +// 1. Leaf request fields (recursive expansion nested messages in the request +// message) are classified into three categories: +// - Fields referred by the path template. They are passed via the URL path. +// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They +// are passed via the HTTP +// request body. +// - All other fields are passed via the URL query parameters, and the +// parameter name is the field path in the request message. A repeated +// field can be represented as multiple query parameters under the same +// name. +// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL +// query parameter, all fields +// are passed via URL path and HTTP request body. +// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP +// request body, all +// fields are passed via URL path and URL query parameters. +// +// ### Path template syntax +// +// Template = "/" Segments [ Verb ] ; +// Segments = Segment { "/" Segment } ; +// Segment = "*" | "**" | LITERAL | Variable ; +// Variable = "{" FieldPath [ "=" Segments ] "}" ; +// FieldPath = IDENT { "." IDENT } ; +// Verb = ":" LITERAL ; +// +// The syntax `*` matches a single URL path segment. The syntax `**` matches +// zero or more URL path segments, which must be the last part of the URL path +// except the `Verb`. +// +// The syntax `Variable` matches part of the URL path as specified by its +// template. A variable template must not contain other variables. If a variable +// matches a single path segment, its template may be omitted, e.g. `{var}` +// is equivalent to `{var=*}`. +// +// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` +// contains any reserved character, such characters should be percent-encoded +// before the matching. +// +// If a variable contains exactly one path segment, such as `"{var}"` or +// `"{var=*}"`, when such a variable is expanded into a URL path on the client +// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The +// server side does the reverse decoding. Such variables show up in the +// [Discovery +// Document](https://developers.google.com/discovery/v1/reference/apis) as +// `{var}`. +// +// If a variable contains multiple path segments, such as `"{var=foo/*}"` +// or `"{var=**}"`, when such a variable is expanded into a URL path on the +// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. +// The server side does the reverse decoding, except "%2F" and "%2f" are left +// unchanged. Such variables show up in the +// [Discovery +// Document](https://developers.google.com/discovery/v1/reference/apis) as +// `{+var}`. +// +// ## Using gRPC API Service Configuration +// +// gRPC API Service Configuration (service config) is a configuration language +// for configuring a gRPC service to become a user-facing product. The +// service config is simply the YAML representation of the `google.api.Service` +// proto message. +// +// As an alternative to annotating your proto file, you can configure gRPC +// transcoding in your service config YAML files. You do this by specifying a +// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same +// effect as the proto annotation. This can be particularly useful if you +// have a proto that is reused in multiple services. Note that any transcoding +// specified in the service config will override any matching transcoding +// configuration in the proto. +// +// Example: +// +// http: +// rules: +// # Selects a gRPC method and applies HttpRule to it. +// - selector: example.v1.Messaging.GetMessage +// get: /v1/messages/{message_id}/{sub.subfield} +// +// ## Special notes +// +// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the +// proto to JSON conversion must follow the [proto3 +// specification](https://developers.google.com/protocol-buffers/docs/proto3#json). +// +// While the single segment variable follows the semantics of +// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String +// Expansion, the multi segment variable **does not** follow RFC 6570 Section +// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion +// does not expand special characters like `?` and `#`, which would lead +// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding +// for multi segment variables. +// +// The path variables **must not** refer to any repeated or mapped field, +// because client libraries are not capable of handling such variable expansion. +// +// The path variables **must not** capture the leading "/" character. The reason +// is that the most common use case "{var}" does not capture the leading "/" +// character. For consistency, all path variables must share the same behavior. +// +// Repeated message fields must not be mapped to URL query parameters, because +// no client library can support such complicated mapping. +// +// If an API needs to use a JSON array for request or response body, it can map +// the request or response body to a repeated field. However, some gRPC +// Transcoding implementations may not support this feature. +message HttpRule { + // Selects a method to which this rule applies. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax + // details. + string selector = 1; + + // Determines the URL pattern is matched by this rules. This pattern can be + // used with any of the {get|put|post|delete|patch} methods. A custom method + // can be defined using the 'custom' field. + oneof pattern { + // Maps to HTTP GET. Used for listing and getting information about + // resources. + string get = 2; + + // Maps to HTTP PUT. Used for replacing a resource. + string put = 3; + + // Maps to HTTP POST. Used for creating a resource or performing an action. + string post = 4; + + // Maps to HTTP DELETE. Used for deleting a resource. + string delete = 5; + + // Maps to HTTP PATCH. Used for updating a resource. + string patch = 6; + + // The custom pattern is used for specifying an HTTP method that is not + // included in the `pattern` field, such as HEAD, or "*" to leave the + // HTTP method unspecified for this rule. The wild-card rule is useful + // for services that provide content to Web (HTML) clients. + CustomHttpPattern custom = 8; + } + + // The name of the request field whose value is mapped to the HTTP request + // body, or `*` for mapping all request fields not captured by the path + // pattern to the HTTP body, or omitted for not having any HTTP request body. + // + // NOTE: the referred field must be present at the top-level of the request + // message type. + string body = 7; + + // Optional. The name of the response field whose value is mapped to the HTTP + // response body. When omitted, the entire response message will be used + // as the HTTP response body. + // + // NOTE: The referred field must be present at the top-level of the response + // message type. + string response_body = 12; + + // Additional HTTP bindings for the selector. Nested bindings must + // not contain an `additional_bindings` field themselves (that is, + // the nesting may only be one level deep). + repeated HttpRule additional_bindings = 11; +} + +// A custom pattern is used for defining custom HTTP verb. +message CustomHttpPattern { + // The name of this custom HTTP verb. + string kind = 1; + + // The path matched by this custom verb. + string path = 2; +} diff --git a/integration/google/protobuf/descriptor.proto b/integration/google/protobuf/descriptor.proto new file mode 100644 index 0000000..16c10a6 --- /dev/null +++ b/integration/google/protobuf/descriptor.proto @@ -0,0 +1,1029 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// The messages in this file describe the definitions found in .proto files. +// A valid .proto file can be translated directly to a FileDescriptorProto +// without any other information (e.g. without reading its imports). + +syntax = "proto2"; + +package google.protobuf; + +option go_package = "google.golang.org/protobuf/types/descriptorpb"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "DescriptorProtos"; +option csharp_namespace = "Google.Protobuf.Reflection"; +option objc_class_prefix = "GPB"; +option cc_enable_arenas = true; + +// descriptor.proto must be optimized for speed because reflection-based +// algorithms don't work during bootstrapping. +option optimize_for = SPEED; + +// The protocol compiler can output a FileDescriptorSet containing the .proto +// files it parses. +message FileDescriptorSet { + repeated FileDescriptorProto file = 1; +} + +// Describes a complete .proto file. +message FileDescriptorProto { + optional string name = 1; // file name, relative to root of source tree + optional string package = 2; // e.g. "foo", "foo.bar", etc. + + // Names of files imported by this file. + repeated string dependency = 3; + // Indexes of the public imported files in the dependency list above. + repeated int32 public_dependency = 10; + // Indexes of the weak imported files in the dependency list. + // For Google-internal migration only. Do not use. + repeated int32 weak_dependency = 11; + + // All top-level definitions in this file. + repeated DescriptorProto message_type = 4; + repeated EnumDescriptorProto enum_type = 5; + repeated ServiceDescriptorProto service = 6; + repeated FieldDescriptorProto extension = 7; + + optional FileOptions options = 8; + + // This field contains optional information about the original source code. + // You may safely remove this entire field without harming runtime + // functionality of the descriptors -- the information is needed only by + // development tools. + optional SourceCodeInfo source_code_info = 9; + + // The syntax of the proto file. + // The supported values are "proto2", "proto3", and "editions". + // + // If `edition` is present, this value must be "editions". + optional string syntax = 12; + + // The edition of the proto file, which is an opaque string. + optional string edition = 13; +} + +// Describes a message type. +message DescriptorProto { + optional string name = 1; + + repeated FieldDescriptorProto field = 2; + repeated FieldDescriptorProto extension = 6; + + repeated DescriptorProto nested_type = 3; + repeated EnumDescriptorProto enum_type = 4; + + message ExtensionRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Exclusive. + + optional ExtensionRangeOptions options = 3; + } + repeated ExtensionRange extension_range = 5; + + repeated OneofDescriptorProto oneof_decl = 8; + + optional MessageOptions options = 7; + + // Range of reserved tag numbers. Reserved tag numbers may not be used by + // fields or extension ranges in the same message. Reserved ranges may + // not overlap. + message ReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Exclusive. + } + repeated ReservedRange reserved_range = 9; + // Reserved field names, which may not be used by fields in the same message. + // A given name may only be reserved once. + repeated string reserved_name = 10; +} + +message ExtensionRangeOptions { + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + message Declaration { + // The extension number declared within the extension range. + optional int32 number = 1; + + // The fully-qualified name of the extension field. There must be a leading + // dot in front of the full name. + optional string full_name = 2; + + // The fully-qualified type name of the extension field. Unlike + // Metadata.type, Declaration.type must have a leading dot for messages + // and enums. + optional string type = 3; + + // Deprecated. Please use "repeated". + optional bool is_repeated = 4 [deprecated = true]; + + // If true, indicates that the number is reserved in the extension range, + // and any extension field with the number will fail to compile. Set this + // when a declared extension field is deleted. + optional bool reserved = 5; + + // If true, indicates that the extension must be defined as repeated. + // Otherwise the extension must be defined as optional. + optional bool repeated = 6; + } + + // go/protobuf-stripping-extension-declarations + // Like Metadata, but we use a repeated field to hold all extension + // declarations. This should avoid the size increases of transforming a large + // extension range into small ranges in generated binaries. + repeated Declaration declaration = 2 [retention = RETENTION_SOURCE]; + + // The verification state of the extension range. + enum VerificationState { + // All the extensions of the range must be declared. + DECLARATION = 0; + UNVERIFIED = 1; + } + + // The verification state of the range. + // TODO(b/278783756): flip the default to DECLARATION once all empty ranges + // are marked as UNVERIFIED. + optional VerificationState verification = 3 [default = UNVERIFIED]; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +// Describes a field within a message. +message FieldDescriptorProto { + enum Type { + // 0 is reserved for errors. + // Order is weird for historical reasons. + TYPE_DOUBLE = 1; + TYPE_FLOAT = 2; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if + // negative values are likely. + TYPE_INT64 = 3; + TYPE_UINT64 = 4; + // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if + // negative values are likely. + TYPE_INT32 = 5; + TYPE_FIXED64 = 6; + TYPE_FIXED32 = 7; + TYPE_BOOL = 8; + TYPE_STRING = 9; + // Tag-delimited aggregate. + // Group type is deprecated and not supported in proto3. However, Proto3 + // implementations should still be able to parse the group wire format and + // treat group fields as unknown fields. + TYPE_GROUP = 10; + TYPE_MESSAGE = 11; // Length-delimited aggregate. + + // New in version 2. + TYPE_BYTES = 12; + TYPE_UINT32 = 13; + TYPE_ENUM = 14; + TYPE_SFIXED32 = 15; + TYPE_SFIXED64 = 16; + TYPE_SINT32 = 17; // Uses ZigZag encoding. + TYPE_SINT64 = 18; // Uses ZigZag encoding. + } + + enum Label { + // 0 is reserved for errors + LABEL_OPTIONAL = 1; + LABEL_REQUIRED = 2; + LABEL_REPEATED = 3; + } + + optional string name = 1; + optional int32 number = 3; + optional Label label = 4; + + // If type_name is set, this need not be set. If both this and type_name + // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. + optional Type type = 5; + + // For message and enum types, this is the name of the type. If the name + // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping + // rules are used to find the type (i.e. first the nested types within this + // message are searched, then within the parent, on up to the root + // namespace). + optional string type_name = 6; + + // For extensions, this is the name of the type being extended. It is + // resolved in the same manner as type_name. + optional string extendee = 2; + + // For numeric types, contains the original text representation of the value. + // For booleans, "true" or "false". + // For strings, contains the default text contents (not escaped in any way). + // For bytes, contains the C escaped value. All bytes >= 128 are escaped. + optional string default_value = 7; + + // If set, gives the index of a oneof in the containing type's oneof_decl + // list. This field is a member of that oneof. + optional int32 oneof_index = 9; + + // JSON name of this field. The value is set by protocol compiler. If the + // user has set a "json_name" option on this field, that option's value + // will be used. Otherwise, it's deduced from the field's name by converting + // it to camelCase. + optional string json_name = 10; + + optional FieldOptions options = 8; + + // If true, this is a proto3 "optional". When a proto3 field is optional, it + // tracks presence regardless of field type. + // + // When proto3_optional is true, this field must be belong to a oneof to + // signal to old proto3 clients that presence is tracked for this field. This + // oneof is known as a "synthetic" oneof, and this field must be its sole + // member (each proto3 optional field gets its own synthetic oneof). Synthetic + // oneofs exist in the descriptor only, and do not generate any API. Synthetic + // oneofs must be ordered after all "real" oneofs. + // + // For message fields, proto3_optional doesn't create any semantic change, + // since non-repeated message fields always track presence. However it still + // indicates the semantic detail of whether the user wrote "optional" or not. + // This can be useful for round-tripping the .proto file. For consistency we + // give message fields a synthetic oneof also, even though it is not required + // to track presence. This is especially important because the parser can't + // tell if a field is a message or an enum, so it must always create a + // synthetic oneof. + // + // Proto2 optional fields do not set this flag, because they already indicate + // optional with `LABEL_OPTIONAL`. + optional bool proto3_optional = 17; +} + +// Describes a oneof. +message OneofDescriptorProto { + optional string name = 1; + optional OneofOptions options = 2; +} + +// Describes an enum type. +message EnumDescriptorProto { + optional string name = 1; + + repeated EnumValueDescriptorProto value = 2; + + optional EnumOptions options = 3; + + // Range of reserved numeric values. Reserved values may not be used by + // entries in the same enum. Reserved ranges may not overlap. + // + // Note that this is distinct from DescriptorProto.ReservedRange in that it + // is inclusive such that it can appropriately represent the entire int32 + // domain. + message EnumReservedRange { + optional int32 start = 1; // Inclusive. + optional int32 end = 2; // Inclusive. + } + + // Range of reserved numeric values. Reserved numeric values may not be used + // by enum values in the same enum declaration. Reserved ranges may not + // overlap. + repeated EnumReservedRange reserved_range = 4; + + // Reserved enum value names, which may not be reused. A given name may only + // be reserved once. + repeated string reserved_name = 5; +} + +// Describes a value within an enum. +message EnumValueDescriptorProto { + optional string name = 1; + optional int32 number = 2; + + optional EnumValueOptions options = 3; +} + +// Describes a service. +message ServiceDescriptorProto { + optional string name = 1; + repeated MethodDescriptorProto method = 2; + + optional ServiceOptions options = 3; +} + +// Describes a method of a service. +message MethodDescriptorProto { + optional string name = 1; + + // Input and output type names. These are resolved in the same way as + // FieldDescriptorProto.type_name, but must refer to a message type. + optional string input_type = 2; + optional string output_type = 3; + + optional MethodOptions options = 4; + + // Identifies if client streams multiple client messages + optional bool client_streaming = 5 [default = false]; + // Identifies if server streams multiple server messages + optional bool server_streaming = 6 [default = false]; +} + +// =================================================================== +// Options + +// Each of the definitions above may have "options" attached. These are +// just annotations which may cause code to be generated slightly differently +// or may contain hints for code that manipulates protocol messages. +// +// Clients may define custom options as extensions of the *Options messages. +// These extensions may not yet be known at parsing time, so the parser cannot +// store the values in them. Instead it stores them in a field in the *Options +// message called uninterpreted_option. This field must have the same name +// across all *Options messages. We then use this field to populate the +// extensions when we build a descriptor, at which point all protos have been +// parsed and so all extensions are known. +// +// Extension numbers for custom options may be chosen as follows: +// * For options which will only be used within a single application or +// organization, or for experimental options, use field numbers 50000 +// through 99999. It is up to you to ensure that you do not use the +// same number for multiple options. +// * For options which will be published and used publicly by multiple +// independent entities, e-mail protobuf-global-extension-registry@google.com +// to reserve extension numbers. Simply provide your project name (e.g. +// Objective-C plugin) and your project website (if available) -- there's no +// need to explain how you intend to use them. Usually you only need one +// extension number. You can declare multiple options with only one extension +// number by putting them in a sub-message. See the Custom Options section of +// the docs for examples: +// https://developers.google.com/protocol-buffers/docs/proto#options +// If this turns out to be popular, a web service will be set up +// to automatically assign option numbers. + +message FileOptions { + + // Sets the Java package where classes generated from this .proto will be + // placed. By default, the proto package is used, but this is often + // inappropriate because proto packages do not normally start with backwards + // domain names. + optional string java_package = 1; + + // Controls the name of the wrapper Java class generated for the .proto file. + // That class will always contain the .proto file's getDescriptor() method as + // well as any top-level extensions defined in the .proto file. + // If java_multiple_files is disabled, then all the other classes from the + // .proto file will be nested inside the single wrapper outer class. + optional string java_outer_classname = 8; + + // If enabled, then the Java code generator will generate a separate .java + // file for each top-level message, enum, and service defined in the .proto + // file. Thus, these types will *not* be nested inside the wrapper class + // named by java_outer_classname. However, the wrapper class will still be + // generated to contain the file's getDescriptor() method as well as any + // top-level extensions defined in the file. + optional bool java_multiple_files = 10 [default = false]; + + // This option does nothing. + optional bool java_generate_equals_and_hash = 20 [deprecated=true]; + + // If set true, then the Java2 code generator will generate code that + // throws an exception whenever an attempt is made to assign a non-UTF-8 + // byte sequence to a string field. + // Message reflection will do the same. + // However, an extension field still accepts non-UTF-8 byte sequences. + // This option has no effect on when used with the lite runtime. + optional bool java_string_check_utf8 = 27 [default = false]; + + // Generated classes can be optimized for speed or code size. + enum OptimizeMode { + SPEED = 1; // Generate complete code for parsing, serialization, + // etc. + CODE_SIZE = 2; // Use ReflectionOps to implement these methods. + LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. + } + optional OptimizeMode optimize_for = 9 [default = SPEED]; + + // Sets the Go package where structs generated from this .proto will be + // placed. If omitted, the Go package will be derived from the following: + // - The basename of the package import path, if provided. + // - Otherwise, the package statement in the .proto file, if present. + // - Otherwise, the basename of the .proto file, without extension. + optional string go_package = 11; + + // Should generic services be generated in each language? "Generic" services + // are not specific to any particular RPC system. They are generated by the + // main code generators in each language (without additional plugins). + // Generic services were the only kind of service generation supported by + // early versions of google.protobuf. + // + // Generic services are now considered deprecated in favor of using plugins + // that generate code specific to your particular RPC system. Therefore, + // these default to false. Old code which depends on generic services should + // explicitly set them to true. + optional bool cc_generic_services = 16 [default = false]; + optional bool java_generic_services = 17 [default = false]; + optional bool py_generic_services = 18 [default = false]; + optional bool php_generic_services = 42 [default = false]; + + // Is this file deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for everything in the file, or it will be completely ignored; in the very + // least, this is a formalization for deprecating files. + optional bool deprecated = 23 [default = false]; + + // Enables the use of arenas for the proto messages in this file. This applies + // only to generated classes for C++. + optional bool cc_enable_arenas = 31 [default = true]; + + // Sets the objective c class prefix which is prepended to all objective c + // generated classes from this .proto. There is no default. + optional string objc_class_prefix = 36; + + // Namespace for generated classes; defaults to the package. + optional string csharp_namespace = 37; + + // By default Swift generators will take the proto package and CamelCase it + // replacing '.' with underscore and use that to prefix the types/symbols + // defined. When this options is provided, they will use this value instead + // to prefix the types/symbols defined. + optional string swift_prefix = 39; + + // Sets the php class prefix which is prepended to all php generated classes + // from this .proto. Default is empty. + optional string php_class_prefix = 40; + + // Use this option to change the namespace of php generated classes. Default + // is empty. When this option is empty, the package name will be used for + // determining the namespace. + optional string php_namespace = 41; + + // Use this option to change the namespace of php generated metadata classes. + // Default is empty. When this option is empty, the proto file name will be + // used for determining the namespace. + optional string php_metadata_namespace = 44; + + // Use this option to change the package of ruby generated classes. Default + // is empty. When this option is not set, the package name will be used for + // determining the ruby package. + optional string ruby_package = 45; + + // The parser stores options it doesn't recognize here. + // See the documentation for the "Options" section above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. + // See the documentation for the "Options" section above. + extensions 1000 to max; + + reserved 38; +} + +message MessageOptions { + // Set true to use the old proto1 MessageSet wire format for extensions. + // This is provided for backwards-compatibility with the MessageSet wire + // format. You should not use this for any other reason: It's less + // efficient, has fewer features, and is more complicated. + // + // The message must be defined exactly as follows: + // message Foo { + // option message_set_wire_format = true; + // extensions 4 to max; + // } + // Note that the message cannot have any defined fields; MessageSets only + // have extensions. + // + // All extensions of your type must be singular messages; e.g. they cannot + // be int32s, enums, or repeated messages. + // + // Because this is an option, the above two restrictions are not enforced by + // the protocol compiler. + optional bool message_set_wire_format = 1 [default = false]; + + // Disables the generation of the standard "descriptor()" accessor, which can + // conflict with a field of the same name. This is meant to make migration + // from proto1 easier; new code should avoid fields named "descriptor". + optional bool no_standard_descriptor_accessor = 2 [default = false]; + + // Is this message deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the message, or it will be completely ignored; in the very least, + // this is a formalization for deprecating messages. + optional bool deprecated = 3 [default = false]; + + reserved 4, 5, 6; + + // NOTE: Do not set the option in .proto files. Always use the maps syntax + // instead. The option should only be implicitly set by the proto compiler + // parser. + // + // Whether the message is an automatically generated map entry type for the + // maps field. + // + // For maps fields: + // map map_field = 1; + // The parsed descriptor looks like: + // message MapFieldEntry { + // option map_entry = true; + // optional KeyType key = 1; + // optional ValueType value = 2; + // } + // repeated MapFieldEntry map_field = 1; + // + // Implementations may choose not to generate the map_entry=true message, but + // use a native map in the target language to hold the keys and values. + // The reflection APIs in such implementations still need to work as + // if the field is a repeated message field. + optional bool map_entry = 7; + + reserved 8; // javalite_serializable + reserved 9; // javanano_as_lite + + // Enable the legacy handling of JSON field name conflicts. This lowercases + // and strips underscored from the fields before comparison in proto3 only. + // The new behavior takes `json_name` into account and applies to proto2 as + // well. + // + // This should only be used as a temporary measure against broken builds due + // to the change in behavior for JSON field name conflicts. + // + // TODO(b/261750190) This is legacy behavior we plan to remove once downstream + // teams have had time to migrate. + optional bool deprecated_legacy_json_field_conflicts = 11 [deprecated = true]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message FieldOptions { + // The ctype option instructs the C++ code generator to use a different + // representation of the field than it normally would. See the specific + // options below. This option is only implemented to support use of + // [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of + // type "bytes" in the open source release -- sorry, we'll try to include + // other types in a future version! + optional CType ctype = 1 [default = STRING]; + enum CType { + // Default mode. + STRING = 0; + + // The option [ctype=CORD] may be applied to a non-repeated field of type + // "bytes". It indicates that in C++, the data should be stored in a Cord + // instead of a string. For very large strings, this may reduce memory + // fragmentation. It may also allow better performance when parsing from a + // Cord, or when parsing with aliasing enabled, as the parsed Cord may then + // alias the original buffer. + CORD = 1; + + STRING_PIECE = 2; + } + // The packed option can be enabled for repeated primitive fields to enable + // a more efficient representation on the wire. Rather than repeatedly + // writing the tag and type for each element, the entire array is encoded as + // a single length-delimited blob. In proto3, only explicit setting it to + // false will avoid using packed encoding. + optional bool packed = 2; + + // The jstype option determines the JavaScript type used for values of the + // field. The option is permitted only for 64 bit integral and fixed types + // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING + // is represented as JavaScript string, which avoids loss of precision that + // can happen when a large value is converted to a floating point JavaScript. + // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to + // use the JavaScript "number" type. The behavior of the default option + // JS_NORMAL is implementation dependent. + // + // This option is an enum to permit additional types to be added, e.g. + // goog.math.Integer. + optional JSType jstype = 6 [default = JS_NORMAL]; + enum JSType { + // Use the default type. + JS_NORMAL = 0; + + // Use JavaScript strings. + JS_STRING = 1; + + // Use JavaScript numbers. + JS_NUMBER = 2; + } + + // Should this field be parsed lazily? Lazy applies only to message-type + // fields. It means that when the outer message is initially parsed, the + // inner message's contents will not be parsed but instead stored in encoded + // form. The inner message will actually be parsed when it is first accessed. + // + // This is only a hint. Implementations are free to choose whether to use + // eager or lazy parsing regardless of the value of this option. However, + // setting this option true suggests that the protocol author believes that + // using lazy parsing on this field is worth the additional bookkeeping + // overhead typically needed to implement it. + // + // This option does not affect the public interface of any generated code; + // all method signatures remain the same. Furthermore, thread-safety of the + // interface is not affected by this option; const methods remain safe to + // call from multiple threads concurrently, while non-const methods continue + // to require exclusive access. + // + // Note that implementations may choose not to check required fields within + // a lazy sub-message. That is, calling IsInitialized() on the outer message + // may return true even if the inner message has missing required fields. + // This is necessary because otherwise the inner message would have to be + // parsed in order to perform the check, defeating the purpose of lazy + // parsing. An implementation which chooses not to check required fields + // must be consistent about it. That is, for any particular sub-message, the + // implementation must either *always* check its required fields, or *never* + // check its required fields, regardless of whether or not the message has + // been parsed. + // + // As of May 2022, lazy verifies the contents of the byte stream during + // parsing. An invalid byte stream will cause the overall parsing to fail. + optional bool lazy = 5 [default = false]; + + // unverified_lazy does no correctness checks on the byte stream. This should + // only be used where lazy with verification is prohibitive for performance + // reasons. + optional bool unverified_lazy = 15 [default = false]; + + // Is this field deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for accessors, or it will be completely ignored; in the very least, this + // is a formalization for deprecating fields. + optional bool deprecated = 3 [default = false]; + + // For Google-internal migration only. Do not use. + optional bool weak = 10 [default = false]; + + // Indicate that the field value should not be printed out when using debug + // formats, e.g. when the field contains sensitive credentials. + optional bool debug_redact = 16 [default = false]; + + // If set to RETENTION_SOURCE, the option will be omitted from the binary. + // Note: as of January 2023, support for this is in progress and does not yet + // have an effect (b/264593489). + enum OptionRetention { + RETENTION_UNKNOWN = 0; + RETENTION_RUNTIME = 1; + RETENTION_SOURCE = 2; + } + + optional OptionRetention retention = 17; + + // This indicates the types of entities that the field may apply to when used + // as an option. If it is unset, then the field may be freely used as an + // option on any kind of entity. Note: as of January 2023, support for this is + // in progress and does not yet have an effect (b/264593489). + enum OptionTargetType { + TARGET_TYPE_UNKNOWN = 0; + TARGET_TYPE_FILE = 1; + TARGET_TYPE_EXTENSION_RANGE = 2; + TARGET_TYPE_MESSAGE = 3; + TARGET_TYPE_FIELD = 4; + TARGET_TYPE_ONEOF = 5; + TARGET_TYPE_ENUM = 6; + TARGET_TYPE_ENUM_ENTRY = 7; + TARGET_TYPE_SERVICE = 8; + TARGET_TYPE_METHOD = 9; + } + + repeated OptionTargetType targets = 19; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; + + reserved 4; // removed jtype + optional OptionTargetType target_obsolete_do_not_use = 18 [deprecated = true]; +} + +message OneofOptions { + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumOptions { + + // Set this option to true to allow mapping different tag names to the same + // value. + optional bool allow_alias = 2; + + // Is this enum deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum, or it will be completely ignored; in the very least, this + // is a formalization for deprecating enums. + optional bool deprecated = 3 [default = false]; + + reserved 5; // javanano_as_lite + + // Enable the legacy handling of JSON field name conflicts. This lowercases + // and strips underscored from the fields before comparison in proto3 only. + // The new behavior takes `json_name` into account and applies to proto2 as + // well. + // TODO(b/261750190) Remove this legacy behavior once downstream teams have + // had time to migrate. + optional bool deprecated_legacy_json_field_conflicts = 6 [deprecated = true]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message EnumValueOptions { + // Is this enum value deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the enum value, or it will be completely ignored; in the very least, + // this is a formalization for deprecating enum values. + optional bool deprecated = 1 [default = false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message ServiceOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this service deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the service, or it will be completely ignored; in the very least, + // this is a formalization for deprecating services. + optional bool deprecated = 33 [default = false]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +message MethodOptions { + + // Note: Field numbers 1 through 32 are reserved for Google's internal RPC + // framework. We apologize for hoarding these numbers to ourselves, but + // we were already using them long before we decided to release Protocol + // Buffers. + + // Is this method deprecated? + // Depending on the target platform, this can emit Deprecated annotations + // for the method, or it will be completely ignored; in the very least, + // this is a formalization for deprecating methods. + optional bool deprecated = 33 [default = false]; + + // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, + // or neither? HTTP based RPC implementation may choose GET verb for safe + // methods, and PUT verb for idempotent methods instead of the default POST. + enum IdempotencyLevel { + IDEMPOTENCY_UNKNOWN = 0; + NO_SIDE_EFFECTS = 1; // implies idempotent + IDEMPOTENT = 2; // idempotent, but may have side effects + } + optional IdempotencyLevel idempotency_level = 34 + [default = IDEMPOTENCY_UNKNOWN]; + + // The parser stores options it doesn't recognize here. See above. + repeated UninterpretedOption uninterpreted_option = 999; + + // Clients can define custom options in extensions of this message. See above. + extensions 1000 to max; +} + +// A message representing a option the parser does not recognize. This only +// appears in options protos created by the compiler::Parser class. +// DescriptorPool resolves these when building Descriptor objects. Therefore, +// options protos in descriptor objects (e.g. returned by Descriptor::options(), +// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions +// in them. +message UninterpretedOption { + // The name of the uninterpreted option. Each string represents a segment in + // a dot-separated name. is_extension is true iff a segment represents an + // extension (denoted with parentheses in options specs in .proto files). + // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents + // "foo.(bar.baz).moo". + message NamePart { + required string name_part = 1; + required bool is_extension = 2; + } + repeated NamePart name = 2; + + // The value of the uninterpreted option, in whatever type the tokenizer + // identified it as during parsing. Exactly one of these should be set. + optional string identifier_value = 3; + optional uint64 positive_int_value = 4; + optional int64 negative_int_value = 5; + optional double double_value = 6; + optional bytes string_value = 7; + optional string aggregate_value = 8; +} + +// =================================================================== +// Optional source code info + +// Encapsulates information about the original source file from which a +// FileDescriptorProto was generated. +message SourceCodeInfo { + // A Location identifies a piece of source code in a .proto file which + // corresponds to a particular definition. This information is intended + // to be useful to IDEs, code indexers, documentation generators, and similar + // tools. + // + // For example, say we have a file like: + // message Foo { + // optional string foo = 1; + // } + // Let's look at just the field definition: + // optional string foo = 1; + // ^ ^^ ^^ ^ ^^^ + // a bc de f ghi + // We have the following locations: + // span path represents + // [a,i) [ 4, 0, 2, 0 ] The whole field definition. + // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). + // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). + // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). + // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). + // + // Notes: + // - A location may refer to a repeated field itself (i.e. not to any + // particular index within it). This is used whenever a set of elements are + // logically enclosed in a single code segment. For example, an entire + // extend block (possibly containing multiple extension definitions) will + // have an outer location whose path refers to the "extensions" repeated + // field without an index. + // - Multiple locations may have the same path. This happens when a single + // logical declaration is spread out across multiple places. The most + // obvious example is the "extend" block again -- there may be multiple + // extend blocks in the same scope, each of which will have the same path. + // - A location's span is not always a subset of its parent's span. For + // example, the "extendee" of an extension declaration appears at the + // beginning of the "extend" block and is shared by all extensions within + // the block. + // - Just because a location's span is a subset of some other location's span + // does not mean that it is a descendant. For example, a "group" defines + // both a type and a field in a single declaration. Thus, the locations + // corresponding to the type and field and their components will overlap. + // - Code which tries to interpret locations should probably be designed to + // ignore those that it doesn't understand, as more types of locations could + // be recorded in the future. + repeated Location location = 1; + message Location { + // Identifies which part of the FileDescriptorProto was defined at this + // location. + // + // Each element is a field number or an index. They form a path from + // the root FileDescriptorProto to the place where the definition occurs. + // For example, this path: + // [ 4, 3, 2, 7, 1 ] + // refers to: + // file.message_type(3) // 4, 3 + // .field(7) // 2, 7 + // .name() // 1 + // This is because FileDescriptorProto.message_type has field number 4: + // repeated DescriptorProto message_type = 4; + // and DescriptorProto.field has field number 2: + // repeated FieldDescriptorProto field = 2; + // and FieldDescriptorProto.name has field number 1: + // optional string name = 1; + // + // Thus, the above path gives the location of a field name. If we removed + // the last element: + // [ 4, 3, 2, 7 ] + // this path refers to the whole field declaration (from the beginning + // of the label to the terminating semicolon). + repeated int32 path = 1 [packed = true]; + + // Always has exactly three or four elements: start line, start column, + // end line (optional, otherwise assumed same as start line), end column. + // These are packed into a single field for efficiency. Note that line + // and column numbers are zero-based -- typically you will want to add + // 1 to each before displaying to a user. + repeated int32 span = 2 [packed = true]; + + // If this SourceCodeInfo represents a complete declaration, these are any + // comments appearing before and after the declaration which appear to be + // attached to the declaration. + // + // A series of line comments appearing on consecutive lines, with no other + // tokens appearing on those lines, will be treated as a single comment. + // + // leading_detached_comments will keep paragraphs of comments that appear + // before (but not connected to) the current element. Each paragraph, + // separated by empty lines, will be one comment element in the repeated + // field. + // + // Only the comment content is provided; comment markers (e.g. //) are + // stripped out. For block comments, leading whitespace and an asterisk + // will be stripped from the beginning of each line other than the first. + // Newlines are included in the output. + // + // Examples: + // + // optional int32 foo = 1; // Comment attached to foo. + // // Comment attached to bar. + // optional int32 bar = 2; + // + // optional string baz = 3; + // // Comment attached to baz. + // // Another line attached to baz. + // + // // Comment attached to moo. + // // + // // Another line attached to moo. + // optional double moo = 4; + // + // // Detached comment for corge. This is not leading or trailing comments + // // to moo or corge because there are blank lines separating it from + // // both. + // + // // Detached comment for corge paragraph 2. + // + // optional string corge = 5; + // /* Block comment attached + // * to corge. Leading asterisks + // * will be removed. */ + // /* Block comment attached to + // * grault. */ + // optional int32 grault = 6; + // + // // ignored detached comments. + optional string leading_comments = 3; + optional string trailing_comments = 4; + repeated string leading_detached_comments = 6; + } +} + +// Describes the relationship between generated code and its original source +// file. A GeneratedCodeInfo message is associated with only one generated +// source file, but may contain references to different source .proto files. +message GeneratedCodeInfo { + // An Annotation connects some span of text in generated code to an element + // of its generating .proto file. + repeated Annotation annotation = 1; + message Annotation { + // Identifies the element in the original source .proto file. This field + // is formatted the same as SourceCodeInfo.Location.path. + repeated int32 path = 1 [packed = true]; + + // Identifies the filesystem path to the original source .proto. + optional string source_file = 2; + + // Identifies the starting offset in bytes in the generated code + // that relates to the identified object. + optional int32 begin = 3; + + // Identifies the ending offset in bytes in the generated code that + // relates to the identified object. The end offset should be one past + // the last relevant byte (so the length of the text = end - begin). + optional int32 end = 4; + + // Represents the identified object's effect on the element in the original + // .proto file. + enum Semantic { + // There is no effect or the effect is indescribable. + NONE = 0; + // The element is set or otherwise mutated. + SET = 1; + // An alias to the element is returned. + ALIAS = 2; + } + optional Semantic semantic = 5; + } +} diff --git a/integration/proxy.proto b/integration/proxy.proto new file mode 100644 index 0000000..eaea1c8 --- /dev/null +++ b/integration/proxy.proto @@ -0,0 +1,123 @@ +syntax = "proto3"; + +package proxypb; + +import "google/api/annotations.proto"; + +option go_package = "github.com/ogen-go/protoc-gen-oas/integration/proxypb;proxypb"; + +message ChildModel1 { + optional bool child_b1 = 44; + optional string child_str1 = 56; +} + +message ChildModel3 { + string sub_key = 1; + bool bool1 = 2; + int32 i32 = 3; + optional string opt_str = 4; + optional bool opt_bool = 5; + optional int32 opt_i32 = 6; +} + +enum TestEnum { + DEVICE_UNKNOWN = 0; + DEVICE_KEYBOARD = 1; + DEVICE_MOUSE = 2; + DEVICE_MONITOR = 3; +} + +message TestModel { + optional int32 value = 1; + repeated int32 value_array = 2; // _UPB_MODE_ARRAY + repeated int32 value_deprec = 4 [deprecated = true]; + optional string str1 = 115; + optional bool b1 = 9; + optional bool b2 = 10; + optional string str2 = 50; + optional string str3 = 11; + optional float optional_float = 14; + optional double optional_double = 15; + optional int64 optional_int64 = 16; + optional uint32 optional_uint32 = 17; + optional uint64 optional_uint64 = 18; + optional sint32 optional_sint32 = 19; + optional sint64 optional_sint64 = 20; + optional fixed32 optional_fixed32 = 21; + optional fixed64 optional_fixed64 = 22; + optional sfixed32 optional_sfixed32 = 23; + optional sfixed64 optional_sfixed64 = 24; + repeated int64 repeated_int64 = 25; + repeated uint64 repeated_uint64 = 26; + repeated fixed64 repeated_fixed64 = 27; + repeated sfixed64 repeated_sfixed64 = 28; + repeated bool repeated_bool = 29; + repeated string repeated_string = 35; + // optional bytes optional_bytes = 36; + message NestedChild { + optional string nested_child_name = 211; + } + optional NestedChild nested_child_1 = 212; + optional ChildModel1 child_model_1 = 222; + repeated ChildModel1 child_model_2 = 223; + optional ChildModel1 bar = 224; + oneof child_oneof1 { + string oneof_member1 = 98; + bool oneof_member2 = 99; + } + + optional TestModel recursive_child = 226; + map child_str_map = 227; + map str_to_int_map = 228; + map str_to_str_map = 229; + + enum Category { + UNKNOWN = 0; + IMAGES = 5; + NEWS = 6; + VIDEO = 7; + RADIO = 8 [deprecated = true]; + } + optional Category category = 37; + + // keyword collisions (double, template, ...) + oneof type { + string string = 230; + int64 int64 = 231; + double double = 232; + } + optional string template = 233; + optional string msg = 234; + optional string arena = 235; + + // Tests publicly imported enum. + optional TestEnum imported_enum = 238; + + optional string phase = 239; + optional bool clear_phase = 240; +} + +message StringMessage { + string value = 1; +} + +service APIService { + rpc Echo(StringMessage) returns (StringMessage) { + option (google.api.http) = { + post: "/echo" + body: "value" + }; + } + rpc TestModelEndpoint(TestModel) returns (TestModel) { + option (google.api.http) = { + post: "/testModel" + body: "*" + }; + } + rpc PathParam(StringMessage) returns (StringMessage) { + option (google.api.http) = { + post: "/pathParam/{value}" + body: "*" + }; + } +} diff --git a/integration/proxypb/handler.gen.go b/integration/proxypb/handler.gen.go new file mode 100644 index 0000000..d5b36f8 --- /dev/null +++ b/integration/proxypb/handler.gen.go @@ -0,0 +1,77 @@ +// Code generated by protoc-gen-oas, DO NOT EDIT. +package proxypb + +import ( + "context" + + oas "github.com/ogen-go/protoc-gen-oas/integration/proxypb/oas" +) + +// WrapperHandler is an oas.Handler implementation that maps request to gRPC server. +type WrapperHandler struct { + APIService APIServiceServer +} + +var _ oas.Handler = (*WrapperHandler)(nil) + +// Echo maps request to APIService.Echo. +func (h *WrapperHandler) Echo(ctx context.Context, req oas.OptString) (resp *oas.StringMessage, _ error) { + input := new(StringMessage) + h.mapEchoBodyInput(input, req) + output, err := h.APIService.Echo(ctx, input) + if err != nil { + return resp, err + } + return h.mapEchoOutput(output), nil +} + +func (h *WrapperHandler) mapEchoBodyInput(pm *StringMessage, om oas.OptString) { + if ogenVal, ok := om.Get(); ok { + pm.Value = ogenVal + } +} + +func (h *WrapperHandler) mapEchoOutput(pm *StringMessage) (om *oas.StringMessage) { + respVal := pm.ToOpenAPI() + return &respVal +} + +// PathParam maps request to APIService.PathParam. +func (h *WrapperHandler) PathParam(ctx context.Context, params oas.PathParamParams) (resp *oas.StringMessage, _ error) { + input := new(StringMessage) + h.mapPathParamParams(input, params) + output, err := h.APIService.PathParam(ctx, input) + if err != nil { + return resp, err + } + return h.mapPathParamOutput(output), nil +} + +func (h *WrapperHandler) mapPathParamParams(pm *StringMessage, om oas.PathParamParams) { + pm.Value = om.Value +} + +func (h *WrapperHandler) mapPathParamOutput(pm *StringMessage) (om *oas.StringMessage) { + respVal := pm.ToOpenAPI() + return &respVal +} + +// TestModelEndpoint maps request to APIService.TestModelEndpoint. +func (h *WrapperHandler) TestModelEndpoint(ctx context.Context, req *oas.TestModel) (resp *oas.TestModel, _ error) { + input := new(TestModel) + h.mapTestModelEndpointBodyInput(input, req) + output, err := h.APIService.TestModelEndpoint(ctx, input) + if err != nil { + return resp, err + } + return h.mapTestModelEndpointOutput(output), nil +} + +func (h *WrapperHandler) mapTestModelEndpointBodyInput(pm *TestModel, om *oas.TestModel) { + pm.FromOpenAPI(*om) +} + +func (h *WrapperHandler) mapTestModelEndpointOutput(pm *TestModel) (om *oas.TestModel) { + respVal := pm.ToOpenAPI() + return &respVal +} diff --git a/integration/proxypb/messages.gen.go b/integration/proxypb/messages.gen.go new file mode 100644 index 0000000..d5cf4c8 --- /dev/null +++ b/integration/proxypb/messages.gen.go @@ -0,0 +1,697 @@ +// Code generated by protoc-gen-oas, DO NOT EDIT. +package proxypb + +import ( + oas "github.com/ogen-go/protoc-gen-oas/integration/proxypb/oas" +) + +func indirectOf[P ~*T, T any](p P) (zero T) { + return zero +} + +func elemOf[S ~[]T, T any](s S) (zero T) { + return zero +} + +func valueOf[M ~map[K]V, K comparable, V any](m M) (zero V) { + return zero +} + +func initPtr[P ~*T, T any](p *P) { + var zero T + *p = &zero +} + +func insertMap[M ~map[K]V, K comparable, V any](m *M, k K, v V) { + if *m == nil { + *m = make(M) + } + (*m)[k] = v +} + +func (pm *ChildModel1) FromOpenAPI(om oas.ChildModel1) { + if ogenVal, ok := om.ChildB1.Get(); ok { + pm.ChildB1 = &ogenVal + } + + if ogenVal, ok := om.ChildStr1.Get(); ok { + pm.ChildStr1 = &ogenVal + } +} + +func (pm *ChildModel1) ToOpenAPI() (om oas.ChildModel1) { + if pm.ChildB1 != nil { + ogenVal := om.ChildB1.Value + { + ogenVal = *pm.ChildB1 + } + om.ChildB1.SetTo(ogenVal) + } + + if pm.ChildStr1 != nil { + ogenVal := om.ChildStr1.Value + { + ogenVal = *pm.ChildStr1 + } + om.ChildStr1.SetTo(ogenVal) + } + return om +} + +func (pm *StringMessage) FromOpenAPI(om oas.StringMessage) { + if ogenVal, ok := om.Value.Get(); ok { + pm.Value = ogenVal + } +} + +func (pm *StringMessage) ToOpenAPI() (om oas.StringMessage) { + { + ogenVal := om.Value.Value + { + ogenVal = pm.Value + } + om.Value.SetTo(ogenVal) + } + return om +} + +func (pm *TestModel) FromOpenAPI(om oas.TestModel) { + if ogenVal, ok := om.Value.Get(); ok { + pm.Value = &ogenVal + } + + for _, ogenVal := range om.ValueArray { + protoVal := elemOf(pm.ValueArray) + protoVal = ogenVal + + pm.ValueArray = append(pm.ValueArray, protoVal) + } + + for _, ogenVal := range om.ValueDeprec { + protoVal := elemOf(pm.ValueDeprec) + protoVal = ogenVal + + pm.ValueDeprec = append(pm.ValueDeprec, protoVal) + } + + if ogenVal, ok := om.Str1.Get(); ok { + pm.Str1 = &ogenVal + } + + if ogenVal, ok := om.B1.Get(); ok { + pm.B1 = &ogenVal + } + + if ogenVal, ok := om.B2.Get(); ok { + pm.B2 = &ogenVal + } + + if ogenVal, ok := om.Str2.Get(); ok { + pm.Str2 = &ogenVal + } + + if ogenVal, ok := om.Str3.Get(); ok { + pm.Str3 = &ogenVal + } + + if ogenVal, ok := om.OptionalFloat.Get(); ok { + pm.OptionalFloat = &ogenVal + } + + if ogenVal, ok := om.OptionalDouble.Get(); ok { + pm.OptionalDouble = &ogenVal + } + + if ogenVal, ok := om.OptionalInt64.Get(); ok { + pm.OptionalInt64 = &ogenVal + } + + if ogenVal, ok := om.OptionalUint32.Get(); ok { + pm.OptionalUint32 = &ogenVal + } + + if ogenVal, ok := om.OptionalUint64.Get(); ok { + pm.OptionalUint64 = &ogenVal + } + + if ogenVal, ok := om.OptionalSint32.Get(); ok { + pm.OptionalSint32 = &ogenVal + } + + if ogenVal, ok := om.OptionalSint64.Get(); ok { + pm.OptionalSint64 = &ogenVal + } + + if ogenVal, ok := om.OptionalFixed32.Get(); ok { + pm.OptionalFixed32 = &ogenVal + } + + if ogenVal, ok := om.OptionalFixed64.Get(); ok { + pm.OptionalFixed64 = &ogenVal + } + + if ogenVal, ok := om.OptionalSfixed32.Get(); ok { + pm.OptionalSfixed32 = &ogenVal + } + + if ogenVal, ok := om.OptionalSfixed64.Get(); ok { + pm.OptionalSfixed64 = &ogenVal + } + + for _, ogenVal := range om.RepeatedInt64 { + protoVal := elemOf(pm.RepeatedInt64) + protoVal = ogenVal + + pm.RepeatedInt64 = append(pm.RepeatedInt64, protoVal) + } + + for _, ogenVal := range om.RepeatedUint64 { + protoVal := elemOf(pm.RepeatedUint64) + protoVal = ogenVal + + pm.RepeatedUint64 = append(pm.RepeatedUint64, protoVal) + } + + for _, ogenVal := range om.RepeatedFixed64 { + protoVal := elemOf(pm.RepeatedFixed64) + protoVal = ogenVal + + pm.RepeatedFixed64 = append(pm.RepeatedFixed64, protoVal) + } + + for _, ogenVal := range om.RepeatedSfixed64 { + protoVal := elemOf(pm.RepeatedSfixed64) + protoVal = ogenVal + + pm.RepeatedSfixed64 = append(pm.RepeatedSfixed64, protoVal) + } + + for _, ogenVal := range om.RepeatedBool { + protoVal := elemOf(pm.RepeatedBool) + protoVal = ogenVal + + pm.RepeatedBool = append(pm.RepeatedBool, protoVal) + } + + for _, ogenVal := range om.RepeatedString { + protoVal := elemOf(pm.RepeatedString) + protoVal = ogenVal + + pm.RepeatedString = append(pm.RepeatedString, protoVal) + } + + if ogenVal, ok := om.NestedChild1.Get(); ok { + pm.NestedChild_1 = new(TestModel_NestedChild) + pm.NestedChild_1.FromOpenAPI(ogenVal) + } + + if ogenVal, ok := om.ChildModel1.Get(); ok { + pm.ChildModel_1 = new(ChildModel1) + pm.ChildModel_1.FromOpenAPI(ogenVal) + } + + for _, ogenVal := range om.ChildModel2 { + protoVal := elemOf(pm.ChildModel_2) + protoVal = new(ChildModel1) + protoVal.FromOpenAPI(ogenVal) + + pm.ChildModel_2 = append(pm.ChildModel_2, protoVal) + } + + if ogenVal, ok := om.Bar.Get(); ok { + pm.Bar = new(ChildModel1) + pm.Bar.FromOpenAPI(ogenVal) + } + + if om.RecursiveChild != nil { + ogenVal := *om.RecursiveChild + pm.RecursiveChild = new(TestModel) + pm.RecursiveChild.FromOpenAPI(ogenVal) + } + + if ogenVal, ok := om.ChildStrMap.Get(); ok { + for key, ogenVal := range ogenVal { + protoVal := valueOf(pm.ChildStrMap) + protoVal = new(ChildModel1) + protoVal.FromOpenAPI(ogenVal) + + insertMap(&pm.ChildStrMap, key, protoVal) + } + } + + if ogenVal, ok := om.StrToIntMap.Get(); ok { + for key, ogenVal := range ogenVal { + protoVal := valueOf(pm.StrToIntMap) + protoVal = ogenVal + + insertMap(&pm.StrToIntMap, key, protoVal) + } + } + + if ogenVal, ok := om.StrToStrMap.Get(); ok { + for key, ogenVal := range ogenVal { + protoVal := valueOf(pm.StrToStrMap) + protoVal = ogenVal + + insertMap(&pm.StrToStrMap, key, protoVal) + } + } + + if ogenVal, ok := om.Category.Get(); ok { + pm.Category = new(TestModel_Category) + pm.Category.FromOpenAPI(ogenVal) + } + + if ogenVal, ok := om.Template.Get(); ok { + pm.Template = &ogenVal + } + + if ogenVal, ok := om.Msg.Get(); ok { + pm.Msg = &ogenVal + } + + if ogenVal, ok := om.Arena.Get(); ok { + pm.Arena = &ogenVal + } + + if ogenVal, ok := om.ImportedEnum.Get(); ok { + pm.ImportedEnum = new(TestEnum) + pm.ImportedEnum.FromOpenAPI(ogenVal) + } + + if ogenVal, ok := om.Phase.Get(); ok { + pm.Phase = &ogenVal + } + + if ogenVal, ok := om.ClearPhase.Get(); ok { + pm.ClearPhase = &ogenVal + } +} + +func (pm *TestModel) ToOpenAPI() (om oas.TestModel) { + if pm.Value != nil { + ogenVal := om.Value.Value + { + ogenVal = *pm.Value + } + om.Value.SetTo(ogenVal) + } + + { + for _, protoVal := range pm.ValueArray { + ogenElem := elemOf(om.ValueArray) + { + ogenElem = protoVal + } + + om.ValueArray = append(om.ValueArray, ogenElem) + } + } + + { + for _, protoVal := range pm.ValueDeprec { + ogenElem := elemOf(om.ValueDeprec) + { + ogenElem = protoVal + } + + om.ValueDeprec = append(om.ValueDeprec, ogenElem) + } + } + + if pm.Str1 != nil { + ogenVal := om.Str1.Value + { + ogenVal = *pm.Str1 + } + om.Str1.SetTo(ogenVal) + } + + if pm.B1 != nil { + ogenVal := om.B1.Value + { + ogenVal = *pm.B1 + } + om.B1.SetTo(ogenVal) + } + + if pm.B2 != nil { + ogenVal := om.B2.Value + { + ogenVal = *pm.B2 + } + om.B2.SetTo(ogenVal) + } + + if pm.Str2 != nil { + ogenVal := om.Str2.Value + { + ogenVal = *pm.Str2 + } + om.Str2.SetTo(ogenVal) + } + + if pm.Str3 != nil { + ogenVal := om.Str3.Value + { + ogenVal = *pm.Str3 + } + om.Str3.SetTo(ogenVal) + } + + if pm.OptionalFloat != nil { + ogenVal := om.OptionalFloat.Value + { + ogenVal = *pm.OptionalFloat + } + om.OptionalFloat.SetTo(ogenVal) + } + + if pm.OptionalDouble != nil { + ogenVal := om.OptionalDouble.Value + { + ogenVal = *pm.OptionalDouble + } + om.OptionalDouble.SetTo(ogenVal) + } + + if pm.OptionalInt64 != nil { + ogenVal := om.OptionalInt64.Value + { + ogenVal = *pm.OptionalInt64 + } + om.OptionalInt64.SetTo(ogenVal) + } + + if pm.OptionalUint32 != nil { + ogenVal := om.OptionalUint32.Value + { + ogenVal = *pm.OptionalUint32 + } + om.OptionalUint32.SetTo(ogenVal) + } + + if pm.OptionalUint64 != nil { + ogenVal := om.OptionalUint64.Value + { + ogenVal = *pm.OptionalUint64 + } + om.OptionalUint64.SetTo(ogenVal) + } + + if pm.OptionalSint32 != nil { + ogenVal := om.OptionalSint32.Value + { + ogenVal = *pm.OptionalSint32 + } + om.OptionalSint32.SetTo(ogenVal) + } + + if pm.OptionalSint64 != nil { + ogenVal := om.OptionalSint64.Value + { + ogenVal = *pm.OptionalSint64 + } + om.OptionalSint64.SetTo(ogenVal) + } + + if pm.OptionalFixed32 != nil { + ogenVal := om.OptionalFixed32.Value + { + ogenVal = *pm.OptionalFixed32 + } + om.OptionalFixed32.SetTo(ogenVal) + } + + if pm.OptionalFixed64 != nil { + ogenVal := om.OptionalFixed64.Value + { + ogenVal = *pm.OptionalFixed64 + } + om.OptionalFixed64.SetTo(ogenVal) + } + + if pm.OptionalSfixed32 != nil { + ogenVal := om.OptionalSfixed32.Value + { + ogenVal = *pm.OptionalSfixed32 + } + om.OptionalSfixed32.SetTo(ogenVal) + } + + if pm.OptionalSfixed64 != nil { + ogenVal := om.OptionalSfixed64.Value + { + ogenVal = *pm.OptionalSfixed64 + } + om.OptionalSfixed64.SetTo(ogenVal) + } + + { + for _, protoVal := range pm.RepeatedInt64 { + ogenElem := elemOf(om.RepeatedInt64) + { + ogenElem = protoVal + } + + om.RepeatedInt64 = append(om.RepeatedInt64, ogenElem) + } + } + + { + for _, protoVal := range pm.RepeatedUint64 { + ogenElem := elemOf(om.RepeatedUint64) + { + ogenElem = protoVal + } + + om.RepeatedUint64 = append(om.RepeatedUint64, ogenElem) + } + } + + { + for _, protoVal := range pm.RepeatedFixed64 { + ogenElem := elemOf(om.RepeatedFixed64) + { + ogenElem = protoVal + } + + om.RepeatedFixed64 = append(om.RepeatedFixed64, ogenElem) + } + } + + { + for _, protoVal := range pm.RepeatedSfixed64 { + ogenElem := elemOf(om.RepeatedSfixed64) + { + ogenElem = protoVal + } + + om.RepeatedSfixed64 = append(om.RepeatedSfixed64, ogenElem) + } + } + + { + for _, protoVal := range pm.RepeatedBool { + ogenElem := elemOf(om.RepeatedBool) + { + ogenElem = protoVal + } + + om.RepeatedBool = append(om.RepeatedBool, ogenElem) + } + } + + { + for _, protoVal := range pm.RepeatedString { + ogenElem := elemOf(om.RepeatedString) + { + ogenElem = protoVal + } + + om.RepeatedString = append(om.RepeatedString, ogenElem) + } + } + + if pm.NestedChild_1 != nil { + ogenVal := om.NestedChild1.Value + { + ogenVal = pm.NestedChild_1.ToOpenAPI() + } + om.NestedChild1.SetTo(ogenVal) + } + + if pm.ChildModel_1 != nil { + ogenVal := om.ChildModel1.Value + { + ogenVal = pm.ChildModel_1.ToOpenAPI() + } + om.ChildModel1.SetTo(ogenVal) + } + + { + for _, protoVal := range pm.ChildModel_2 { + ogenElem := elemOf(om.ChildModel2) + { + ogenElem = protoVal.ToOpenAPI() + } + + om.ChildModel2 = append(om.ChildModel2, ogenElem) + } + } + + if pm.Bar != nil { + ogenVal := om.Bar.Value + { + ogenVal = pm.Bar.ToOpenAPI() + } + om.Bar.SetTo(ogenVal) + } + + if pm.RecursiveChild != nil { + ogenVal := indirectOf(om.RecursiveChild) + { + ogenVal = pm.RecursiveChild.ToOpenAPI() + } + om.RecursiveChild = &ogenVal + } + + if pm.ChildStrMap != nil { + ogenVal := om.ChildStrMap.Value + { + for key, protoVal := range pm.ChildStrMap { + ogenElem := valueOf(ogenVal) + { + ogenElem = protoVal.ToOpenAPI() + } + + insertMap(&ogenVal, key, ogenElem) + } + } + om.ChildStrMap.SetTo(ogenVal) + } + + if pm.StrToIntMap != nil { + ogenVal := om.StrToIntMap.Value + { + for key, protoVal := range pm.StrToIntMap { + ogenElem := valueOf(ogenVal) + { + ogenElem = protoVal + } + + insertMap(&ogenVal, key, ogenElem) + } + } + om.StrToIntMap.SetTo(ogenVal) + } + + if pm.StrToStrMap != nil { + ogenVal := om.StrToStrMap.Value + { + for key, protoVal := range pm.StrToStrMap { + ogenElem := valueOf(ogenVal) + { + ogenElem = protoVal + } + + insertMap(&ogenVal, key, ogenElem) + } + } + om.StrToStrMap.SetTo(ogenVal) + } + + if pm.Category != nil { + ogenVal := om.Category.Value + { + ogenVal = pm.Category.ToOpenAPI() + } + om.Category.SetTo(ogenVal) + } + + if pm.Template != nil { + ogenVal := om.Template.Value + { + ogenVal = *pm.Template + } + om.Template.SetTo(ogenVal) + } + + if pm.Msg != nil { + ogenVal := om.Msg.Value + { + ogenVal = *pm.Msg + } + om.Msg.SetTo(ogenVal) + } + + if pm.Arena != nil { + ogenVal := om.Arena.Value + { + ogenVal = *pm.Arena + } + om.Arena.SetTo(ogenVal) + } + + if pm.ImportedEnum != nil { + ogenVal := om.ImportedEnum.Value + { + ogenVal = pm.ImportedEnum.ToOpenAPI() + } + om.ImportedEnum.SetTo(ogenVal) + } + + if pm.Phase != nil { + ogenVal := om.Phase.Value + { + ogenVal = *pm.Phase + } + om.Phase.SetTo(ogenVal) + } + + if pm.ClearPhase != nil { + ogenVal := om.ClearPhase.Value + { + ogenVal = *pm.ClearPhase + } + om.ClearPhase.SetTo(ogenVal) + } + return om +} + +func (pm *TestModel_NestedChild) FromOpenAPI(om oas.TestModelNestedChild) { + if ogenVal, ok := om.NestedChildName.Get(); ok { + pm.NestedChildName = &ogenVal + } +} + +func (pm *TestModel_NestedChild) ToOpenAPI() (om oas.TestModelNestedChild) { + if pm.NestedChildName != nil { + ogenVal := om.NestedChildName.Value + { + ogenVal = *pm.NestedChildName + } + om.NestedChildName.SetTo(ogenVal) + } + return om +} + +func (pm *TestEnum) FromOpenAPI(om oas.TestEnum) { + idx := TestEnum_value[string(om)] + *pm = TestEnum(idx) +} + +func (pm TestEnum) ToOpenAPI() oas.TestEnum { + name := TestEnum_name[int32(pm)] + return oas.TestEnum(name) +} + +func (pm *TestModel_Category) FromOpenAPI(om oas.TestModelCategory) { + idx := TestModel_Category_value[string(om)] + *pm = TestModel_Category(idx) +} + +func (pm TestModel_Category) ToOpenAPI() oas.TestModelCategory { + name := TestModel_Category_name[int32(pm)] + return oas.TestModelCategory(name) +} diff --git a/integration/proxypb/oas/oas_cfg_gen.go b/integration/proxypb/oas/oas_cfg_gen.go new file mode 100644 index 0000000..ddeeee7 --- /dev/null +++ b/integration/proxypb/oas/oas_cfg_gen.go @@ -0,0 +1,276 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "net/http" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" + + ht "github.com/ogen-go/ogen/http" + "github.com/ogen-go/ogen/middleware" + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/otelogen" +) + +var ( + // Allocate option closure once. + clientSpanKind = trace.WithSpanKind(trace.SpanKindClient) + // Allocate option closure once. + serverSpanKind = trace.WithSpanKind(trace.SpanKindServer) +) + +type ( + optionFunc[C any] func(*C) + otelOptionFunc func(*otelConfig) +) + +type otelConfig struct { + TracerProvider trace.TracerProvider + Tracer trace.Tracer + MeterProvider metric.MeterProvider + Meter metric.Meter +} + +func (cfg *otelConfig) initOTEL() { + if cfg.TracerProvider == nil { + cfg.TracerProvider = otel.GetTracerProvider() + } + if cfg.MeterProvider == nil { + cfg.MeterProvider = otel.GetMeterProvider() + } + cfg.Tracer = cfg.TracerProvider.Tracer(otelogen.Name, + trace.WithInstrumentationVersion(otelogen.SemVersion()), + ) + cfg.Meter = cfg.MeterProvider.Meter(otelogen.Name) +} + +// ErrorHandler is error handler. +type ErrorHandler = ogenerrors.ErrorHandler + +type serverConfig struct { + otelConfig + NotFound http.HandlerFunc + MethodNotAllowed func(w http.ResponseWriter, r *http.Request, allowed string) + ErrorHandler ErrorHandler + Prefix string + Middleware Middleware + MaxMultipartMemory int64 +} + +// ServerOption is server config option. +type ServerOption interface { + applyServer(*serverConfig) +} + +var _ = []ServerOption{ + (optionFunc[serverConfig])(nil), + (otelOptionFunc)(nil), +} + +func (o optionFunc[C]) applyServer(c *C) { + o(c) +} + +func (o otelOptionFunc) applyServer(c *serverConfig) { + o(&c.otelConfig) +} + +func newServerConfig(opts ...ServerOption) serverConfig { + cfg := serverConfig{ + NotFound: http.NotFound, + MethodNotAllowed: func(w http.ResponseWriter, r *http.Request, allowed string) { + w.Header().Set("Allow", allowed) + w.WriteHeader(http.StatusMethodNotAllowed) + }, + ErrorHandler: ogenerrors.DefaultErrorHandler, + Middleware: nil, + MaxMultipartMemory: 32 << 20, // 32 MB + } + for _, opt := range opts { + opt.applyServer(&cfg) + } + cfg.initOTEL() + return cfg +} + +type baseServer struct { + cfg serverConfig + requests metric.Int64Counter + errors metric.Int64Counter + duration metric.Float64Histogram +} + +func (s baseServer) notFound(w http.ResponseWriter, r *http.Request) { + s.cfg.NotFound(w, r) +} + +func (s baseServer) notAllowed(w http.ResponseWriter, r *http.Request, allowed string) { + s.cfg.MethodNotAllowed(w, r, allowed) +} + +func (cfg serverConfig) baseServer() (s baseServer, err error) { + s = baseServer{cfg: cfg} + if s.requests, err = s.cfg.Meter.Int64Counter(otelogen.ServerRequestCount); err != nil { + return s, err + } + if s.errors, err = s.cfg.Meter.Int64Counter(otelogen.ServerErrorsCount); err != nil { + return s, err + } + if s.duration, err = s.cfg.Meter.Float64Histogram(otelogen.ServerDuration); err != nil { + return s, err + } + return s, nil +} + +type clientConfig struct { + otelConfig + Client ht.Client +} + +// ClientOption is client config option. +type ClientOption interface { + applyClient(*clientConfig) +} + +var _ = []ClientOption{ + (optionFunc[clientConfig])(nil), + (otelOptionFunc)(nil), +} + +func (o optionFunc[C]) applyClient(c *C) { + o(c) +} + +func (o otelOptionFunc) applyClient(c *clientConfig) { + o(&c.otelConfig) +} + +func newClientConfig(opts ...ClientOption) clientConfig { + cfg := clientConfig{ + Client: http.DefaultClient, + } + for _, opt := range opts { + opt.applyClient(&cfg) + } + cfg.initOTEL() + return cfg +} + +type baseClient struct { + cfg clientConfig + requests metric.Int64Counter + errors metric.Int64Counter + duration metric.Float64Histogram +} + +func (cfg clientConfig) baseClient() (c baseClient, err error) { + c = baseClient{cfg: cfg} + if c.requests, err = c.cfg.Meter.Int64Counter(otelogen.ClientRequestCount); err != nil { + return c, err + } + if c.errors, err = c.cfg.Meter.Int64Counter(otelogen.ClientErrorsCount); err != nil { + return c, err + } + if c.duration, err = c.cfg.Meter.Float64Histogram(otelogen.ClientDuration); err != nil { + return c, err + } + return c, nil +} + +// Option is config option. +type Option interface { + ServerOption + ClientOption +} + +// WithTracerProvider specifies a tracer provider to use for creating a tracer. +// +// If none is specified, the global provider is used. +func WithTracerProvider(provider trace.TracerProvider) Option { + return otelOptionFunc(func(cfg *otelConfig) { + if provider != nil { + cfg.TracerProvider = provider + } + }) +} + +// WithMeterProvider specifies a meter provider to use for creating a meter. +// +// If none is specified, the otel.GetMeterProvider() is used. +func WithMeterProvider(provider metric.MeterProvider) Option { + return otelOptionFunc(func(cfg *otelConfig) { + if provider != nil { + cfg.MeterProvider = provider + } + }) +} + +// WithClient specifies http client to use. +func WithClient(client ht.Client) ClientOption { + return optionFunc[clientConfig](func(cfg *clientConfig) { + if client != nil { + cfg.Client = client + } + }) +} + +// WithNotFound specifies Not Found handler to use. +func WithNotFound(notFound http.HandlerFunc) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + if notFound != nil { + cfg.NotFound = notFound + } + }) +} + +// WithMethodNotAllowed specifies Method Not Allowed handler to use. +func WithMethodNotAllowed(methodNotAllowed func(w http.ResponseWriter, r *http.Request, allowed string)) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + if methodNotAllowed != nil { + cfg.MethodNotAllowed = methodNotAllowed + } + }) +} + +// WithErrorHandler specifies error handler to use. +func WithErrorHandler(h ErrorHandler) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + if h != nil { + cfg.ErrorHandler = h + } + }) +} + +// WithPathPrefix specifies server path prefix. +func WithPathPrefix(prefix string) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + cfg.Prefix = prefix + }) +} + +// WithMiddleware specifies middlewares to use. +func WithMiddleware(m ...Middleware) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + switch len(m) { + case 0: + cfg.Middleware = nil + case 1: + cfg.Middleware = m[0] + default: + cfg.Middleware = middleware.ChainMiddlewares(m...) + } + }) +} + +// WithMaxMultipartMemory specifies limit of memory for storing file parts. +// File parts which can't be stored in memory will be stored on disk in temporary files. +func WithMaxMultipartMemory(max int64) ServerOption { + return optionFunc[serverConfig](func(cfg *serverConfig) { + if max > 0 { + cfg.MaxMultipartMemory = max + } + }) +} diff --git a/integration/proxypb/oas/oas_client_gen.go b/integration/proxypb/oas/oas_client_gen.go new file mode 100644 index 0000000..c688b4e --- /dev/null +++ b/integration/proxypb/oas/oas_client_gen.go @@ -0,0 +1,329 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "context" + "net/url" + "strings" + "time" + + "github.com/go-faster/errors" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/metric" + semconv "go.opentelemetry.io/otel/semconv/v1.19.0" + "go.opentelemetry.io/otel/trace" + + "github.com/ogen-go/ogen/conv" + ht "github.com/ogen-go/ogen/http" + "github.com/ogen-go/ogen/otelogen" + "github.com/ogen-go/ogen/uri" +) + +// Invoker invokes operations described by OpenAPI v3 specification. +type Invoker interface { + // Echo invokes echo operation. + // + // POST /echo + Echo(ctx context.Context, request OptString) (*StringMessage, error) + // PathParam invokes pathParam operation. + // + // POST /pathParam/{value} + PathParam(ctx context.Context, params PathParamParams) (*StringMessage, error) + // TestModelEndpoint invokes testModelEndpoint operation. + // + // POST /testModel + TestModelEndpoint(ctx context.Context, request *TestModel) (*TestModel, error) +} + +// Client implements OAS client. +type Client struct { + serverURL *url.URL + baseClient +} + +var _ Handler = struct { + *Client +}{} + +func trimTrailingSlashes(u *url.URL) { + u.Path = strings.TrimRight(u.Path, "/") + u.RawPath = strings.TrimRight(u.RawPath, "/") +} + +// NewClient initializes new Client defined by OAS. +func NewClient(serverURL string, opts ...ClientOption) (*Client, error) { + u, err := url.Parse(serverURL) + if err != nil { + return nil, err + } + trimTrailingSlashes(u) + + c, err := newClientConfig(opts...).baseClient() + if err != nil { + return nil, err + } + return &Client{ + serverURL: u, + baseClient: c, + }, nil +} + +type serverURLKey struct{} + +// WithServerURL sets context key to override server URL. +func WithServerURL(ctx context.Context, u *url.URL) context.Context { + return context.WithValue(ctx, serverURLKey{}, u) +} + +func (c *Client) requestURL(ctx context.Context) *url.URL { + u, ok := ctx.Value(serverURLKey{}).(*url.URL) + if !ok { + return c.serverURL + } + return u +} + +// Echo invokes echo operation. +// +// POST /echo +func (c *Client) Echo(ctx context.Context, request OptString) (*StringMessage, error) { + res, err := c.sendEcho(ctx, request) + return res, err +} + +func (c *Client) sendEcho(ctx context.Context, request OptString) (res *StringMessage, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("echo"), + semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/echo"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, "Echo", + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/echo" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + if err := encodeEchoRequest(request, r); err != nil { + return res, errors.Wrap(err, "encode request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeEchoResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// PathParam invokes pathParam operation. +// +// POST /pathParam/{value} +func (c *Client) PathParam(ctx context.Context, params PathParamParams) (*StringMessage, error) { + res, err := c.sendPathParam(ctx, params) + return res, err +} + +func (c *Client) sendPathParam(ctx context.Context, params PathParamParams) (res *StringMessage, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("pathParam"), + semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/pathParam/{value}"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, "PathParam", + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [2]string + pathParts[0] = "/pathParam/" + { + // Encode "value" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "value", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + return e.EncodeValue(conv.StringToString(params.Value)) + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodePathParamResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + +// TestModelEndpoint invokes testModelEndpoint operation. +// +// POST /testModel +func (c *Client) TestModelEndpoint(ctx context.Context, request *TestModel) (*TestModel, error) { + res, err := c.sendTestModelEndpoint(ctx, request) + return res, err +} + +func (c *Client) sendTestModelEndpoint(ctx context.Context, request *TestModel) (res *TestModel, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("testModelEndpoint"), + semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/testModel"), + } + // Validate request before sending. + if err := func() error { + if err := request.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, "TestModelEndpoint", + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [1]string + pathParts[0] = "/testModel" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + if err := encodeTestModelEndpointRequest(request, r); err != nil { + return res, errors.Wrap(err, "encode request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeTestModelEndpointResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} diff --git a/integration/proxypb/oas/oas_handlers_gen.go b/integration/proxypb/oas/oas_handlers_gen.go new file mode 100644 index 0000000..7555a42 --- /dev/null +++ b/integration/proxypb/oas/oas_handlers_gen.go @@ -0,0 +1,333 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "context" + "net/http" + "time" + + "github.com/go-faster/errors" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/metric" + semconv "go.opentelemetry.io/otel/semconv/v1.19.0" + "go.opentelemetry.io/otel/trace" + + ht "github.com/ogen-go/ogen/http" + "github.com/ogen-go/ogen/middleware" + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/otelogen" +) + +// handleEchoRequest handles echo operation. +// +// POST /echo +func (s *Server) handleEchoRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("echo"), + semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/echo"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), "Echo", + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: "Echo", + ID: "echo", + } + ) + request, close, err := s.decodeEchoRequest(r) + if err != nil { + err = &ogenerrors.DecodeRequestError{ + OperationContext: opErrContext, + Err: err, + } + recordError("DecodeRequest", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + defer func() { + if err := close(); err != nil { + recordError("CloseRequest", err) + } + }() + + var response *StringMessage + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: "Echo", + OperationSummary: "", + OperationID: "echo", + Body: request, + Params: middleware.Parameters{}, + Raw: r, + } + + type ( + Request = OptString + Params = struct{} + Response = *StringMessage + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + nil, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.Echo(ctx, request) + return response, err + }, + ) + } else { + response, err = s.h.Echo(ctx, request) + } + if err != nil { + recordError("Internal", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + + if err := encodeEchoResponse(response, w, span); err != nil { + recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handlePathParamRequest handles pathParam operation. +// +// POST /pathParam/{value} +func (s *Server) handlePathParamRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("pathParam"), + semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/pathParam/{value}"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), "PathParam", + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: "PathParam", + ID: "pathParam", + } + ) + params, err := decodePathParamParams(args, argsEscaped, r) + if err != nil { + err = &ogenerrors.DecodeParamsError{ + OperationContext: opErrContext, + Err: err, + } + recordError("DecodeParams", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + + var response *StringMessage + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: "PathParam", + OperationSummary: "", + OperationID: "pathParam", + Body: nil, + Params: middleware.Parameters{ + { + Name: "value", + In: "path", + }: params.Value, + }, + Raw: r, + } + + type ( + Request = struct{} + Params = PathParamParams + Response = *StringMessage + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackPathParamParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.PathParam(ctx, params) + return response, err + }, + ) + } else { + response, err = s.h.PathParam(ctx, params) + } + if err != nil { + recordError("Internal", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + + if err := encodePathParamResponse(response, w, span); err != nil { + recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + +// handleTestModelEndpointRequest handles testModelEndpoint operation. +// +// POST /testModel +func (s *Server) handleTestModelEndpointRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("testModelEndpoint"), + semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/testModel"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), "TestModelEndpoint", + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: "TestModelEndpoint", + ID: "testModelEndpoint", + } + ) + request, close, err := s.decodeTestModelEndpointRequest(r) + if err != nil { + err = &ogenerrors.DecodeRequestError{ + OperationContext: opErrContext, + Err: err, + } + recordError("DecodeRequest", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + defer func() { + if err := close(); err != nil { + recordError("CloseRequest", err) + } + }() + + var response *TestModel + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: "TestModelEndpoint", + OperationSummary: "", + OperationID: "testModelEndpoint", + Body: request, + Params: middleware.Parameters{}, + Raw: r, + } + + type ( + Request = *TestModel + Params = struct{} + Response = *TestModel + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + nil, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + response, err = s.h.TestModelEndpoint(ctx, request) + return response, err + }, + ) + } else { + response, err = s.h.TestModelEndpoint(ctx, request) + } + if err != nil { + recordError("Internal", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + + if err := encodeTestModelEndpointResponse(response, w, span); err != nil { + recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} diff --git a/integration/proxypb/oas/oas_json_gen.go b/integration/proxypb/oas/oas_json_gen.go new file mode 100644 index 0000000..2b10e29 --- /dev/null +++ b/integration/proxypb/oas/oas_json_gen.go @@ -0,0 +1,1912 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "github.com/go-faster/errors" + "github.com/go-faster/jx" +) + +// Encode implements json.Marshaler. +func (s *ChildModel1) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *ChildModel1) encodeFields(e *jx.Encoder) { + { + if s.ChildB1.Set { + e.FieldStart("childB1") + s.ChildB1.Encode(e) + } + } + { + if s.ChildStr1.Set { + e.FieldStart("childStr1") + s.ChildStr1.Encode(e) + } + } +} + +var jsonFieldsNameOfChildModel1 = [2]string{ + 0: "childB1", + 1: "childStr1", +} + +// Decode decodes ChildModel1 from json. +func (s *ChildModel1) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode ChildModel1 to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "childB1": + if err := func() error { + s.ChildB1.Reset() + if err := s.ChildB1.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"childB1\"") + } + case "childStr1": + if err := func() error { + s.ChildStr1.Reset() + if err := s.ChildStr1.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"childStr1\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode ChildModel1") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *ChildModel1) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *ChildModel1) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes bool as json. +func (o OptBool) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Bool(bool(o.Value)) +} + +// Decode decodes bool from json. +func (o *OptBool) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptBool to nil") + } + o.Set = true + v, err := d.Bool() + if err != nil { + return err + } + o.Value = bool(v) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptBool) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptBool) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes ChildModel1 as json. +func (o OptChildModel1) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes ChildModel1 from json. +func (o *OptChildModel1) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptChildModel1 to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptChildModel1) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptChildModel1) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes float32 as json. +func (o OptFloat32) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Float32(float32(o.Value)) +} + +// Decode decodes float32 from json. +func (o *OptFloat32) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptFloat32 to nil") + } + o.Set = true + v, err := d.Float32() + if err != nil { + return err + } + o.Value = float32(v) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptFloat32) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptFloat32) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes float64 as json. +func (o OptFloat64) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Float64(float64(o.Value)) +} + +// Decode decodes float64 from json. +func (o *OptFloat64) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptFloat64 to nil") + } + o.Set = true + v, err := d.Float64() + if err != nil { + return err + } + o.Value = float64(v) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptFloat64) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptFloat64) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes int32 as json. +func (o OptInt32) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Int32(int32(o.Value)) +} + +// Decode decodes int32 from json. +func (o *OptInt32) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptInt32 to nil") + } + o.Set = true + v, err := d.Int32() + if err != nil { + return err + } + o.Value = int32(v) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptInt32) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptInt32) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes int64 as json. +func (o OptInt64) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Int64(int64(o.Value)) +} + +// Decode decodes int64 from json. +func (o *OptInt64) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptInt64 to nil") + } + o.Set = true + v, err := d.Int64() + if err != nil { + return err + } + o.Value = int64(v) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptInt64) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptInt64) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes string as json. +func (o OptString) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Str(string(o.Value)) +} + +// Decode decodes string from json. +func (o *OptString) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptString to nil") + } + o.Set = true + v, err := d.Str() + if err != nil { + return err + } + o.Value = string(v) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptString) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptString) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes TestEnum as json. +func (o OptTestEnum) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Str(string(o.Value)) +} + +// Decode decodes TestEnum from json. +func (o *OptTestEnum) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptTestEnum to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptTestEnum) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptTestEnum) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes TestModelCategory as json. +func (o OptTestModelCategory) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.Str(string(o.Value)) +} + +// Decode decodes TestModelCategory from json. +func (o *OptTestModelCategory) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptTestModelCategory to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptTestModelCategory) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptTestModelCategory) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes TestModelChildStrMap as json. +func (o OptTestModelChildStrMap) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes TestModelChildStrMap from json. +func (o *OptTestModelChildStrMap) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptTestModelChildStrMap to nil") + } + o.Set = true + o.Value = make(TestModelChildStrMap) + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptTestModelChildStrMap) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptTestModelChildStrMap) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes TestModelNestedChild as json. +func (o OptTestModelNestedChild) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes TestModelNestedChild from json. +func (o *OptTestModelNestedChild) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptTestModelNestedChild to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptTestModelNestedChild) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptTestModelNestedChild) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes TestModelStrToIntMap as json. +func (o OptTestModelStrToIntMap) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes TestModelStrToIntMap from json. +func (o *OptTestModelStrToIntMap) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptTestModelStrToIntMap to nil") + } + o.Set = true + o.Value = make(TestModelStrToIntMap) + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptTestModelStrToIntMap) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptTestModelStrToIntMap) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes TestModelStrToStrMap as json. +func (o OptTestModelStrToStrMap) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes TestModelStrToStrMap from json. +func (o *OptTestModelStrToStrMap) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptTestModelStrToStrMap to nil") + } + o.Set = true + o.Value = make(TestModelStrToStrMap) + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptTestModelStrToStrMap) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptTestModelStrToStrMap) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes uint32 as json. +func (o OptUint32) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.UInt32(uint32(o.Value)) +} + +// Decode decodes uint32 from json. +func (o *OptUint32) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptUint32 to nil") + } + o.Set = true + v, err := d.UInt32() + if err != nil { + return err + } + o.Value = uint32(v) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptUint32) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptUint32) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes uint64 as json. +func (o OptUint64) Encode(e *jx.Encoder) { + if !o.Set { + return + } + e.UInt64(uint64(o.Value)) +} + +// Decode decodes uint64 from json. +func (o *OptUint64) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptUint64 to nil") + } + o.Set = true + v, err := d.UInt64() + if err != nil { + return err + } + o.Value = uint64(v) + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptUint64) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptUint64) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *StringMessage) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *StringMessage) encodeFields(e *jx.Encoder) { + { + if s.Value.Set { + e.FieldStart("value") + s.Value.Encode(e) + } + } +} + +var jsonFieldsNameOfStringMessage = [1]string{ + 0: "value", +} + +// Decode decodes StringMessage from json. +func (s *StringMessage) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode StringMessage to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "value": + if err := func() error { + s.Value.Reset() + if err := s.Value.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"value\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode StringMessage") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *StringMessage) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *StringMessage) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes TestEnum as json. +func (s TestEnum) Encode(e *jx.Encoder) { + e.Str(string(s)) +} + +// Decode decodes TestEnum from json. +func (s *TestEnum) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode TestEnum to nil") + } + v, err := d.StrBytes() + if err != nil { + return err + } + // Try to use constant string. + switch TestEnum(v) { + case TestEnumDEVICEUNKNOWN: + *s = TestEnumDEVICEUNKNOWN + case TestEnumDEVICEKEYBOARD: + *s = TestEnumDEVICEKEYBOARD + case TestEnumDEVICEMOUSE: + *s = TestEnumDEVICEMOUSE + case TestEnumDEVICEMONITOR: + *s = TestEnumDEVICEMONITOR + default: + *s = TestEnum(v) + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s TestEnum) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *TestEnum) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *TestModel) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *TestModel) encodeFields(e *jx.Encoder) { + { + if s.Value.Set { + e.FieldStart("value") + s.Value.Encode(e) + } + } + { + if s.ValueArray != nil { + e.FieldStart("valueArray") + e.ArrStart() + for _, elem := range s.ValueArray { + e.Int32(elem) + } + e.ArrEnd() + } + } + { + if s.ValueDeprec != nil { + e.FieldStart("valueDeprec") + e.ArrStart() + for _, elem := range s.ValueDeprec { + e.Int32(elem) + } + e.ArrEnd() + } + } + { + if s.Str1.Set { + e.FieldStart("str1") + s.Str1.Encode(e) + } + } + { + if s.B1.Set { + e.FieldStart("b1") + s.B1.Encode(e) + } + } + { + if s.B2.Set { + e.FieldStart("b2") + s.B2.Encode(e) + } + } + { + if s.Str2.Set { + e.FieldStart("str2") + s.Str2.Encode(e) + } + } + { + if s.Str3.Set { + e.FieldStart("str3") + s.Str3.Encode(e) + } + } + { + if s.OptionalFloat.Set { + e.FieldStart("optionalFloat") + s.OptionalFloat.Encode(e) + } + } + { + if s.OptionalDouble.Set { + e.FieldStart("optionalDouble") + s.OptionalDouble.Encode(e) + } + } + { + if s.OptionalInt64.Set { + e.FieldStart("optionalInt64") + s.OptionalInt64.Encode(e) + } + } + { + if s.OptionalUint32.Set { + e.FieldStart("optionalUint32") + s.OptionalUint32.Encode(e) + } + } + { + if s.OptionalUint64.Set { + e.FieldStart("optionalUint64") + s.OptionalUint64.Encode(e) + } + } + { + if s.OptionalSint32.Set { + e.FieldStart("optionalSint32") + s.OptionalSint32.Encode(e) + } + } + { + if s.OptionalSint64.Set { + e.FieldStart("optionalSint64") + s.OptionalSint64.Encode(e) + } + } + { + if s.OptionalFixed32.Set { + e.FieldStart("optionalFixed32") + s.OptionalFixed32.Encode(e) + } + } + { + if s.OptionalFixed64.Set { + e.FieldStart("optionalFixed64") + s.OptionalFixed64.Encode(e) + } + } + { + if s.OptionalSfixed32.Set { + e.FieldStart("optionalSfixed32") + s.OptionalSfixed32.Encode(e) + } + } + { + if s.OptionalSfixed64.Set { + e.FieldStart("optionalSfixed64") + s.OptionalSfixed64.Encode(e) + } + } + { + if s.RepeatedInt64 != nil { + e.FieldStart("repeatedInt64") + e.ArrStart() + for _, elem := range s.RepeatedInt64 { + e.Int64(elem) + } + e.ArrEnd() + } + } + { + if s.RepeatedUint64 != nil { + e.FieldStart("repeatedUint64") + e.ArrStart() + for _, elem := range s.RepeatedUint64 { + e.UInt64(elem) + } + e.ArrEnd() + } + } + { + if s.RepeatedFixed64 != nil { + e.FieldStart("repeatedFixed64") + e.ArrStart() + for _, elem := range s.RepeatedFixed64 { + e.UInt64(elem) + } + e.ArrEnd() + } + } + { + if s.RepeatedSfixed64 != nil { + e.FieldStart("repeatedSfixed64") + e.ArrStart() + for _, elem := range s.RepeatedSfixed64 { + e.Int64(elem) + } + e.ArrEnd() + } + } + { + if s.RepeatedBool != nil { + e.FieldStart("repeatedBool") + e.ArrStart() + for _, elem := range s.RepeatedBool { + e.Bool(elem) + } + e.ArrEnd() + } + } + { + if s.RepeatedString != nil { + e.FieldStart("repeatedString") + e.ArrStart() + for _, elem := range s.RepeatedString { + e.Str(elem) + } + e.ArrEnd() + } + } + { + if s.NestedChild1.Set { + e.FieldStart("nestedChild1") + s.NestedChild1.Encode(e) + } + } + { + if s.ChildModel1.Set { + e.FieldStart("childModel1") + s.ChildModel1.Encode(e) + } + } + { + if s.ChildModel2 != nil { + e.FieldStart("childModel2") + e.ArrStart() + for _, elem := range s.ChildModel2 { + elem.Encode(e) + } + e.ArrEnd() + } + } + { + if s.Bar.Set { + e.FieldStart("bar") + s.Bar.Encode(e) + } + } + { + if s.OneofMember1.Set { + e.FieldStart("oneofMember1") + s.OneofMember1.Encode(e) + } + } + { + if s.OneofMember2.Set { + e.FieldStart("oneofMember2") + s.OneofMember2.Encode(e) + } + } + { + if s.RecursiveChild != nil { + e.FieldStart("recursiveChild") + s.RecursiveChild.Encode(e) + } + } + { + if s.ChildStrMap.Set { + e.FieldStart("childStrMap") + s.ChildStrMap.Encode(e) + } + } + { + if s.StrToIntMap.Set { + e.FieldStart("strToIntMap") + s.StrToIntMap.Encode(e) + } + } + { + if s.StrToStrMap.Set { + e.FieldStart("strToStrMap") + s.StrToStrMap.Encode(e) + } + } + { + if s.Category.Set { + e.FieldStart("category") + s.Category.Encode(e) + } + } + { + if s.String.Set { + e.FieldStart("string") + s.String.Encode(e) + } + } + { + if s.Int64.Set { + e.FieldStart("int64") + s.Int64.Encode(e) + } + } + { + if s.Double.Set { + e.FieldStart("double") + s.Double.Encode(e) + } + } + { + if s.Template.Set { + e.FieldStart("template") + s.Template.Encode(e) + } + } + { + if s.Msg.Set { + e.FieldStart("msg") + s.Msg.Encode(e) + } + } + { + if s.Arena.Set { + e.FieldStart("arena") + s.Arena.Encode(e) + } + } + { + if s.ImportedEnum.Set { + e.FieldStart("importedEnum") + s.ImportedEnum.Encode(e) + } + } + { + if s.Phase.Set { + e.FieldStart("phase") + s.Phase.Encode(e) + } + } + { + if s.ClearPhase.Set { + e.FieldStart("clearPhase") + s.ClearPhase.Encode(e) + } + } +} + +var jsonFieldsNameOfTestModel = [45]string{ + 0: "value", + 1: "valueArray", + 2: "valueDeprec", + 3: "str1", + 4: "b1", + 5: "b2", + 6: "str2", + 7: "str3", + 8: "optionalFloat", + 9: "optionalDouble", + 10: "optionalInt64", + 11: "optionalUint32", + 12: "optionalUint64", + 13: "optionalSint32", + 14: "optionalSint64", + 15: "optionalFixed32", + 16: "optionalFixed64", + 17: "optionalSfixed32", + 18: "optionalSfixed64", + 19: "repeatedInt64", + 20: "repeatedUint64", + 21: "repeatedFixed64", + 22: "repeatedSfixed64", + 23: "repeatedBool", + 24: "repeatedString", + 25: "nestedChild1", + 26: "childModel1", + 27: "childModel2", + 28: "bar", + 29: "oneofMember1", + 30: "oneofMember2", + 31: "recursiveChild", + 32: "childStrMap", + 33: "strToIntMap", + 34: "strToStrMap", + 35: "category", + 36: "string", + 37: "int64", + 38: "double", + 39: "template", + 40: "msg", + 41: "arena", + 42: "importedEnum", + 43: "phase", + 44: "clearPhase", +} + +// Decode decodes TestModel from json. +func (s *TestModel) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode TestModel to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "value": + if err := func() error { + s.Value.Reset() + if err := s.Value.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"value\"") + } + case "valueArray": + if err := func() error { + s.ValueArray = make([]int32, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem int32 + v, err := d.Int32() + elem = int32(v) + if err != nil { + return err + } + s.ValueArray = append(s.ValueArray, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"valueArray\"") + } + case "valueDeprec": + if err := func() error { + s.ValueDeprec = make([]int32, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem int32 + v, err := d.Int32() + elem = int32(v) + if err != nil { + return err + } + s.ValueDeprec = append(s.ValueDeprec, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"valueDeprec\"") + } + case "str1": + if err := func() error { + s.Str1.Reset() + if err := s.Str1.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"str1\"") + } + case "b1": + if err := func() error { + s.B1.Reset() + if err := s.B1.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"b1\"") + } + case "b2": + if err := func() error { + s.B2.Reset() + if err := s.B2.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"b2\"") + } + case "str2": + if err := func() error { + s.Str2.Reset() + if err := s.Str2.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"str2\"") + } + case "str3": + if err := func() error { + s.Str3.Reset() + if err := s.Str3.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"str3\"") + } + case "optionalFloat": + if err := func() error { + s.OptionalFloat.Reset() + if err := s.OptionalFloat.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"optionalFloat\"") + } + case "optionalDouble": + if err := func() error { + s.OptionalDouble.Reset() + if err := s.OptionalDouble.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"optionalDouble\"") + } + case "optionalInt64": + if err := func() error { + s.OptionalInt64.Reset() + if err := s.OptionalInt64.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"optionalInt64\"") + } + case "optionalUint32": + if err := func() error { + s.OptionalUint32.Reset() + if err := s.OptionalUint32.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"optionalUint32\"") + } + case "optionalUint64": + if err := func() error { + s.OptionalUint64.Reset() + if err := s.OptionalUint64.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"optionalUint64\"") + } + case "optionalSint32": + if err := func() error { + s.OptionalSint32.Reset() + if err := s.OptionalSint32.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"optionalSint32\"") + } + case "optionalSint64": + if err := func() error { + s.OptionalSint64.Reset() + if err := s.OptionalSint64.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"optionalSint64\"") + } + case "optionalFixed32": + if err := func() error { + s.OptionalFixed32.Reset() + if err := s.OptionalFixed32.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"optionalFixed32\"") + } + case "optionalFixed64": + if err := func() error { + s.OptionalFixed64.Reset() + if err := s.OptionalFixed64.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"optionalFixed64\"") + } + case "optionalSfixed32": + if err := func() error { + s.OptionalSfixed32.Reset() + if err := s.OptionalSfixed32.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"optionalSfixed32\"") + } + case "optionalSfixed64": + if err := func() error { + s.OptionalSfixed64.Reset() + if err := s.OptionalSfixed64.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"optionalSfixed64\"") + } + case "repeatedInt64": + if err := func() error { + s.RepeatedInt64 = make([]int64, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem int64 + v, err := d.Int64() + elem = int64(v) + if err != nil { + return err + } + s.RepeatedInt64 = append(s.RepeatedInt64, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"repeatedInt64\"") + } + case "repeatedUint64": + if err := func() error { + s.RepeatedUint64 = make([]uint64, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem uint64 + v, err := d.UInt64() + elem = uint64(v) + if err != nil { + return err + } + s.RepeatedUint64 = append(s.RepeatedUint64, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"repeatedUint64\"") + } + case "repeatedFixed64": + if err := func() error { + s.RepeatedFixed64 = make([]uint64, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem uint64 + v, err := d.UInt64() + elem = uint64(v) + if err != nil { + return err + } + s.RepeatedFixed64 = append(s.RepeatedFixed64, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"repeatedFixed64\"") + } + case "repeatedSfixed64": + if err := func() error { + s.RepeatedSfixed64 = make([]int64, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem int64 + v, err := d.Int64() + elem = int64(v) + if err != nil { + return err + } + s.RepeatedSfixed64 = append(s.RepeatedSfixed64, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"repeatedSfixed64\"") + } + case "repeatedBool": + if err := func() error { + s.RepeatedBool = make([]bool, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem bool + v, err := d.Bool() + elem = bool(v) + if err != nil { + return err + } + s.RepeatedBool = append(s.RepeatedBool, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"repeatedBool\"") + } + case "repeatedString": + if err := func() error { + s.RepeatedString = make([]string, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem string + v, err := d.Str() + elem = string(v) + if err != nil { + return err + } + s.RepeatedString = append(s.RepeatedString, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"repeatedString\"") + } + case "nestedChild1": + if err := func() error { + s.NestedChild1.Reset() + if err := s.NestedChild1.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"nestedChild1\"") + } + case "childModel1": + if err := func() error { + s.ChildModel1.Reset() + if err := s.ChildModel1.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"childModel1\"") + } + case "childModel2": + if err := func() error { + s.ChildModel2 = make([]ChildModel1, 0) + if err := d.Arr(func(d *jx.Decoder) error { + var elem ChildModel1 + if err := elem.Decode(d); err != nil { + return err + } + s.ChildModel2 = append(s.ChildModel2, elem) + return nil + }); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"childModel2\"") + } + case "bar": + if err := func() error { + s.Bar.Reset() + if err := s.Bar.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"bar\"") + } + case "oneofMember1": + if err := func() error { + s.OneofMember1.Reset() + if err := s.OneofMember1.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"oneofMember1\"") + } + case "oneofMember2": + if err := func() error { + s.OneofMember2.Reset() + if err := s.OneofMember2.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"oneofMember2\"") + } + case "recursiveChild": + if err := func() error { + s.RecursiveChild = nil + var elem TestModel + if err := elem.Decode(d); err != nil { + return err + } + s.RecursiveChild = &elem + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"recursiveChild\"") + } + case "childStrMap": + if err := func() error { + s.ChildStrMap.Reset() + if err := s.ChildStrMap.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"childStrMap\"") + } + case "strToIntMap": + if err := func() error { + s.StrToIntMap.Reset() + if err := s.StrToIntMap.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"strToIntMap\"") + } + case "strToStrMap": + if err := func() error { + s.StrToStrMap.Reset() + if err := s.StrToStrMap.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"strToStrMap\"") + } + case "category": + if err := func() error { + s.Category.Reset() + if err := s.Category.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"category\"") + } + case "string": + if err := func() error { + s.String.Reset() + if err := s.String.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"string\"") + } + case "int64": + if err := func() error { + s.Int64.Reset() + if err := s.Int64.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"int64\"") + } + case "double": + if err := func() error { + s.Double.Reset() + if err := s.Double.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"double\"") + } + case "template": + if err := func() error { + s.Template.Reset() + if err := s.Template.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"template\"") + } + case "msg": + if err := func() error { + s.Msg.Reset() + if err := s.Msg.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"msg\"") + } + case "arena": + if err := func() error { + s.Arena.Reset() + if err := s.Arena.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"arena\"") + } + case "importedEnum": + if err := func() error { + s.ImportedEnum.Reset() + if err := s.ImportedEnum.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"importedEnum\"") + } + case "phase": + if err := func() error { + s.Phase.Reset() + if err := s.Phase.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"phase\"") + } + case "clearPhase": + if err := func() error { + s.ClearPhase.Reset() + if err := s.ClearPhase.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"clearPhase\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode TestModel") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *TestModel) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *TestModel) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode encodes TestModelCategory as json. +func (s TestModelCategory) Encode(e *jx.Encoder) { + e.Str(string(s)) +} + +// Decode decodes TestModelCategory from json. +func (s *TestModelCategory) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode TestModelCategory to nil") + } + v, err := d.StrBytes() + if err != nil { + return err + } + // Try to use constant string. + switch TestModelCategory(v) { + case TestModelCategoryUNKNOWN: + *s = TestModelCategoryUNKNOWN + case TestModelCategoryIMAGES: + *s = TestModelCategoryIMAGES + case TestModelCategoryNEWS: + *s = TestModelCategoryNEWS + case TestModelCategoryVIDEO: + *s = TestModelCategoryVIDEO + case TestModelCategoryRADIO: + *s = TestModelCategoryRADIO + default: + *s = TestModelCategory(v) + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s TestModelCategory) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *TestModelCategory) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s TestModelChildStrMap) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields implements json.Marshaler. +func (s TestModelChildStrMap) encodeFields(e *jx.Encoder) { + for k, elem := range s { + e.FieldStart(k) + + elem.Encode(e) + } +} + +// Decode decodes TestModelChildStrMap from json. +func (s *TestModelChildStrMap) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode TestModelChildStrMap to nil") + } + m := s.init() + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + var elem ChildModel1 + if err := func() error { + if err := elem.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrapf(err, "decode field %q", k) + } + m[string(k)] = elem + return nil + }); err != nil { + return errors.Wrap(err, "decode TestModelChildStrMap") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s TestModelChildStrMap) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *TestModelChildStrMap) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s *TestModelNestedChild) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields encodes fields. +func (s *TestModelNestedChild) encodeFields(e *jx.Encoder) { + { + if s.NestedChildName.Set { + e.FieldStart("nestedChildName") + s.NestedChildName.Encode(e) + } + } +} + +var jsonFieldsNameOfTestModelNestedChild = [1]string{ + 0: "nestedChildName", +} + +// Decode decodes TestModelNestedChild from json. +func (s *TestModelNestedChild) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode TestModelNestedChild to nil") + } + + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + switch string(k) { + case "nestedChildName": + if err := func() error { + s.NestedChildName.Reset() + if err := s.NestedChildName.Decode(d); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "decode field \"nestedChildName\"") + } + default: + return d.Skip() + } + return nil + }); err != nil { + return errors.Wrap(err, "decode TestModelNestedChild") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s *TestModelNestedChild) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *TestModelNestedChild) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s TestModelStrToIntMap) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields implements json.Marshaler. +func (s TestModelStrToIntMap) encodeFields(e *jx.Encoder) { + for k, elem := range s { + e.FieldStart(k) + + e.Int32(elem) + } +} + +// Decode decodes TestModelStrToIntMap from json. +func (s *TestModelStrToIntMap) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode TestModelStrToIntMap to nil") + } + m := s.init() + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + var elem int32 + if err := func() error { + v, err := d.Int32() + elem = int32(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrapf(err, "decode field %q", k) + } + m[string(k)] = elem + return nil + }); err != nil { + return errors.Wrap(err, "decode TestModelStrToIntMap") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s TestModelStrToIntMap) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *TestModelStrToIntMap) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + +// Encode implements json.Marshaler. +func (s TestModelStrToStrMap) Encode(e *jx.Encoder) { + e.ObjStart() + s.encodeFields(e) + e.ObjEnd() +} + +// encodeFields implements json.Marshaler. +func (s TestModelStrToStrMap) encodeFields(e *jx.Encoder) { + for k, elem := range s { + e.FieldStart(k) + + e.Str(elem) + } +} + +// Decode decodes TestModelStrToStrMap from json. +func (s *TestModelStrToStrMap) Decode(d *jx.Decoder) error { + if s == nil { + return errors.New("invalid: unable to decode TestModelStrToStrMap to nil") + } + m := s.init() + if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error { + var elem string + if err := func() error { + v, err := d.Str() + elem = string(v) + if err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrapf(err, "decode field %q", k) + } + m[string(k)] = elem + return nil + }); err != nil { + return errors.Wrap(err, "decode TestModelStrToStrMap") + } + + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s TestModelStrToStrMap) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *TestModelStrToStrMap) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} diff --git a/integration/proxypb/oas/oas_middleware_gen.go b/integration/proxypb/oas/oas_middleware_gen.go new file mode 100644 index 0000000..7ba299f --- /dev/null +++ b/integration/proxypb/oas/oas_middleware_gen.go @@ -0,0 +1,10 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "github.com/ogen-go/ogen/middleware" +) + +// Middleware is middleware type. +type Middleware = middleware.Middleware diff --git a/integration/proxypb/oas/oas_parameters_gen.go b/integration/proxypb/oas/oas_parameters_gen.go new file mode 100644 index 0000000..baa5e3c --- /dev/null +++ b/integration/proxypb/oas/oas_parameters_gen.go @@ -0,0 +1,81 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "net/http" + "net/url" + + "github.com/go-faster/errors" + + "github.com/ogen-go/ogen/conv" + "github.com/ogen-go/ogen/middleware" + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/uri" + "github.com/ogen-go/ogen/validate" +) + +// PathParamParams is parameters of pathParam operation. +type PathParamParams struct { + Value string +} + +func unpackPathParamParams(packed middleware.Parameters) (params PathParamParams) { + { + key := middleware.ParameterKey{ + Name: "value", + In: "path", + } + params.Value = packed[key].(string) + } + return params +} + +func decodePathParamParams(args [1]string, argsEscaped bool, r *http.Request) (params PathParamParams, _ error) { + // Decode path: value. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "value", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToString(val) + if err != nil { + return err + } + + params.Value = c + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "value", + In: "path", + Err: err, + } + } + return params, nil +} diff --git a/integration/proxypb/oas/oas_request_decoders_gen.go b/integration/proxypb/oas/oas_request_decoders_gen.go new file mode 100644 index 0000000..8f5b944 --- /dev/null +++ b/integration/proxypb/oas/oas_request_decoders_gen.go @@ -0,0 +1,154 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "io" + "mime" + "net/http" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + "go.uber.org/multierr" + + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/validate" +) + +func (s *Server) decodeEchoRequest(r *http.Request) ( + req OptString, + close func() error, + rerr error, +) { + var closers []func() error + close = func() error { + var merr error + // Close in reverse order, to match defer behavior. + for i := len(closers) - 1; i >= 0; i-- { + c := closers[i] + merr = multierr.Append(merr, c()) + } + return merr + } + defer func() { + if rerr != nil { + rerr = multierr.Append(rerr, close()) + } + }() + if _, ok := r.Header["Content-Type"]; !ok && r.ContentLength == 0 { + return req, close, nil + } + ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) + if err != nil { + return req, close, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + if r.ContentLength == 0 { + return req, close, nil + } + buf, err := io.ReadAll(r.Body) + if err != nil { + return req, close, err + } + + if len(buf) == 0 { + return req, close, nil + } + + d := jx.DecodeBytes(buf) + + var request OptString + if err := func() error { + request.Reset() + if err := request.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return req, close, err + } + return request, close, nil + default: + return req, close, validate.InvalidContentType(ct) + } +} + +func (s *Server) decodeTestModelEndpointRequest(r *http.Request) ( + req *TestModel, + close func() error, + rerr error, +) { + var closers []func() error + close = func() error { + var merr error + // Close in reverse order, to match defer behavior. + for i := len(closers) - 1; i >= 0; i-- { + c := closers[i] + merr = multierr.Append(merr, c()) + } + return merr + } + defer func() { + if rerr != nil { + rerr = multierr.Append(rerr, close()) + } + }() + ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) + if err != nil { + return req, close, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + if r.ContentLength == 0 { + return req, close, validate.ErrBodyRequired + } + buf, err := io.ReadAll(r.Body) + if err != nil { + return req, close, err + } + + if len(buf) == 0 { + return req, close, validate.ErrBodyRequired + } + + d := jx.DecodeBytes(buf) + + var request TestModel + if err := func() error { + if err := request.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return req, close, err + } + if err := func() error { + if err := request.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return req, close, errors.Wrap(err, "validate") + } + return &request, close, nil + default: + return req, close, validate.InvalidContentType(ct) + } +} diff --git a/integration/proxypb/oas/oas_request_encoders_gen.go b/integration/proxypb/oas/oas_request_encoders_gen.go new file mode 100644 index 0000000..8fa6eeb --- /dev/null +++ b/integration/proxypb/oas/oas_request_encoders_gen.go @@ -0,0 +1,46 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "bytes" + "net/http" + + "github.com/go-faster/jx" + + ht "github.com/ogen-go/ogen/http" +) + +func encodeEchoRequest( + req OptString, + r *http.Request, +) error { + const contentType = "application/json" + if !req.Set { + // Keep request with empty body if value is not set. + return nil + } + e := new(jx.Encoder) + { + if req.Set { + req.Encode(e) + } + } + encoded := e.Bytes() + ht.SetBody(r, bytes.NewReader(encoded), contentType) + return nil +} + +func encodeTestModelEndpointRequest( + req *TestModel, + r *http.Request, +) error { + const contentType = "application/json" + e := new(jx.Encoder) + { + req.Encode(e) + } + encoded := e.Bytes() + ht.SetBody(r, bytes.NewReader(encoded), contentType) + return nil +} diff --git a/integration/proxypb/oas/oas_response_decoders_gen.go b/integration/proxypb/oas/oas_response_decoders_gen.go new file mode 100644 index 0000000..7a925aa --- /dev/null +++ b/integration/proxypb/oas/oas_response_decoders_gen.go @@ -0,0 +1,138 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "io" + "mime" + "net/http" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + + "github.com/ogen-go/ogen/ogenerrors" + "github.com/ogen-go/ogen/validate" +) + +func decodeEchoResponse(resp *http.Response) (res *StringMessage, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response StringMessage + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + return res, validate.UnexpectedStatusCode(resp.StatusCode) +} + +func decodePathParamResponse(resp *http.Response) (res *StringMessage, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response StringMessage + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + return res, validate.UnexpectedStatusCode(resp.StatusCode) +} + +func decodeTestModelEndpointResponse(resp *http.Response) (res *TestModel, _ error) { + switch resp.StatusCode { + case 200: + // Code 200. + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response TestModel + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + return &response, nil + default: + return res, validate.InvalidContentType(ct) + } + } + return res, validate.UnexpectedStatusCode(resp.StatusCode) +} diff --git a/integration/proxypb/oas/oas_response_encoders_gen.go b/integration/proxypb/oas/oas_response_encoders_gen.go new file mode 100644 index 0000000..0473c83 --- /dev/null +++ b/integration/proxypb/oas/oas_response_encoders_gen.go @@ -0,0 +1,54 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "net/http" + + "github.com/go-faster/errors" + "github.com/go-faster/jx" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" +) + +func encodeEchoResponse(response *StringMessage, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil +} + +func encodePathParamResponse(response *StringMessage, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil +} + +func encodeTestModelEndpointResponse(response *TestModel, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + span.SetStatus(codes.Ok, http.StatusText(200)) + + e := new(jx.Encoder) + response.Encode(e) + if _, err := e.WriteTo(w); err != nil { + return errors.Wrap(err, "write") + } + + return nil +} diff --git a/integration/proxypb/oas/oas_router_gen.go b/integration/proxypb/oas/oas_router_gen.go new file mode 100644 index 0000000..3fc800f --- /dev/null +++ b/integration/proxypb/oas/oas_router_gen.go @@ -0,0 +1,291 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "net/http" + "net/url" + "strings" + + "github.com/ogen-go/ogen/uri" +) + +func (s *Server) cutPrefix(path string) (string, bool) { + prefix := s.cfg.Prefix + if prefix == "" { + return path, true + } + if !strings.HasPrefix(path, prefix) { + // Prefix doesn't match. + return "", false + } + // Cut prefix from the path. + return strings.TrimPrefix(path, prefix), true +} + +// ServeHTTP serves http request as defined by OpenAPI v3 specification, +// calling handler that matches the path or returning not found error. +func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + elem := r.URL.Path + elemIsEscaped := false + if rawPath := r.URL.RawPath; rawPath != "" { + if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok { + elem = normalized + elemIsEscaped = strings.ContainsRune(elem, '%') + } + } + + elem, ok := s.cutPrefix(elem) + if !ok || len(elem) == 0 { + s.notFound(w, r) + return + } + args := [1]string{} + + // Static code generated router with unwrapped path search. + switch { + default: + if len(elem) == 0 { + break + } + switch elem[0] { + case '/': // Prefix: "/" + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'e': // Prefix: "echo" + if l := len("echo"); len(elem) >= l && elem[0:l] == "echo" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleEchoRequest([0]string{}, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + case 'p': // Prefix: "pathParam/" + if l := len("pathParam/"); len(elem) >= l && elem[0:l] == "pathParam/" { + elem = elem[l:] + } else { + break + } + + // Param: "value" + // Leaf parameter + args[0] = elem + elem = "" + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handlePathParamRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + case 't': // Prefix: "testModel" + if l := len("testModel"); len(elem) >= l && elem[0:l] == "testModel" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleTestModelEndpointRequest([0]string{}, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + } + } + } + s.notFound(w, r) +} + +// Route is route object. +type Route struct { + name string + summary string + operationID string + pathPattern string + count int + args [1]string +} + +// Name returns ogen operation name. +// +// It is guaranteed to be unique and not empty. +func (r Route) Name() string { + return r.name +} + +// Summary returns OpenAPI summary. +func (r Route) Summary() string { + return r.summary +} + +// OperationID returns OpenAPI operationId. +func (r Route) OperationID() string { + return r.operationID +} + +// PathPattern returns OpenAPI path. +func (r Route) PathPattern() string { + return r.pathPattern +} + +// Args returns parsed arguments. +func (r Route) Args() []string { + return r.args[:r.count] +} + +// FindRoute finds Route for given method and path. +// +// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead. +func (s *Server) FindRoute(method, path string) (Route, bool) { + return s.FindPath(method, &url.URL{Path: path}) +} + +// FindPath finds Route for given method and URL. +func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { + var ( + elem = u.Path + args = r.args + ) + if rawPath := u.RawPath; rawPath != "" { + if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok { + elem = normalized + } + defer func() { + for i, arg := range r.args[:r.count] { + if unescaped, err := url.PathUnescape(arg); err == nil { + r.args[i] = unescaped + } + } + }() + } + + elem, ok := s.cutPrefix(elem) + if !ok { + return r, false + } + + // Static code generated router with unwrapped path search. + switch { + default: + if len(elem) == 0 { + break + } + switch elem[0] { + case '/': // Prefix: "/" + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + break + } + switch elem[0] { + case 'e': // Prefix: "echo" + if l := len("echo"); len(elem) >= l && elem[0:l] == "echo" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + switch method { + case "POST": + // Leaf: Echo + r.name = "Echo" + r.summary = "" + r.operationID = "echo" + r.pathPattern = "/echo" + r.args = args + r.count = 0 + return r, true + default: + return + } + } + case 'p': // Prefix: "pathParam/" + if l := len("pathParam/"); len(elem) >= l && elem[0:l] == "pathParam/" { + elem = elem[l:] + } else { + break + } + + // Param: "value" + // Leaf parameter + args[0] = elem + elem = "" + + if len(elem) == 0 { + switch method { + case "POST": + // Leaf: PathParam + r.name = "PathParam" + r.summary = "" + r.operationID = "pathParam" + r.pathPattern = "/pathParam/{value}" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + case 't': // Prefix: "testModel" + if l := len("testModel"); len(elem) >= l && elem[0:l] == "testModel" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + switch method { + case "POST": + // Leaf: TestModelEndpoint + r.name = "TestModelEndpoint" + r.summary = "" + r.operationID = "testModelEndpoint" + r.pathPattern = "/testModel" + r.args = args + r.count = 0 + return r, true + default: + return + } + } + } + } + } + return r, false +} diff --git a/integration/proxypb/oas/oas_schemas_gen.go b/integration/proxypb/oas/oas_schemas_gen.go new file mode 100644 index 0000000..8a32a18 --- /dev/null +++ b/integration/proxypb/oas/oas_schemas_gen.go @@ -0,0 +1,1450 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "github.com/go-faster/errors" +) + +// Ref: #/components/schemas/ChildModel1 +type ChildModel1 struct { + ChildB1 OptBool `json:"childB1"` + ChildStr1 OptString `json:"childStr1"` +} + +// GetChildB1 returns the value of ChildB1. +func (s *ChildModel1) GetChildB1() OptBool { + return s.ChildB1 +} + +// GetChildStr1 returns the value of ChildStr1. +func (s *ChildModel1) GetChildStr1() OptString { + return s.ChildStr1 +} + +// SetChildB1 sets the value of ChildB1. +func (s *ChildModel1) SetChildB1(val OptBool) { + s.ChildB1 = val +} + +// SetChildStr1 sets the value of ChildStr1. +func (s *ChildModel1) SetChildStr1(val OptString) { + s.ChildStr1 = val +} + +// NewOptBool returns new OptBool with value set to v. +func NewOptBool(v bool) OptBool { + return OptBool{ + Value: v, + Set: true, + } +} + +// OptBool is optional bool. +type OptBool struct { + Value bool + Set bool +} + +// IsSet returns true if OptBool was set. +func (o OptBool) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptBool) Reset() { + var v bool + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptBool) SetTo(v bool) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptBool) Get() (v bool, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptBool) Or(d bool) bool { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptChildModel1 returns new OptChildModel1 with value set to v. +func NewOptChildModel1(v ChildModel1) OptChildModel1 { + return OptChildModel1{ + Value: v, + Set: true, + } +} + +// OptChildModel1 is optional ChildModel1. +type OptChildModel1 struct { + Value ChildModel1 + Set bool +} + +// IsSet returns true if OptChildModel1 was set. +func (o OptChildModel1) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptChildModel1) Reset() { + var v ChildModel1 + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptChildModel1) SetTo(v ChildModel1) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptChildModel1) Get() (v ChildModel1, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptChildModel1) Or(d ChildModel1) ChildModel1 { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptFloat32 returns new OptFloat32 with value set to v. +func NewOptFloat32(v float32) OptFloat32 { + return OptFloat32{ + Value: v, + Set: true, + } +} + +// OptFloat32 is optional float32. +type OptFloat32 struct { + Value float32 + Set bool +} + +// IsSet returns true if OptFloat32 was set. +func (o OptFloat32) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptFloat32) Reset() { + var v float32 + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptFloat32) SetTo(v float32) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptFloat32) Get() (v float32, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptFloat32) Or(d float32) float32 { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptFloat64 returns new OptFloat64 with value set to v. +func NewOptFloat64(v float64) OptFloat64 { + return OptFloat64{ + Value: v, + Set: true, + } +} + +// OptFloat64 is optional float64. +type OptFloat64 struct { + Value float64 + Set bool +} + +// IsSet returns true if OptFloat64 was set. +func (o OptFloat64) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptFloat64) Reset() { + var v float64 + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptFloat64) SetTo(v float64) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptFloat64) Get() (v float64, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptFloat64) Or(d float64) float64 { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptInt32 returns new OptInt32 with value set to v. +func NewOptInt32(v int32) OptInt32 { + return OptInt32{ + Value: v, + Set: true, + } +} + +// OptInt32 is optional int32. +type OptInt32 struct { + Value int32 + Set bool +} + +// IsSet returns true if OptInt32 was set. +func (o OptInt32) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptInt32) Reset() { + var v int32 + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptInt32) SetTo(v int32) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptInt32) Get() (v int32, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptInt32) Or(d int32) int32 { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptInt64 returns new OptInt64 with value set to v. +func NewOptInt64(v int64) OptInt64 { + return OptInt64{ + Value: v, + Set: true, + } +} + +// OptInt64 is optional int64. +type OptInt64 struct { + Value int64 + Set bool +} + +// IsSet returns true if OptInt64 was set. +func (o OptInt64) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptInt64) Reset() { + var v int64 + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptInt64) SetTo(v int64) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptInt64) Get() (v int64, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptInt64) Or(d int64) int64 { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptString returns new OptString with value set to v. +func NewOptString(v string) OptString { + return OptString{ + Value: v, + Set: true, + } +} + +// OptString is optional string. +type OptString struct { + Value string + Set bool +} + +// IsSet returns true if OptString was set. +func (o OptString) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptString) Reset() { + var v string + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptString) SetTo(v string) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptString) Get() (v string, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptString) Or(d string) string { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptTestEnum returns new OptTestEnum with value set to v. +func NewOptTestEnum(v TestEnum) OptTestEnum { + return OptTestEnum{ + Value: v, + Set: true, + } +} + +// OptTestEnum is optional TestEnum. +type OptTestEnum struct { + Value TestEnum + Set bool +} + +// IsSet returns true if OptTestEnum was set. +func (o OptTestEnum) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptTestEnum) Reset() { + var v TestEnum + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptTestEnum) SetTo(v TestEnum) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptTestEnum) Get() (v TestEnum, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptTestEnum) Or(d TestEnum) TestEnum { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptTestModel returns new OptTestModel with value set to v. +func NewOptTestModel(v TestModel) OptTestModel { + return OptTestModel{ + Value: v, + Set: true, + } +} + +// OptTestModel is optional TestModel. +type OptTestModel struct { + Value TestModel + Set bool +} + +// IsSet returns true if OptTestModel was set. +func (o OptTestModel) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptTestModel) Reset() { + var v TestModel + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptTestModel) SetTo(v TestModel) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptTestModel) Get() (v TestModel, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptTestModel) Or(d TestModel) TestModel { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptTestModelCategory returns new OptTestModelCategory with value set to v. +func NewOptTestModelCategory(v TestModelCategory) OptTestModelCategory { + return OptTestModelCategory{ + Value: v, + Set: true, + } +} + +// OptTestModelCategory is optional TestModelCategory. +type OptTestModelCategory struct { + Value TestModelCategory + Set bool +} + +// IsSet returns true if OptTestModelCategory was set. +func (o OptTestModelCategory) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptTestModelCategory) Reset() { + var v TestModelCategory + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptTestModelCategory) SetTo(v TestModelCategory) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptTestModelCategory) Get() (v TestModelCategory, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptTestModelCategory) Or(d TestModelCategory) TestModelCategory { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptTestModelChildStrMap returns new OptTestModelChildStrMap with value set to v. +func NewOptTestModelChildStrMap(v TestModelChildStrMap) OptTestModelChildStrMap { + return OptTestModelChildStrMap{ + Value: v, + Set: true, + } +} + +// OptTestModelChildStrMap is optional TestModelChildStrMap. +type OptTestModelChildStrMap struct { + Value TestModelChildStrMap + Set bool +} + +// IsSet returns true if OptTestModelChildStrMap was set. +func (o OptTestModelChildStrMap) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptTestModelChildStrMap) Reset() { + var v TestModelChildStrMap + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptTestModelChildStrMap) SetTo(v TestModelChildStrMap) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptTestModelChildStrMap) Get() (v TestModelChildStrMap, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptTestModelChildStrMap) Or(d TestModelChildStrMap) TestModelChildStrMap { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptTestModelNestedChild returns new OptTestModelNestedChild with value set to v. +func NewOptTestModelNestedChild(v TestModelNestedChild) OptTestModelNestedChild { + return OptTestModelNestedChild{ + Value: v, + Set: true, + } +} + +// OptTestModelNestedChild is optional TestModelNestedChild. +type OptTestModelNestedChild struct { + Value TestModelNestedChild + Set bool +} + +// IsSet returns true if OptTestModelNestedChild was set. +func (o OptTestModelNestedChild) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptTestModelNestedChild) Reset() { + var v TestModelNestedChild + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptTestModelNestedChild) SetTo(v TestModelNestedChild) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptTestModelNestedChild) Get() (v TestModelNestedChild, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptTestModelNestedChild) Or(d TestModelNestedChild) TestModelNestedChild { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptTestModelStrToIntMap returns new OptTestModelStrToIntMap with value set to v. +func NewOptTestModelStrToIntMap(v TestModelStrToIntMap) OptTestModelStrToIntMap { + return OptTestModelStrToIntMap{ + Value: v, + Set: true, + } +} + +// OptTestModelStrToIntMap is optional TestModelStrToIntMap. +type OptTestModelStrToIntMap struct { + Value TestModelStrToIntMap + Set bool +} + +// IsSet returns true if OptTestModelStrToIntMap was set. +func (o OptTestModelStrToIntMap) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptTestModelStrToIntMap) Reset() { + var v TestModelStrToIntMap + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptTestModelStrToIntMap) SetTo(v TestModelStrToIntMap) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptTestModelStrToIntMap) Get() (v TestModelStrToIntMap, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptTestModelStrToIntMap) Or(d TestModelStrToIntMap) TestModelStrToIntMap { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptTestModelStrToStrMap returns new OptTestModelStrToStrMap with value set to v. +func NewOptTestModelStrToStrMap(v TestModelStrToStrMap) OptTestModelStrToStrMap { + return OptTestModelStrToStrMap{ + Value: v, + Set: true, + } +} + +// OptTestModelStrToStrMap is optional TestModelStrToStrMap. +type OptTestModelStrToStrMap struct { + Value TestModelStrToStrMap + Set bool +} + +// IsSet returns true if OptTestModelStrToStrMap was set. +func (o OptTestModelStrToStrMap) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptTestModelStrToStrMap) Reset() { + var v TestModelStrToStrMap + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptTestModelStrToStrMap) SetTo(v TestModelStrToStrMap) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptTestModelStrToStrMap) Get() (v TestModelStrToStrMap, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptTestModelStrToStrMap) Or(d TestModelStrToStrMap) TestModelStrToStrMap { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptUint32 returns new OptUint32 with value set to v. +func NewOptUint32(v uint32) OptUint32 { + return OptUint32{ + Value: v, + Set: true, + } +} + +// OptUint32 is optional uint32. +type OptUint32 struct { + Value uint32 + Set bool +} + +// IsSet returns true if OptUint32 was set. +func (o OptUint32) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptUint32) Reset() { + var v uint32 + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptUint32) SetTo(v uint32) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptUint32) Get() (v uint32, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptUint32) Or(d uint32) uint32 { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// NewOptUint64 returns new OptUint64 with value set to v. +func NewOptUint64(v uint64) OptUint64 { + return OptUint64{ + Value: v, + Set: true, + } +} + +// OptUint64 is optional uint64. +type OptUint64 struct { + Value uint64 + Set bool +} + +// IsSet returns true if OptUint64 was set. +func (o OptUint64) IsSet() bool { return o.Set } + +// Reset unsets value. +func (o *OptUint64) Reset() { + var v uint64 + o.Value = v + o.Set = false +} + +// SetTo sets value to v. +func (o *OptUint64) SetTo(v uint64) { + o.Set = true + o.Value = v +} + +// Get returns value and boolean that denotes whether value was set. +func (o OptUint64) Get() (v uint64, ok bool) { + if !o.Set { + return v, false + } + return o.Value, true +} + +// Or returns value if set, or given parameter if does not. +func (o OptUint64) Or(d uint64) uint64 { + if v, ok := o.Get(); ok { + return v + } + return d +} + +// Ref: #/components/schemas/StringMessage +type StringMessage struct { + Value OptString `json:"value"` +} + +// GetValue returns the value of Value. +func (s *StringMessage) GetValue() OptString { + return s.Value +} + +// SetValue sets the value of Value. +func (s *StringMessage) SetValue(val OptString) { + s.Value = val +} + +// Ref: #/components/schemas/TestEnum +type TestEnum string + +const ( + TestEnumDEVICEUNKNOWN TestEnum = "DEVICE_UNKNOWN" + TestEnumDEVICEKEYBOARD TestEnum = "DEVICE_KEYBOARD" + TestEnumDEVICEMOUSE TestEnum = "DEVICE_MOUSE" + TestEnumDEVICEMONITOR TestEnum = "DEVICE_MONITOR" +) + +// AllValues returns all TestEnum values. +func (TestEnum) AllValues() []TestEnum { + return []TestEnum{ + TestEnumDEVICEUNKNOWN, + TestEnumDEVICEKEYBOARD, + TestEnumDEVICEMOUSE, + TestEnumDEVICEMONITOR, + } +} + +// MarshalText implements encoding.TextMarshaler. +func (s TestEnum) MarshalText() ([]byte, error) { + switch s { + case TestEnumDEVICEUNKNOWN: + return []byte(s), nil + case TestEnumDEVICEKEYBOARD: + return []byte(s), nil + case TestEnumDEVICEMOUSE: + return []byte(s), nil + case TestEnumDEVICEMONITOR: + return []byte(s), nil + default: + return nil, errors.Errorf("invalid value: %q", s) + } +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (s *TestEnum) UnmarshalText(data []byte) error { + switch TestEnum(data) { + case TestEnumDEVICEUNKNOWN: + *s = TestEnumDEVICEUNKNOWN + return nil + case TestEnumDEVICEKEYBOARD: + *s = TestEnumDEVICEKEYBOARD + return nil + case TestEnumDEVICEMOUSE: + *s = TestEnumDEVICEMOUSE + return nil + case TestEnumDEVICEMONITOR: + *s = TestEnumDEVICEMONITOR + return nil + default: + return errors.Errorf("invalid value: %q", data) + } +} + +// Ref: #/components/schemas/TestModel +type TestModel struct { + Value OptInt32 `json:"value"` + ValueArray []int32 `json:"valueArray"` + ValueDeprec []int32 `json:"valueDeprec"` + Str1 OptString `json:"str1"` + B1 OptBool `json:"b1"` + B2 OptBool `json:"b2"` + Str2 OptString `json:"str2"` + Str3 OptString `json:"str3"` + OptionalFloat OptFloat32 `json:"optionalFloat"` + OptionalDouble OptFloat64 `json:"optionalDouble"` + OptionalInt64 OptInt64 `json:"optionalInt64"` + OptionalUint32 OptUint32 `json:"optionalUint32"` + OptionalUint64 OptUint64 `json:"optionalUint64"` + OptionalSint32 OptInt32 `json:"optionalSint32"` + OptionalSint64 OptInt64 `json:"optionalSint64"` + OptionalFixed32 OptUint32 `json:"optionalFixed32"` + OptionalFixed64 OptUint64 `json:"optionalFixed64"` + OptionalSfixed32 OptInt32 `json:"optionalSfixed32"` + OptionalSfixed64 OptInt64 `json:"optionalSfixed64"` + RepeatedInt64 []int64 `json:"repeatedInt64"` + RepeatedUint64 []uint64 `json:"repeatedUint64"` + RepeatedFixed64 []uint64 `json:"repeatedFixed64"` + RepeatedSfixed64 []int64 `json:"repeatedSfixed64"` + RepeatedBool []bool `json:"repeatedBool"` + RepeatedString []string `json:"repeatedString"` + NestedChild1 OptTestModelNestedChild `json:"nestedChild1"` + ChildModel1 OptChildModel1 `json:"childModel1"` + ChildModel2 []ChildModel1 `json:"childModel2"` + Bar OptChildModel1 `json:"bar"` + OneofMember1 OptString `json:"oneofMember1"` + OneofMember2 OptBool `json:"oneofMember2"` + RecursiveChild *TestModel `json:"recursiveChild"` + ChildStrMap OptTestModelChildStrMap `json:"childStrMap"` + StrToIntMap OptTestModelStrToIntMap `json:"strToIntMap"` + StrToStrMap OptTestModelStrToStrMap `json:"strToStrMap"` + Category OptTestModelCategory `json:"category"` + String OptString `json:"string"` + Int64 OptInt64 `json:"int64"` + Double OptFloat64 `json:"double"` + Template OptString `json:"template"` + Msg OptString `json:"msg"` + Arena OptString `json:"arena"` + ImportedEnum OptTestEnum `json:"importedEnum"` + Phase OptString `json:"phase"` + ClearPhase OptBool `json:"clearPhase"` +} + +// GetValue returns the value of Value. +func (s *TestModel) GetValue() OptInt32 { + return s.Value +} + +// GetValueArray returns the value of ValueArray. +func (s *TestModel) GetValueArray() []int32 { + return s.ValueArray +} + +// GetValueDeprec returns the value of ValueDeprec. +func (s *TestModel) GetValueDeprec() []int32 { + return s.ValueDeprec +} + +// GetStr1 returns the value of Str1. +func (s *TestModel) GetStr1() OptString { + return s.Str1 +} + +// GetB1 returns the value of B1. +func (s *TestModel) GetB1() OptBool { + return s.B1 +} + +// GetB2 returns the value of B2. +func (s *TestModel) GetB2() OptBool { + return s.B2 +} + +// GetStr2 returns the value of Str2. +func (s *TestModel) GetStr2() OptString { + return s.Str2 +} + +// GetStr3 returns the value of Str3. +func (s *TestModel) GetStr3() OptString { + return s.Str3 +} + +// GetOptionalFloat returns the value of OptionalFloat. +func (s *TestModel) GetOptionalFloat() OptFloat32 { + return s.OptionalFloat +} + +// GetOptionalDouble returns the value of OptionalDouble. +func (s *TestModel) GetOptionalDouble() OptFloat64 { + return s.OptionalDouble +} + +// GetOptionalInt64 returns the value of OptionalInt64. +func (s *TestModel) GetOptionalInt64() OptInt64 { + return s.OptionalInt64 +} + +// GetOptionalUint32 returns the value of OptionalUint32. +func (s *TestModel) GetOptionalUint32() OptUint32 { + return s.OptionalUint32 +} + +// GetOptionalUint64 returns the value of OptionalUint64. +func (s *TestModel) GetOptionalUint64() OptUint64 { + return s.OptionalUint64 +} + +// GetOptionalSint32 returns the value of OptionalSint32. +func (s *TestModel) GetOptionalSint32() OptInt32 { + return s.OptionalSint32 +} + +// GetOptionalSint64 returns the value of OptionalSint64. +func (s *TestModel) GetOptionalSint64() OptInt64 { + return s.OptionalSint64 +} + +// GetOptionalFixed32 returns the value of OptionalFixed32. +func (s *TestModel) GetOptionalFixed32() OptUint32 { + return s.OptionalFixed32 +} + +// GetOptionalFixed64 returns the value of OptionalFixed64. +func (s *TestModel) GetOptionalFixed64() OptUint64 { + return s.OptionalFixed64 +} + +// GetOptionalSfixed32 returns the value of OptionalSfixed32. +func (s *TestModel) GetOptionalSfixed32() OptInt32 { + return s.OptionalSfixed32 +} + +// GetOptionalSfixed64 returns the value of OptionalSfixed64. +func (s *TestModel) GetOptionalSfixed64() OptInt64 { + return s.OptionalSfixed64 +} + +// GetRepeatedInt64 returns the value of RepeatedInt64. +func (s *TestModel) GetRepeatedInt64() []int64 { + return s.RepeatedInt64 +} + +// GetRepeatedUint64 returns the value of RepeatedUint64. +func (s *TestModel) GetRepeatedUint64() []uint64 { + return s.RepeatedUint64 +} + +// GetRepeatedFixed64 returns the value of RepeatedFixed64. +func (s *TestModel) GetRepeatedFixed64() []uint64 { + return s.RepeatedFixed64 +} + +// GetRepeatedSfixed64 returns the value of RepeatedSfixed64. +func (s *TestModel) GetRepeatedSfixed64() []int64 { + return s.RepeatedSfixed64 +} + +// GetRepeatedBool returns the value of RepeatedBool. +func (s *TestModel) GetRepeatedBool() []bool { + return s.RepeatedBool +} + +// GetRepeatedString returns the value of RepeatedString. +func (s *TestModel) GetRepeatedString() []string { + return s.RepeatedString +} + +// GetNestedChild1 returns the value of NestedChild1. +func (s *TestModel) GetNestedChild1() OptTestModelNestedChild { + return s.NestedChild1 +} + +// GetChildModel1 returns the value of ChildModel1. +func (s *TestModel) GetChildModel1() OptChildModel1 { + return s.ChildModel1 +} + +// GetChildModel2 returns the value of ChildModel2. +func (s *TestModel) GetChildModel2() []ChildModel1 { + return s.ChildModel2 +} + +// GetBar returns the value of Bar. +func (s *TestModel) GetBar() OptChildModel1 { + return s.Bar +} + +// GetOneofMember1 returns the value of OneofMember1. +func (s *TestModel) GetOneofMember1() OptString { + return s.OneofMember1 +} + +// GetOneofMember2 returns the value of OneofMember2. +func (s *TestModel) GetOneofMember2() OptBool { + return s.OneofMember2 +} + +// GetRecursiveChild returns the value of RecursiveChild. +func (s *TestModel) GetRecursiveChild() *TestModel { + return s.RecursiveChild +} + +// GetChildStrMap returns the value of ChildStrMap. +func (s *TestModel) GetChildStrMap() OptTestModelChildStrMap { + return s.ChildStrMap +} + +// GetStrToIntMap returns the value of StrToIntMap. +func (s *TestModel) GetStrToIntMap() OptTestModelStrToIntMap { + return s.StrToIntMap +} + +// GetStrToStrMap returns the value of StrToStrMap. +func (s *TestModel) GetStrToStrMap() OptTestModelStrToStrMap { + return s.StrToStrMap +} + +// GetCategory returns the value of Category. +func (s *TestModel) GetCategory() OptTestModelCategory { + return s.Category +} + +// GetString returns the value of String. +func (s *TestModel) GetString() OptString { + return s.String +} + +// GetInt64 returns the value of Int64. +func (s *TestModel) GetInt64() OptInt64 { + return s.Int64 +} + +// GetDouble returns the value of Double. +func (s *TestModel) GetDouble() OptFloat64 { + return s.Double +} + +// GetTemplate returns the value of Template. +func (s *TestModel) GetTemplate() OptString { + return s.Template +} + +// GetMsg returns the value of Msg. +func (s *TestModel) GetMsg() OptString { + return s.Msg +} + +// GetArena returns the value of Arena. +func (s *TestModel) GetArena() OptString { + return s.Arena +} + +// GetImportedEnum returns the value of ImportedEnum. +func (s *TestModel) GetImportedEnum() OptTestEnum { + return s.ImportedEnum +} + +// GetPhase returns the value of Phase. +func (s *TestModel) GetPhase() OptString { + return s.Phase +} + +// GetClearPhase returns the value of ClearPhase. +func (s *TestModel) GetClearPhase() OptBool { + return s.ClearPhase +} + +// SetValue sets the value of Value. +func (s *TestModel) SetValue(val OptInt32) { + s.Value = val +} + +// SetValueArray sets the value of ValueArray. +func (s *TestModel) SetValueArray(val []int32) { + s.ValueArray = val +} + +// SetValueDeprec sets the value of ValueDeprec. +func (s *TestModel) SetValueDeprec(val []int32) { + s.ValueDeprec = val +} + +// SetStr1 sets the value of Str1. +func (s *TestModel) SetStr1(val OptString) { + s.Str1 = val +} + +// SetB1 sets the value of B1. +func (s *TestModel) SetB1(val OptBool) { + s.B1 = val +} + +// SetB2 sets the value of B2. +func (s *TestModel) SetB2(val OptBool) { + s.B2 = val +} + +// SetStr2 sets the value of Str2. +func (s *TestModel) SetStr2(val OptString) { + s.Str2 = val +} + +// SetStr3 sets the value of Str3. +func (s *TestModel) SetStr3(val OptString) { + s.Str3 = val +} + +// SetOptionalFloat sets the value of OptionalFloat. +func (s *TestModel) SetOptionalFloat(val OptFloat32) { + s.OptionalFloat = val +} + +// SetOptionalDouble sets the value of OptionalDouble. +func (s *TestModel) SetOptionalDouble(val OptFloat64) { + s.OptionalDouble = val +} + +// SetOptionalInt64 sets the value of OptionalInt64. +func (s *TestModel) SetOptionalInt64(val OptInt64) { + s.OptionalInt64 = val +} + +// SetOptionalUint32 sets the value of OptionalUint32. +func (s *TestModel) SetOptionalUint32(val OptUint32) { + s.OptionalUint32 = val +} + +// SetOptionalUint64 sets the value of OptionalUint64. +func (s *TestModel) SetOptionalUint64(val OptUint64) { + s.OptionalUint64 = val +} + +// SetOptionalSint32 sets the value of OptionalSint32. +func (s *TestModel) SetOptionalSint32(val OptInt32) { + s.OptionalSint32 = val +} + +// SetOptionalSint64 sets the value of OptionalSint64. +func (s *TestModel) SetOptionalSint64(val OptInt64) { + s.OptionalSint64 = val +} + +// SetOptionalFixed32 sets the value of OptionalFixed32. +func (s *TestModel) SetOptionalFixed32(val OptUint32) { + s.OptionalFixed32 = val +} + +// SetOptionalFixed64 sets the value of OptionalFixed64. +func (s *TestModel) SetOptionalFixed64(val OptUint64) { + s.OptionalFixed64 = val +} + +// SetOptionalSfixed32 sets the value of OptionalSfixed32. +func (s *TestModel) SetOptionalSfixed32(val OptInt32) { + s.OptionalSfixed32 = val +} + +// SetOptionalSfixed64 sets the value of OptionalSfixed64. +func (s *TestModel) SetOptionalSfixed64(val OptInt64) { + s.OptionalSfixed64 = val +} + +// SetRepeatedInt64 sets the value of RepeatedInt64. +func (s *TestModel) SetRepeatedInt64(val []int64) { + s.RepeatedInt64 = val +} + +// SetRepeatedUint64 sets the value of RepeatedUint64. +func (s *TestModel) SetRepeatedUint64(val []uint64) { + s.RepeatedUint64 = val +} + +// SetRepeatedFixed64 sets the value of RepeatedFixed64. +func (s *TestModel) SetRepeatedFixed64(val []uint64) { + s.RepeatedFixed64 = val +} + +// SetRepeatedSfixed64 sets the value of RepeatedSfixed64. +func (s *TestModel) SetRepeatedSfixed64(val []int64) { + s.RepeatedSfixed64 = val +} + +// SetRepeatedBool sets the value of RepeatedBool. +func (s *TestModel) SetRepeatedBool(val []bool) { + s.RepeatedBool = val +} + +// SetRepeatedString sets the value of RepeatedString. +func (s *TestModel) SetRepeatedString(val []string) { + s.RepeatedString = val +} + +// SetNestedChild1 sets the value of NestedChild1. +func (s *TestModel) SetNestedChild1(val OptTestModelNestedChild) { + s.NestedChild1 = val +} + +// SetChildModel1 sets the value of ChildModel1. +func (s *TestModel) SetChildModel1(val OptChildModel1) { + s.ChildModel1 = val +} + +// SetChildModel2 sets the value of ChildModel2. +func (s *TestModel) SetChildModel2(val []ChildModel1) { + s.ChildModel2 = val +} + +// SetBar sets the value of Bar. +func (s *TestModel) SetBar(val OptChildModel1) { + s.Bar = val +} + +// SetOneofMember1 sets the value of OneofMember1. +func (s *TestModel) SetOneofMember1(val OptString) { + s.OneofMember1 = val +} + +// SetOneofMember2 sets the value of OneofMember2. +func (s *TestModel) SetOneofMember2(val OptBool) { + s.OneofMember2 = val +} + +// SetRecursiveChild sets the value of RecursiveChild. +func (s *TestModel) SetRecursiveChild(val *TestModel) { + s.RecursiveChild = val +} + +// SetChildStrMap sets the value of ChildStrMap. +func (s *TestModel) SetChildStrMap(val OptTestModelChildStrMap) { + s.ChildStrMap = val +} + +// SetStrToIntMap sets the value of StrToIntMap. +func (s *TestModel) SetStrToIntMap(val OptTestModelStrToIntMap) { + s.StrToIntMap = val +} + +// SetStrToStrMap sets the value of StrToStrMap. +func (s *TestModel) SetStrToStrMap(val OptTestModelStrToStrMap) { + s.StrToStrMap = val +} + +// SetCategory sets the value of Category. +func (s *TestModel) SetCategory(val OptTestModelCategory) { + s.Category = val +} + +// SetString sets the value of String. +func (s *TestModel) SetString(val OptString) { + s.String = val +} + +// SetInt64 sets the value of Int64. +func (s *TestModel) SetInt64(val OptInt64) { + s.Int64 = val +} + +// SetDouble sets the value of Double. +func (s *TestModel) SetDouble(val OptFloat64) { + s.Double = val +} + +// SetTemplate sets the value of Template. +func (s *TestModel) SetTemplate(val OptString) { + s.Template = val +} + +// SetMsg sets the value of Msg. +func (s *TestModel) SetMsg(val OptString) { + s.Msg = val +} + +// SetArena sets the value of Arena. +func (s *TestModel) SetArena(val OptString) { + s.Arena = val +} + +// SetImportedEnum sets the value of ImportedEnum. +func (s *TestModel) SetImportedEnum(val OptTestEnum) { + s.ImportedEnum = val +} + +// SetPhase sets the value of Phase. +func (s *TestModel) SetPhase(val OptString) { + s.Phase = val +} + +// SetClearPhase sets the value of ClearPhase. +func (s *TestModel) SetClearPhase(val OptBool) { + s.ClearPhase = val +} + +// Ref: #/components/schemas/TestModel.Category +type TestModelCategory string + +const ( + TestModelCategoryUNKNOWN TestModelCategory = "UNKNOWN" + TestModelCategoryIMAGES TestModelCategory = "IMAGES" + TestModelCategoryNEWS TestModelCategory = "NEWS" + TestModelCategoryVIDEO TestModelCategory = "VIDEO" + TestModelCategoryRADIO TestModelCategory = "RADIO" +) + +// AllValues returns all TestModelCategory values. +func (TestModelCategory) AllValues() []TestModelCategory { + return []TestModelCategory{ + TestModelCategoryUNKNOWN, + TestModelCategoryIMAGES, + TestModelCategoryNEWS, + TestModelCategoryVIDEO, + TestModelCategoryRADIO, + } +} + +// MarshalText implements encoding.TextMarshaler. +func (s TestModelCategory) MarshalText() ([]byte, error) { + switch s { + case TestModelCategoryUNKNOWN: + return []byte(s), nil + case TestModelCategoryIMAGES: + return []byte(s), nil + case TestModelCategoryNEWS: + return []byte(s), nil + case TestModelCategoryVIDEO: + return []byte(s), nil + case TestModelCategoryRADIO: + return []byte(s), nil + default: + return nil, errors.Errorf("invalid value: %q", s) + } +} + +// UnmarshalText implements encoding.TextUnmarshaler. +func (s *TestModelCategory) UnmarshalText(data []byte) error { + switch TestModelCategory(data) { + case TestModelCategoryUNKNOWN: + *s = TestModelCategoryUNKNOWN + return nil + case TestModelCategoryIMAGES: + *s = TestModelCategoryIMAGES + return nil + case TestModelCategoryNEWS: + *s = TestModelCategoryNEWS + return nil + case TestModelCategoryVIDEO: + *s = TestModelCategoryVIDEO + return nil + case TestModelCategoryRADIO: + *s = TestModelCategoryRADIO + return nil + default: + return errors.Errorf("invalid value: %q", data) + } +} + +type TestModelChildStrMap map[string]ChildModel1 + +func (s *TestModelChildStrMap) init() TestModelChildStrMap { + m := *s + if m == nil { + m = map[string]ChildModel1{} + *s = m + } + return m +} + +// Ref: #/components/schemas/TestModel.NestedChild +type TestModelNestedChild struct { + NestedChildName OptString `json:"nestedChildName"` +} + +// GetNestedChildName returns the value of NestedChildName. +func (s *TestModelNestedChild) GetNestedChildName() OptString { + return s.NestedChildName +} + +// SetNestedChildName sets the value of NestedChildName. +func (s *TestModelNestedChild) SetNestedChildName(val OptString) { + s.NestedChildName = val +} + +type TestModelStrToIntMap map[string]int32 + +func (s *TestModelStrToIntMap) init() TestModelStrToIntMap { + m := *s + if m == nil { + m = map[string]int32{} + *s = m + } + return m +} + +type TestModelStrToStrMap map[string]string + +func (s *TestModelStrToStrMap) init() TestModelStrToStrMap { + m := *s + if m == nil { + m = map[string]string{} + *s = m + } + return m +} diff --git a/integration/proxypb/oas/oas_server_gen.go b/integration/proxypb/oas/oas_server_gen.go new file mode 100644 index 0000000..3bb7465 --- /dev/null +++ b/integration/proxypb/oas/oas_server_gen.go @@ -0,0 +1,42 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "context" +) + +// Handler handles operations described by OpenAPI v3 specification. +type Handler interface { + // Echo implements echo operation. + // + // POST /echo + Echo(ctx context.Context, req OptString) (*StringMessage, error) + // PathParam implements pathParam operation. + // + // POST /pathParam/{value} + PathParam(ctx context.Context, params PathParamParams) (*StringMessage, error) + // TestModelEndpoint implements testModelEndpoint operation. + // + // POST /testModel + TestModelEndpoint(ctx context.Context, req *TestModel) (*TestModel, error) +} + +// Server implements http server based on OpenAPI v3 specification and +// calls Handler to handle requests. +type Server struct { + h Handler + baseServer +} + +// NewServer creates new Server. +func NewServer(h Handler, opts ...ServerOption) (*Server, error) { + s, err := newServerConfig(opts...).baseServer() + if err != nil { + return nil, err + } + return &Server{ + h: h, + baseServer: s, + }, nil +} diff --git a/integration/proxypb/oas/oas_unimplemented_gen.go b/integration/proxypb/oas/oas_unimplemented_gen.go new file mode 100644 index 0000000..709c864 --- /dev/null +++ b/integration/proxypb/oas/oas_unimplemented_gen.go @@ -0,0 +1,35 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "context" + + ht "github.com/ogen-go/ogen/http" +) + +// UnimplementedHandler is no-op Handler which returns http.ErrNotImplemented. +type UnimplementedHandler struct{} + +var _ Handler = UnimplementedHandler{} + +// Echo implements echo operation. +// +// POST /echo +func (UnimplementedHandler) Echo(ctx context.Context, req OptString) (r *StringMessage, _ error) { + return r, ht.ErrNotImplemented +} + +// PathParam implements pathParam operation. +// +// POST /pathParam/{value} +func (UnimplementedHandler) PathParam(ctx context.Context, params PathParamParams) (r *StringMessage, _ error) { + return r, ht.ErrNotImplemented +} + +// TestModelEndpoint implements testModelEndpoint operation. +// +// POST /testModel +func (UnimplementedHandler) TestModelEndpoint(ctx context.Context, req *TestModel) (r *TestModel, _ error) { + return r, ht.ErrNotImplemented +} diff --git a/integration/proxypb/oas/oas_validators_gen.go b/integration/proxypb/oas/oas_validators_gen.go new file mode 100644 index 0000000..a03cdda --- /dev/null +++ b/integration/proxypb/oas/oas_validators_gen.go @@ -0,0 +1,158 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "github.com/go-faster/errors" + + "github.com/ogen-go/ogen/validate" +) + +func (s TestEnum) Validate() error { + switch s { + case "DEVICE_UNKNOWN": + return nil + case "DEVICE_KEYBOARD": + return nil + case "DEVICE_MOUSE": + return nil + case "DEVICE_MONITOR": + return nil + default: + return errors.Errorf("invalid value: %v", s) + } +} + +func (s *TestModel) Validate() error { + var failures []validate.FieldError + if err := func() error { + if value, ok := s.OptionalFloat.Get(); ok { + if err := func() error { + if err := (validate.Float{}).Validate(float64(value)); err != nil { + return errors.Wrap(err, "float") + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "optionalFloat", + Error: err, + }) + } + if err := func() error { + if value, ok := s.OptionalDouble.Get(); ok { + if err := func() error { + if err := (validate.Float{}).Validate(float64(value)); err != nil { + return errors.Wrap(err, "float") + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "optionalDouble", + Error: err, + }) + } + if err := func() error { + if s.RecursiveChild == nil { + return nil // optional + } + if err := func() error { + if err := s.RecursiveChild.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return errors.Wrap(err, "pointer") + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "recursiveChild", + Error: err, + }) + } + if err := func() error { + if value, ok := s.Category.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "category", + Error: err, + }) + } + if err := func() error { + if value, ok := s.Double.Get(); ok { + if err := func() error { + if err := (validate.Float{}).Validate(float64(value)); err != nil { + return errors.Wrap(err, "float") + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "double", + Error: err, + }) + } + if err := func() error { + if value, ok := s.ImportedEnum.Get(); ok { + if err := func() error { + if err := value.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return err + } + } + return nil + }(); err != nil { + failures = append(failures, validate.FieldError{ + Name: "importedEnum", + Error: err, + }) + } + if len(failures) > 0 { + return &validate.Error{Fields: failures} + } + return nil +} + +func (s TestModelCategory) Validate() error { + switch s { + case "UNKNOWN": + return nil + case "IMAGES": + return nil + case "NEWS": + return nil + case "VIDEO": + return nil + case "RADIO": + return nil + default: + return errors.Errorf("invalid value: %v", s) + } +} diff --git a/integration/proxypb/openapi.yaml b/integration/proxypb/openapi.yaml new file mode 100644 index 0000000..db73c3f --- /dev/null +++ b/integration/proxypb/openapi.yaml @@ -0,0 +1,248 @@ +openapi: 3.1.0 +info: + title: "" + version: "" +paths: + /echo: + post: + operationId: echo + requestBody: + content: + application/json: + schema: + type: string + responses: + "200": + description: proxypb.APIService.Echo response + content: + application/json: + schema: + $ref: '#/components/schemas/StringMessage' + /pathParam/{value}: + post: + operationId: pathParam + parameters: + - name: value + in: path + required: true + schema: + type: string + responses: + "200": + description: proxypb.APIService.PathParam response + content: + application/json: + schema: + $ref: '#/components/schemas/StringMessage' + /testModel: + post: + operationId: testModelEndpoint + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TestModel' + required: true + responses: + "200": + description: proxypb.APIService.TestModelEndpoint response + content: + application/json: + schema: + $ref: '#/components/schemas/TestModel' +components: + schemas: + ChildModel1: + type: object + properties: + childB1: + type: boolean + childStr1: + type: string + StringMessage: + type: object + properties: + value: + type: string + TestEnum: + type: string + enum: + - "DEVICE_UNKNOWN" + - "DEVICE_KEYBOARD" + - "DEVICE_MOUSE" + - "DEVICE_MONITOR" + TestModel: + type: object + properties: + value: + type: integer + format: int32 + valueArray: + type: array + items: + description: _UPB_MODE_ARRAY + type: integer + format: int32 + valueDeprec: + type: array + items: + type: integer + format: int32 + deprecated: true + str1: + type: string + b1: + type: boolean + b2: + type: boolean + str2: + type: string + str3: + type: string + optionalFloat: + type: number + format: float + optionalDouble: + type: number + format: double + optionalInt64: + type: integer + format: int64 + optionalUint32: + type: integer + format: uint32 + optionalUint64: + type: integer + format: uint64 + optionalSint32: + type: integer + format: int32 + optionalSint64: + type: integer + format: int64 + optionalFixed32: + type: integer + format: uint32 + optionalFixed64: + type: integer + format: uint64 + optionalSfixed32: + type: integer + format: int32 + optionalSfixed64: + type: integer + format: int64 + repeatedInt64: + type: array + items: + type: integer + format: int64 + repeatedUint64: + type: array + items: + type: integer + format: uint64 + repeatedFixed64: + type: array + items: + type: integer + format: uint64 + repeatedSfixed64: + type: array + items: + type: integer + format: int64 + repeatedBool: + type: array + items: + type: boolean + repeatedString: + type: array + items: + type: string + nestedChild1: + $ref: '#/components/schemas/TestModel.NestedChild' + childModel1: + $ref: '#/components/schemas/ChildModel1' + childModel2: + type: array + items: + $ref: '#/components/schemas/ChildModel1' + bar: + $ref: '#/components/schemas/ChildModel1' + oneofMember1: + type: string + oneofMember2: + type: boolean + recursiveChild: + $ref: '#/components/schemas/TestModel' + childStrMap: + type: object + additionalProperties: + $ref: '#/components/schemas/ChildModel1' + strToIntMap: + type: object + additionalProperties: + type: integer + format: int32 + strToStrMap: + type: object + additionalProperties: + type: string + category: + $ref: '#/components/schemas/TestModel.Category' + string: + type: string + int64: + type: integer + format: int64 + double: + type: number + format: double + template: + type: string + msg: + type: string + arena: + type: string + importedEnum: + $ref: '#/components/schemas/TestEnum' + phase: + type: string + clearPhase: + type: boolean + TestModel.Category: + type: string + enum: + - "UNKNOWN" + - "IMAGES" + - "NEWS" + - "VIDEO" + - "RADIO" + TestModel.ChildStrMapEntry: + type: object + properties: + key: + type: string + value: + $ref: '#/components/schemas/ChildModel1' + TestModel.NestedChild: + type: object + properties: + nestedChildName: + type: string + TestModel.StrToIntMapEntry: + type: object + properties: + key: + type: string + value: + type: integer + format: int32 + TestModel.StrToStrMapEntry: + type: object + properties: + key: + type: string + value: + type: string diff --git a/integration/proxypb/proxy.pb.go b/integration/proxypb/proxy.pb.go new file mode 100644 index 0000000..57be32d --- /dev/null +++ b/integration/proxypb/proxy.pb.go @@ -0,0 +1,1210 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc v4.25.0 +// source: proxy.proto + +package proxypb + +import ( + _ "google.golang.org/genproto/googleapis/api/annotations" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type TestEnum int32 + +const ( + TestEnum_DEVICE_UNKNOWN TestEnum = 0 + TestEnum_DEVICE_KEYBOARD TestEnum = 1 + TestEnum_DEVICE_MOUSE TestEnum = 2 + TestEnum_DEVICE_MONITOR TestEnum = 3 +) + +// Enum value maps for TestEnum. +var ( + TestEnum_name = map[int32]string{ + 0: "DEVICE_UNKNOWN", + 1: "DEVICE_KEYBOARD", + 2: "DEVICE_MOUSE", + 3: "DEVICE_MONITOR", + } + TestEnum_value = map[string]int32{ + "DEVICE_UNKNOWN": 0, + "DEVICE_KEYBOARD": 1, + "DEVICE_MOUSE": 2, + "DEVICE_MONITOR": 3, + } +) + +func (x TestEnum) Enum() *TestEnum { + p := new(TestEnum) + *p = x + return p +} + +func (x TestEnum) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (TestEnum) Descriptor() protoreflect.EnumDescriptor { + return file_proxy_proto_enumTypes[0].Descriptor() +} + +func (TestEnum) Type() protoreflect.EnumType { + return &file_proxy_proto_enumTypes[0] +} + +func (x TestEnum) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use TestEnum.Descriptor instead. +func (TestEnum) EnumDescriptor() ([]byte, []int) { + return file_proxy_proto_rawDescGZIP(), []int{0} +} + +type TestModel_Category int32 + +const ( + TestModel_UNKNOWN TestModel_Category = 0 + TestModel_IMAGES TestModel_Category = 5 + TestModel_NEWS TestModel_Category = 6 + TestModel_VIDEO TestModel_Category = 7 + // Deprecated: Marked as deprecated in proxy.proto. + TestModel_RADIO TestModel_Category = 8 +) + +// Enum value maps for TestModel_Category. +var ( + TestModel_Category_name = map[int32]string{ + 0: "UNKNOWN", + 5: "IMAGES", + 6: "NEWS", + 7: "VIDEO", + 8: "RADIO", + } + TestModel_Category_value = map[string]int32{ + "UNKNOWN": 0, + "IMAGES": 5, + "NEWS": 6, + "VIDEO": 7, + "RADIO": 8, + } +) + +func (x TestModel_Category) Enum() *TestModel_Category { + p := new(TestModel_Category) + *p = x + return p +} + +func (x TestModel_Category) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (TestModel_Category) Descriptor() protoreflect.EnumDescriptor { + return file_proxy_proto_enumTypes[1].Descriptor() +} + +func (TestModel_Category) Type() protoreflect.EnumType { + return &file_proxy_proto_enumTypes[1] +} + +func (x TestModel_Category) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use TestModel_Category.Descriptor instead. +func (TestModel_Category) EnumDescriptor() ([]byte, []int) { + return file_proxy_proto_rawDescGZIP(), []int{2, 0} +} + +type ChildModel1 struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ChildB1 *bool `protobuf:"varint,44,opt,name=child_b1,json=childB1,proto3,oneof" json:"child_b1,omitempty"` + ChildStr1 *string `protobuf:"bytes,56,opt,name=child_str1,json=childStr1,proto3,oneof" json:"child_str1,omitempty"` +} + +func (x *ChildModel1) Reset() { + *x = ChildModel1{} + if protoimpl.UnsafeEnabled { + mi := &file_proxy_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChildModel1) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChildModel1) ProtoMessage() {} + +func (x *ChildModel1) ProtoReflect() protoreflect.Message { + mi := &file_proxy_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChildModel1.ProtoReflect.Descriptor instead. +func (*ChildModel1) Descriptor() ([]byte, []int) { + return file_proxy_proto_rawDescGZIP(), []int{0} +} + +func (x *ChildModel1) GetChildB1() bool { + if x != nil && x.ChildB1 != nil { + return *x.ChildB1 + } + return false +} + +func (x *ChildModel1) GetChildStr1() string { + if x != nil && x.ChildStr1 != nil { + return *x.ChildStr1 + } + return "" +} + +type ChildModel3 struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SubKey string `protobuf:"bytes,1,opt,name=sub_key,json=subKey,proto3" json:"sub_key,omitempty"` + Bool1 bool `protobuf:"varint,2,opt,name=bool1,proto3" json:"bool1,omitempty"` + I32 int32 `protobuf:"varint,3,opt,name=i32,proto3" json:"i32,omitempty"` + OptStr *string `protobuf:"bytes,4,opt,name=opt_str,json=optStr,proto3,oneof" json:"opt_str,omitempty"` + OptBool *bool `protobuf:"varint,5,opt,name=opt_bool,json=optBool,proto3,oneof" json:"opt_bool,omitempty"` + OptI32 *int32 `protobuf:"varint,6,opt,name=opt_i32,json=optI32,proto3,oneof" json:"opt_i32,omitempty"` +} + +func (x *ChildModel3) Reset() { + *x = ChildModel3{} + if protoimpl.UnsafeEnabled { + mi := &file_proxy_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ChildModel3) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ChildModel3) ProtoMessage() {} + +func (x *ChildModel3) ProtoReflect() protoreflect.Message { + mi := &file_proxy_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ChildModel3.ProtoReflect.Descriptor instead. +func (*ChildModel3) Descriptor() ([]byte, []int) { + return file_proxy_proto_rawDescGZIP(), []int{1} +} + +func (x *ChildModel3) GetSubKey() string { + if x != nil { + return x.SubKey + } + return "" +} + +func (x *ChildModel3) GetBool1() bool { + if x != nil { + return x.Bool1 + } + return false +} + +func (x *ChildModel3) GetI32() int32 { + if x != nil { + return x.I32 + } + return 0 +} + +func (x *ChildModel3) GetOptStr() string { + if x != nil && x.OptStr != nil { + return *x.OptStr + } + return "" +} + +func (x *ChildModel3) GetOptBool() bool { + if x != nil && x.OptBool != nil { + return *x.OptBool + } + return false +} + +func (x *ChildModel3) GetOptI32() int32 { + if x != nil && x.OptI32 != nil { + return *x.OptI32 + } + return 0 +} + +type TestModel struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value *int32 `protobuf:"varint,1,opt,name=value,proto3,oneof" json:"value,omitempty"` + ValueArray []int32 `protobuf:"varint,2,rep,packed,name=value_array,json=valueArray,proto3" json:"value_array,omitempty"` // _UPB_MODE_ARRAY + // Deprecated: Marked as deprecated in proxy.proto. + ValueDeprec []int32 `protobuf:"varint,4,rep,packed,name=value_deprec,json=valueDeprec,proto3" json:"value_deprec,omitempty"` + Str1 *string `protobuf:"bytes,115,opt,name=str1,proto3,oneof" json:"str1,omitempty"` + B1 *bool `protobuf:"varint,9,opt,name=b1,proto3,oneof" json:"b1,omitempty"` + B2 *bool `protobuf:"varint,10,opt,name=b2,proto3,oneof" json:"b2,omitempty"` + Str2 *string `protobuf:"bytes,50,opt,name=str2,proto3,oneof" json:"str2,omitempty"` + Str3 *string `protobuf:"bytes,11,opt,name=str3,proto3,oneof" json:"str3,omitempty"` + OptionalFloat *float32 `protobuf:"fixed32,14,opt,name=optional_float,json=optionalFloat,proto3,oneof" json:"optional_float,omitempty"` + OptionalDouble *float64 `protobuf:"fixed64,15,opt,name=optional_double,json=optionalDouble,proto3,oneof" json:"optional_double,omitempty"` + OptionalInt64 *int64 `protobuf:"varint,16,opt,name=optional_int64,json=optionalInt64,proto3,oneof" json:"optional_int64,omitempty"` + OptionalUint32 *uint32 `protobuf:"varint,17,opt,name=optional_uint32,json=optionalUint32,proto3,oneof" json:"optional_uint32,omitempty"` + OptionalUint64 *uint64 `protobuf:"varint,18,opt,name=optional_uint64,json=optionalUint64,proto3,oneof" json:"optional_uint64,omitempty"` + OptionalSint32 *int32 `protobuf:"zigzag32,19,opt,name=optional_sint32,json=optionalSint32,proto3,oneof" json:"optional_sint32,omitempty"` + OptionalSint64 *int64 `protobuf:"zigzag64,20,opt,name=optional_sint64,json=optionalSint64,proto3,oneof" json:"optional_sint64,omitempty"` + OptionalFixed32 *uint32 `protobuf:"fixed32,21,opt,name=optional_fixed32,json=optionalFixed32,proto3,oneof" json:"optional_fixed32,omitempty"` + OptionalFixed64 *uint64 `protobuf:"fixed64,22,opt,name=optional_fixed64,json=optionalFixed64,proto3,oneof" json:"optional_fixed64,omitempty"` + OptionalSfixed32 *int32 `protobuf:"fixed32,23,opt,name=optional_sfixed32,json=optionalSfixed32,proto3,oneof" json:"optional_sfixed32,omitempty"` + OptionalSfixed64 *int64 `protobuf:"fixed64,24,opt,name=optional_sfixed64,json=optionalSfixed64,proto3,oneof" json:"optional_sfixed64,omitempty"` + RepeatedInt64 []int64 `protobuf:"varint,25,rep,packed,name=repeated_int64,json=repeatedInt64,proto3" json:"repeated_int64,omitempty"` + RepeatedUint64 []uint64 `protobuf:"varint,26,rep,packed,name=repeated_uint64,json=repeatedUint64,proto3" json:"repeated_uint64,omitempty"` + RepeatedFixed64 []uint64 `protobuf:"fixed64,27,rep,packed,name=repeated_fixed64,json=repeatedFixed64,proto3" json:"repeated_fixed64,omitempty"` + RepeatedSfixed64 []int64 `protobuf:"fixed64,28,rep,packed,name=repeated_sfixed64,json=repeatedSfixed64,proto3" json:"repeated_sfixed64,omitempty"` + RepeatedBool []bool `protobuf:"varint,29,rep,packed,name=repeated_bool,json=repeatedBool,proto3" json:"repeated_bool,omitempty"` + RepeatedString []string `protobuf:"bytes,35,rep,name=repeated_string,json=repeatedString,proto3" json:"repeated_string,omitempty"` + NestedChild_1 *TestModel_NestedChild `protobuf:"bytes,212,opt,name=nested_child_1,json=nestedChild1,proto3,oneof" json:"nested_child_1,omitempty"` + ChildModel_1 *ChildModel1 `protobuf:"bytes,222,opt,name=child_model_1,json=childModel1,proto3,oneof" json:"child_model_1,omitempty"` + ChildModel_2 []*ChildModel1 `protobuf:"bytes,223,rep,name=child_model_2,json=childModel2,proto3" json:"child_model_2,omitempty"` + Bar *ChildModel1 `protobuf:"bytes,224,opt,name=bar,proto3,oneof" json:"bar,omitempty"` + // Types that are assignable to ChildOneof1: + // + // *TestModel_OneofMember1 + // *TestModel_OneofMember2 + ChildOneof1 isTestModel_ChildOneof1 `protobuf_oneof:"child_oneof1"` + RecursiveChild *TestModel `protobuf:"bytes,226,opt,name=recursive_child,json=recursiveChild,proto3,oneof" json:"recursive_child,omitempty"` + ChildStrMap map[string]*ChildModel1 `protobuf:"bytes,227,rep,name=child_str_map,json=childStrMap,proto3" json:"child_str_map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + StrToIntMap map[string]int32 `protobuf:"bytes,228,rep,name=str_to_int_map,json=strToIntMap,proto3" json:"str_to_int_map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + StrToStrMap map[string]string `protobuf:"bytes,229,rep,name=str_to_str_map,json=strToStrMap,proto3" json:"str_to_str_map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Category *TestModel_Category `protobuf:"varint,37,opt,name=category,proto3,enum=proxypb.TestModel_Category,oneof" json:"category,omitempty"` + // keyword collisions (double, template, ...) + // + // Types that are assignable to Type: + // + // *TestModel_String_ + // *TestModel_Int64 + // *TestModel_Double + Type isTestModel_Type `protobuf_oneof:"type"` + Template *string `protobuf:"bytes,233,opt,name=template,proto3,oneof" json:"template,omitempty"` + Msg *string `protobuf:"bytes,234,opt,name=msg,proto3,oneof" json:"msg,omitempty"` + Arena *string `protobuf:"bytes,235,opt,name=arena,proto3,oneof" json:"arena,omitempty"` + // Tests publicly imported enum. + ImportedEnum *TestEnum `protobuf:"varint,238,opt,name=imported_enum,json=importedEnum,proto3,enum=proxypb.TestEnum,oneof" json:"imported_enum,omitempty"` + Phase *string `protobuf:"bytes,239,opt,name=phase,proto3,oneof" json:"phase,omitempty"` + ClearPhase *bool `protobuf:"varint,240,opt,name=clear_phase,json=clearPhase,proto3,oneof" json:"clear_phase,omitempty"` +} + +func (x *TestModel) Reset() { + *x = TestModel{} + if protoimpl.UnsafeEnabled { + mi := &file_proxy_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TestModel) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TestModel) ProtoMessage() {} + +func (x *TestModel) ProtoReflect() protoreflect.Message { + mi := &file_proxy_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TestModel.ProtoReflect.Descriptor instead. +func (*TestModel) Descriptor() ([]byte, []int) { + return file_proxy_proto_rawDescGZIP(), []int{2} +} + +func (x *TestModel) GetValue() int32 { + if x != nil && x.Value != nil { + return *x.Value + } + return 0 +} + +func (x *TestModel) GetValueArray() []int32 { + if x != nil { + return x.ValueArray + } + return nil +} + +// Deprecated: Marked as deprecated in proxy.proto. +func (x *TestModel) GetValueDeprec() []int32 { + if x != nil { + return x.ValueDeprec + } + return nil +} + +func (x *TestModel) GetStr1() string { + if x != nil && x.Str1 != nil { + return *x.Str1 + } + return "" +} + +func (x *TestModel) GetB1() bool { + if x != nil && x.B1 != nil { + return *x.B1 + } + return false +} + +func (x *TestModel) GetB2() bool { + if x != nil && x.B2 != nil { + return *x.B2 + } + return false +} + +func (x *TestModel) GetStr2() string { + if x != nil && x.Str2 != nil { + return *x.Str2 + } + return "" +} + +func (x *TestModel) GetStr3() string { + if x != nil && x.Str3 != nil { + return *x.Str3 + } + return "" +} + +func (x *TestModel) GetOptionalFloat() float32 { + if x != nil && x.OptionalFloat != nil { + return *x.OptionalFloat + } + return 0 +} + +func (x *TestModel) GetOptionalDouble() float64 { + if x != nil && x.OptionalDouble != nil { + return *x.OptionalDouble + } + return 0 +} + +func (x *TestModel) GetOptionalInt64() int64 { + if x != nil && x.OptionalInt64 != nil { + return *x.OptionalInt64 + } + return 0 +} + +func (x *TestModel) GetOptionalUint32() uint32 { + if x != nil && x.OptionalUint32 != nil { + return *x.OptionalUint32 + } + return 0 +} + +func (x *TestModel) GetOptionalUint64() uint64 { + if x != nil && x.OptionalUint64 != nil { + return *x.OptionalUint64 + } + return 0 +} + +func (x *TestModel) GetOptionalSint32() int32 { + if x != nil && x.OptionalSint32 != nil { + return *x.OptionalSint32 + } + return 0 +} + +func (x *TestModel) GetOptionalSint64() int64 { + if x != nil && x.OptionalSint64 != nil { + return *x.OptionalSint64 + } + return 0 +} + +func (x *TestModel) GetOptionalFixed32() uint32 { + if x != nil && x.OptionalFixed32 != nil { + return *x.OptionalFixed32 + } + return 0 +} + +func (x *TestModel) GetOptionalFixed64() uint64 { + if x != nil && x.OptionalFixed64 != nil { + return *x.OptionalFixed64 + } + return 0 +} + +func (x *TestModel) GetOptionalSfixed32() int32 { + if x != nil && x.OptionalSfixed32 != nil { + return *x.OptionalSfixed32 + } + return 0 +} + +func (x *TestModel) GetOptionalSfixed64() int64 { + if x != nil && x.OptionalSfixed64 != nil { + return *x.OptionalSfixed64 + } + return 0 +} + +func (x *TestModel) GetRepeatedInt64() []int64 { + if x != nil { + return x.RepeatedInt64 + } + return nil +} + +func (x *TestModel) GetRepeatedUint64() []uint64 { + if x != nil { + return x.RepeatedUint64 + } + return nil +} + +func (x *TestModel) GetRepeatedFixed64() []uint64 { + if x != nil { + return x.RepeatedFixed64 + } + return nil +} + +func (x *TestModel) GetRepeatedSfixed64() []int64 { + if x != nil { + return x.RepeatedSfixed64 + } + return nil +} + +func (x *TestModel) GetRepeatedBool() []bool { + if x != nil { + return x.RepeatedBool + } + return nil +} + +func (x *TestModel) GetRepeatedString() []string { + if x != nil { + return x.RepeatedString + } + return nil +} + +func (x *TestModel) GetNestedChild_1() *TestModel_NestedChild { + if x != nil { + return x.NestedChild_1 + } + return nil +} + +func (x *TestModel) GetChildModel_1() *ChildModel1 { + if x != nil { + return x.ChildModel_1 + } + return nil +} + +func (x *TestModel) GetChildModel_2() []*ChildModel1 { + if x != nil { + return x.ChildModel_2 + } + return nil +} + +func (x *TestModel) GetBar() *ChildModel1 { + if x != nil { + return x.Bar + } + return nil +} + +func (m *TestModel) GetChildOneof1() isTestModel_ChildOneof1 { + if m != nil { + return m.ChildOneof1 + } + return nil +} + +func (x *TestModel) GetOneofMember1() string { + if x, ok := x.GetChildOneof1().(*TestModel_OneofMember1); ok { + return x.OneofMember1 + } + return "" +} + +func (x *TestModel) GetOneofMember2() bool { + if x, ok := x.GetChildOneof1().(*TestModel_OneofMember2); ok { + return x.OneofMember2 + } + return false +} + +func (x *TestModel) GetRecursiveChild() *TestModel { + if x != nil { + return x.RecursiveChild + } + return nil +} + +func (x *TestModel) GetChildStrMap() map[string]*ChildModel1 { + if x != nil { + return x.ChildStrMap + } + return nil +} + +func (x *TestModel) GetStrToIntMap() map[string]int32 { + if x != nil { + return x.StrToIntMap + } + return nil +} + +func (x *TestModel) GetStrToStrMap() map[string]string { + if x != nil { + return x.StrToStrMap + } + return nil +} + +func (x *TestModel) GetCategory() TestModel_Category { + if x != nil && x.Category != nil { + return *x.Category + } + return TestModel_UNKNOWN +} + +func (m *TestModel) GetType() isTestModel_Type { + if m != nil { + return m.Type + } + return nil +} + +func (x *TestModel) GetString_() string { + if x, ok := x.GetType().(*TestModel_String_); ok { + return x.String_ + } + return "" +} + +func (x *TestModel) GetInt64() int64 { + if x, ok := x.GetType().(*TestModel_Int64); ok { + return x.Int64 + } + return 0 +} + +func (x *TestModel) GetDouble() float64 { + if x, ok := x.GetType().(*TestModel_Double); ok { + return x.Double + } + return 0 +} + +func (x *TestModel) GetTemplate() string { + if x != nil && x.Template != nil { + return *x.Template + } + return "" +} + +func (x *TestModel) GetMsg() string { + if x != nil && x.Msg != nil { + return *x.Msg + } + return "" +} + +func (x *TestModel) GetArena() string { + if x != nil && x.Arena != nil { + return *x.Arena + } + return "" +} + +func (x *TestModel) GetImportedEnum() TestEnum { + if x != nil && x.ImportedEnum != nil { + return *x.ImportedEnum + } + return TestEnum_DEVICE_UNKNOWN +} + +func (x *TestModel) GetPhase() string { + if x != nil && x.Phase != nil { + return *x.Phase + } + return "" +} + +func (x *TestModel) GetClearPhase() bool { + if x != nil && x.ClearPhase != nil { + return *x.ClearPhase + } + return false +} + +type isTestModel_ChildOneof1 interface { + isTestModel_ChildOneof1() +} + +type TestModel_OneofMember1 struct { + OneofMember1 string `protobuf:"bytes,98,opt,name=oneof_member1,json=oneofMember1,proto3,oneof"` +} + +type TestModel_OneofMember2 struct { + OneofMember2 bool `protobuf:"varint,99,opt,name=oneof_member2,json=oneofMember2,proto3,oneof"` +} + +func (*TestModel_OneofMember1) isTestModel_ChildOneof1() {} + +func (*TestModel_OneofMember2) isTestModel_ChildOneof1() {} + +type isTestModel_Type interface { + isTestModel_Type() +} + +type TestModel_String_ struct { + String_ string `protobuf:"bytes,230,opt,name=string,proto3,oneof"` +} + +type TestModel_Int64 struct { + Int64 int64 `protobuf:"varint,231,opt,name=int64,proto3,oneof"` +} + +type TestModel_Double struct { + Double float64 `protobuf:"fixed64,232,opt,name=double,proto3,oneof"` +} + +func (*TestModel_String_) isTestModel_Type() {} + +func (*TestModel_Int64) isTestModel_Type() {} + +func (*TestModel_Double) isTestModel_Type() {} + +type StringMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *StringMessage) Reset() { + *x = StringMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_proxy_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StringMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StringMessage) ProtoMessage() {} + +func (x *StringMessage) ProtoReflect() protoreflect.Message { + mi := &file_proxy_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StringMessage.ProtoReflect.Descriptor instead. +func (*StringMessage) Descriptor() ([]byte, []int) { + return file_proxy_proto_rawDescGZIP(), []int{3} +} + +func (x *StringMessage) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +// optional bytes optional_bytes = 36; +type TestModel_NestedChild struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + NestedChildName *string `protobuf:"bytes,211,opt,name=nested_child_name,json=nestedChildName,proto3,oneof" json:"nested_child_name,omitempty"` +} + +func (x *TestModel_NestedChild) Reset() { + *x = TestModel_NestedChild{} + if protoimpl.UnsafeEnabled { + mi := &file_proxy_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TestModel_NestedChild) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TestModel_NestedChild) ProtoMessage() {} + +func (x *TestModel_NestedChild) ProtoReflect() protoreflect.Message { + mi := &file_proxy_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TestModel_NestedChild.ProtoReflect.Descriptor instead. +func (*TestModel_NestedChild) Descriptor() ([]byte, []int) { + return file_proxy_proto_rawDescGZIP(), []int{2, 0} +} + +func (x *TestModel_NestedChild) GetNestedChildName() string { + if x != nil && x.NestedChildName != nil { + return *x.NestedChildName + } + return "" +} + +var File_proxy_proto protoreflect.FileDescriptor + +var file_proxy_proto_rawDesc = []byte{ + 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x70, 0x62, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x6d, 0x0a, 0x0b, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x4d, 0x6f, 0x64, + 0x65, 0x6c, 0x31, 0x12, 0x1e, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x31, 0x18, + 0x2c, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x07, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x42, 0x31, + 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x74, 0x72, + 0x31, 0x18, 0x38, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x09, 0x63, 0x68, 0x69, 0x6c, 0x64, + 0x53, 0x74, 0x72, 0x31, 0x88, 0x01, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x68, 0x69, 0x6c, + 0x64, 0x5f, 0x62, 0x31, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x73, + 0x74, 0x72, 0x31, 0x22, 0xcf, 0x01, 0x0a, 0x0b, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x4d, 0x6f, 0x64, + 0x65, 0x6c, 0x33, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x62, 0x6f, 0x6f, 0x6c, 0x31, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x62, 0x6f, 0x6f, + 0x6c, 0x31, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x33, 0x32, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x03, 0x69, 0x33, 0x32, 0x12, 0x1c, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x6f, 0x70, 0x74, 0x53, 0x74, 0x72, 0x88, + 0x01, 0x01, 0x12, 0x1e, 0x0a, 0x08, 0x6f, 0x70, 0x74, 0x5f, 0x62, 0x6f, 0x6f, 0x6c, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x42, 0x6f, 0x6f, 0x6c, 0x88, + 0x01, 0x01, 0x12, 0x1c, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x5f, 0x69, 0x33, 0x32, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x05, 0x48, 0x02, 0x52, 0x06, 0x6f, 0x70, 0x74, 0x49, 0x33, 0x32, 0x88, 0x01, 0x01, + 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x6f, 0x70, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x42, 0x0b, 0x0a, 0x09, + 0x5f, 0x6f, 0x70, 0x74, 0x5f, 0x62, 0x6f, 0x6f, 0x6c, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x6f, 0x70, + 0x74, 0x5f, 0x69, 0x33, 0x32, 0x22, 0xdf, 0x15, 0x0a, 0x09, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x6f, + 0x64, 0x65, 0x6c, 0x12, 0x19, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x05, 0x48, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1f, + 0x0a, 0x0b, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x05, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x41, 0x72, 0x72, 0x61, 0x79, 0x12, + 0x25, 0x0a, 0x0c, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x05, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0b, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x44, 0x65, 0x70, 0x72, 0x65, 0x63, 0x12, 0x17, 0x0a, 0x04, 0x73, 0x74, 0x72, 0x31, 0x18, 0x73, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x04, 0x73, 0x74, 0x72, 0x31, 0x88, 0x01, 0x01, 0x12, + 0x13, 0x0a, 0x02, 0x62, 0x31, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x48, 0x04, 0x52, 0x02, 0x62, + 0x31, 0x88, 0x01, 0x01, 0x12, 0x13, 0x0a, 0x02, 0x62, 0x32, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, + 0x48, 0x05, 0x52, 0x02, 0x62, 0x32, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x73, 0x74, 0x72, + 0x32, 0x18, 0x32, 0x20, 0x01, 0x28, 0x09, 0x48, 0x06, 0x52, 0x04, 0x73, 0x74, 0x72, 0x32, 0x88, + 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x73, 0x74, 0x72, 0x33, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x07, 0x52, 0x04, 0x73, 0x74, 0x72, 0x33, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x18, 0x0e, 0x20, + 0x01, 0x28, 0x02, 0x48, 0x08, 0x52, 0x0d, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x46, + 0x6c, 0x6f, 0x61, 0x74, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x0f, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x61, 0x6c, 0x5f, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x01, + 0x48, 0x09, 0x52, 0x0e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x75, 0x62, + 0x6c, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x5f, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x18, 0x10, 0x20, 0x01, 0x28, 0x03, 0x48, 0x0a, 0x52, + 0x0d, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x88, 0x01, + 0x01, 0x12, 0x2c, 0x0a, 0x0f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x75, 0x69, + 0x6e, 0x74, 0x33, 0x32, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x0b, 0x52, 0x0e, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x55, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x88, 0x01, 0x01, 0x12, + 0x2c, 0x0a, 0x0f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x75, 0x69, 0x6e, 0x74, + 0x36, 0x34, 0x18, 0x12, 0x20, 0x01, 0x28, 0x04, 0x48, 0x0c, 0x52, 0x0e, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x61, 0x6c, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, + 0x0f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x69, 0x6e, 0x74, 0x33, 0x32, + 0x18, 0x13, 0x20, 0x01, 0x28, 0x11, 0x48, 0x0d, 0x52, 0x0e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x53, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x88, 0x01, 0x01, 0x12, 0x2c, 0x0a, 0x0f, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x18, 0x14, + 0x20, 0x01, 0x28, 0x12, 0x48, 0x0e, 0x52, 0x0e, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, + 0x53, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x33, 0x32, 0x18, 0x15, 0x20, + 0x01, 0x28, 0x07, 0x48, 0x0f, 0x52, 0x0f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x46, + 0x69, 0x78, 0x65, 0x64, 0x33, 0x32, 0x88, 0x01, 0x01, 0x12, 0x2e, 0x0a, 0x10, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x36, 0x34, 0x18, 0x16, 0x20, + 0x01, 0x28, 0x06, 0x48, 0x10, 0x52, 0x0f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x46, + 0x69, 0x78, 0x65, 0x64, 0x36, 0x34, 0x88, 0x01, 0x01, 0x12, 0x30, 0x0a, 0x11, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x66, 0x69, 0x78, 0x65, 0x64, 0x33, 0x32, 0x18, 0x17, + 0x20, 0x01, 0x28, 0x0f, 0x48, 0x11, 0x52, 0x10, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, + 0x53, 0x66, 0x69, 0x78, 0x65, 0x64, 0x33, 0x32, 0x88, 0x01, 0x01, 0x12, 0x30, 0x0a, 0x11, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x66, 0x69, 0x78, 0x65, 0x64, 0x36, 0x34, + 0x18, 0x18, 0x20, 0x01, 0x28, 0x10, 0x48, 0x12, 0x52, 0x10, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x53, 0x66, 0x69, 0x78, 0x65, 0x64, 0x36, 0x34, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, + 0x0e, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x18, + 0x19, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0d, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x49, + 0x6e, 0x74, 0x36, 0x34, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x18, 0x1a, 0x20, 0x03, 0x28, 0x04, 0x52, 0x0e, 0x72, + 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x12, 0x29, 0x0a, + 0x10, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x36, + 0x34, 0x18, 0x1b, 0x20, 0x03, 0x28, 0x06, 0x52, 0x0f, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x46, 0x69, 0x78, 0x65, 0x64, 0x36, 0x34, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x70, 0x65, + 0x61, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x66, 0x69, 0x78, 0x65, 0x64, 0x36, 0x34, 0x18, 0x1c, 0x20, + 0x03, 0x28, 0x10, 0x52, 0x10, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x53, 0x66, 0x69, + 0x78, 0x65, 0x64, 0x36, 0x34, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, + 0x64, 0x5f, 0x62, 0x6f, 0x6f, 0x6c, 0x18, 0x1d, 0x20, 0x03, 0x28, 0x08, 0x52, 0x0c, 0x72, 0x65, + 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x6f, 0x6f, 0x6c, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, + 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x23, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x53, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x12, 0x4a, 0x0a, 0x0e, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x68, + 0x69, 0x6c, 0x64, 0x5f, 0x31, 0x18, 0xd4, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x6c, + 0x2e, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x48, 0x13, 0x52, 0x0c, + 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x31, 0x88, 0x01, 0x01, 0x12, + 0x3e, 0x0a, 0x0d, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x31, + 0x18, 0xde, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x70, + 0x62, 0x2e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x31, 0x48, 0x14, 0x52, + 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x31, 0x88, 0x01, 0x01, 0x12, + 0x39, 0x0a, 0x0d, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x32, + 0x18, 0xdf, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x70, + 0x62, 0x2e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x31, 0x52, 0x0b, 0x63, + 0x68, 0x69, 0x6c, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x32, 0x12, 0x2c, 0x0a, 0x03, 0x62, 0x61, + 0x72, 0x18, 0xe0, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, + 0x70, 0x62, 0x2e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x31, 0x48, 0x15, + 0x52, 0x03, 0x62, 0x61, 0x72, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0d, 0x6f, 0x6e, 0x65, 0x6f, + 0x66, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x31, 0x18, 0x62, 0x20, 0x01, 0x28, 0x09, 0x48, + 0x00, 0x52, 0x0c, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x31, 0x12, + 0x25, 0x0a, 0x0d, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x32, + 0x18, 0x63, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0c, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x4d, + 0x65, 0x6d, 0x62, 0x65, 0x72, 0x32, 0x12, 0x41, 0x0a, 0x0f, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, + 0x69, 0x76, 0x65, 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x18, 0xe2, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4d, + 0x6f, 0x64, 0x65, 0x6c, 0x48, 0x16, 0x52, 0x0e, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, + 0x65, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x88, 0x01, 0x01, 0x12, 0x48, 0x0a, 0x0d, 0x63, 0x68, 0x69, + 0x6c, 0x64, 0x5f, 0x73, 0x74, 0x72, 0x5f, 0x6d, 0x61, 0x70, 0x18, 0xe3, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x73, 0x74, + 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x72, 0x4d, 0x61, + 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x72, + 0x4d, 0x61, 0x70, 0x12, 0x49, 0x0a, 0x0e, 0x73, 0x74, 0x72, 0x5f, 0x74, 0x6f, 0x5f, 0x69, 0x6e, + 0x74, 0x5f, 0x6d, 0x61, 0x70, 0x18, 0xe4, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, + 0x72, 0x6f, 0x78, 0x79, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x6c, + 0x2e, 0x53, 0x74, 0x72, 0x54, 0x6f, 0x49, 0x6e, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x54, 0x6f, 0x49, 0x6e, 0x74, 0x4d, 0x61, 0x70, 0x12, 0x49, + 0x0a, 0x0e, 0x73, 0x74, 0x72, 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x74, 0x72, 0x5f, 0x6d, 0x61, 0x70, + 0x18, 0xe5, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x70, + 0x62, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x53, 0x74, 0x72, 0x54, + 0x6f, 0x53, 0x74, 0x72, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x73, 0x74, + 0x72, 0x54, 0x6f, 0x53, 0x74, 0x72, 0x4d, 0x61, 0x70, 0x12, 0x3c, 0x0a, 0x08, 0x63, 0x61, 0x74, + 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x25, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x70, 0x72, + 0x6f, 0x78, 0x79, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, + 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x48, 0x17, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, + 0x67, 0x6f, 0x72, 0x79, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x18, 0xe6, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x06, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x12, 0x17, 0x0a, 0x05, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x18, 0xe7, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x48, 0x01, 0x52, 0x05, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x12, 0x19, 0x0a, 0x06, 0x64, + 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x18, 0xe8, 0x01, 0x20, 0x01, 0x28, 0x01, 0x48, 0x01, 0x52, 0x06, + 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x18, 0xe9, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x18, 0x52, 0x08, 0x74, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x88, 0x01, 0x01, 0x12, 0x16, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, + 0xea, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x19, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x88, 0x01, 0x01, + 0x12, 0x1a, 0x0a, 0x05, 0x61, 0x72, 0x65, 0x6e, 0x61, 0x18, 0xeb, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x1a, 0x52, 0x05, 0x61, 0x72, 0x65, 0x6e, 0x61, 0x88, 0x01, 0x01, 0x12, 0x3c, 0x0a, 0x0d, + 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x18, 0xee, 0x01, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x70, 0x62, 0x2e, 0x54, + 0x65, 0x73, 0x74, 0x45, 0x6e, 0x75, 0x6d, 0x48, 0x1b, 0x52, 0x0c, 0x69, 0x6d, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x45, 0x6e, 0x75, 0x6d, 0x88, 0x01, 0x01, 0x12, 0x1a, 0x0a, 0x05, 0x70, 0x68, + 0x61, 0x73, 0x65, 0x18, 0xef, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x1c, 0x52, 0x05, 0x70, 0x68, + 0x61, 0x73, 0x65, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0b, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x5f, + 0x70, 0x68, 0x61, 0x73, 0x65, 0x18, 0xf0, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x1d, 0x52, 0x0a, + 0x63, 0x6c, 0x65, 0x61, 0x72, 0x50, 0x68, 0x61, 0x73, 0x65, 0x88, 0x01, 0x01, 0x1a, 0x55, 0x0a, + 0x0b, 0x4e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x12, 0x30, 0x0a, 0x11, + 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0xd3, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0f, 0x6e, 0x65, 0x73, 0x74, + 0x65, 0x64, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x42, 0x14, + 0x0a, 0x12, 0x5f, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x1a, 0x54, 0x0a, 0x10, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x72, + 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x78, + 0x79, 0x70, 0x62, 0x2e, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x31, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3e, 0x0a, 0x10, 0x53, 0x74, + 0x72, 0x54, 0x6f, 0x49, 0x6e, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3e, 0x0a, 0x10, 0x53, 0x74, + 0x72, 0x54, 0x6f, 0x53, 0x74, 0x72, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x47, 0x0a, 0x08, 0x43, 0x61, + 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, + 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x53, 0x10, 0x05, 0x12, + 0x08, 0x0a, 0x04, 0x4e, 0x45, 0x57, 0x53, 0x10, 0x06, 0x12, 0x09, 0x0a, 0x05, 0x56, 0x49, 0x44, + 0x45, 0x4f, 0x10, 0x07, 0x12, 0x0d, 0x0a, 0x05, 0x52, 0x41, 0x44, 0x49, 0x4f, 0x10, 0x08, 0x1a, + 0x02, 0x08, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x6f, 0x6e, 0x65, + 0x6f, 0x66, 0x31, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x73, 0x74, 0x72, 0x31, 0x42, 0x05, + 0x0a, 0x03, 0x5f, 0x62, 0x31, 0x42, 0x05, 0x0a, 0x03, 0x5f, 0x62, 0x32, 0x42, 0x07, 0x0a, 0x05, + 0x5f, 0x73, 0x74, 0x72, 0x32, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x73, 0x74, 0x72, 0x33, 0x42, 0x11, + 0x0a, 0x0f, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x6c, 0x6f, 0x61, + 0x74, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x64, + 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x61, 0x6c, 0x5f, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x75, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x42, 0x12, 0x0a, 0x10, + 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, + 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x69, + 0x6e, 0x74, 0x33, 0x32, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, + 0x6c, 0x5f, 0x73, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, 0x33, 0x32, 0x42, 0x13, 0x0a, + 0x11, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x78, 0x65, 0x64, + 0x36, 0x34, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, + 0x73, 0x66, 0x69, 0x78, 0x65, 0x64, 0x33, 0x32, 0x42, 0x14, 0x0a, 0x12, 0x5f, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x5f, 0x73, 0x66, 0x69, 0x78, 0x65, 0x64, 0x36, 0x34, 0x42, 0x11, + 0x0a, 0x0f, 0x5f, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, + 0x31, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x65, + 0x6c, 0x5f, 0x31, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x62, 0x61, 0x72, 0x42, 0x12, 0x0a, 0x10, 0x5f, + 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x5f, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x42, + 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x42, 0x0b, 0x0a, 0x09, + 0x5f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x6d, 0x73, + 0x67, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x61, 0x72, 0x65, 0x6e, 0x61, 0x42, 0x10, 0x0a, 0x0e, 0x5f, + 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x65, 0x6e, 0x75, 0x6d, 0x42, 0x08, 0x0a, + 0x06, 0x5f, 0x70, 0x68, 0x61, 0x73, 0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x63, 0x6c, 0x65, 0x61, + 0x72, 0x5f, 0x70, 0x68, 0x61, 0x73, 0x65, 0x22, 0x25, 0x0a, 0x0d, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x59, + 0x0a, 0x08, 0x54, 0x65, 0x73, 0x74, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, + 0x56, 0x49, 0x43, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x13, + 0x0a, 0x0f, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x4b, 0x45, 0x59, 0x42, 0x4f, 0x41, 0x52, + 0x44, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x4d, 0x4f, + 0x55, 0x53, 0x45, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x45, 0x56, 0x49, 0x43, 0x45, 0x5f, + 0x4d, 0x4f, 0x4e, 0x49, 0x54, 0x4f, 0x52, 0x10, 0x03, 0x32, 0x8a, 0x02, 0x0a, 0x0a, 0x41, 0x50, + 0x49, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x04, 0x45, 0x63, 0x68, 0x6f, + 0x12, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, + 0x70, 0x62, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x3a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, + 0x05, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x12, 0x52, 0x0a, 0x11, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x6f, + 0x64, 0x65, 0x6c, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x72, + 0x6f, 0x78, 0x79, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x1a, + 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x70, 0x62, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x4d, 0x6f, + 0x64, 0x65, 0x6c, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x3a, 0x01, 0x2a, 0x22, 0x0a, + 0x2f, 0x74, 0x65, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x5a, 0x0a, 0x09, 0x50, 0x61, + 0x74, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x12, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x70, + 0x62, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, + 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x70, 0x62, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x3a, + 0x01, 0x2a, 0x22, 0x12, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x2f, 0x7b, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x7d, 0x42, 0x3f, 0x5a, 0x3d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x61, 0x73, 0x2f, 0x69, 0x6e, 0x74, 0x65, + 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x70, 0x62, 0x3b, + 0x70, 0x72, 0x6f, 0x78, 0x79, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_proxy_proto_rawDescOnce sync.Once + file_proxy_proto_rawDescData = file_proxy_proto_rawDesc +) + +func file_proxy_proto_rawDescGZIP() []byte { + file_proxy_proto_rawDescOnce.Do(func() { + file_proxy_proto_rawDescData = protoimpl.X.CompressGZIP(file_proxy_proto_rawDescData) + }) + return file_proxy_proto_rawDescData +} + +var file_proxy_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_proxy_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_proxy_proto_goTypes = []interface{}{ + (TestEnum)(0), // 0: proxypb.TestEnum + (TestModel_Category)(0), // 1: proxypb.TestModel.Category + (*ChildModel1)(nil), // 2: proxypb.ChildModel1 + (*ChildModel3)(nil), // 3: proxypb.ChildModel3 + (*TestModel)(nil), // 4: proxypb.TestModel + (*StringMessage)(nil), // 5: proxypb.StringMessage + (*TestModel_NestedChild)(nil), // 6: proxypb.TestModel.NestedChild + nil, // 7: proxypb.TestModel.ChildStrMapEntry + nil, // 8: proxypb.TestModel.StrToIntMapEntry + nil, // 9: proxypb.TestModel.StrToStrMapEntry +} +var file_proxy_proto_depIdxs = []int32{ + 6, // 0: proxypb.TestModel.nested_child_1:type_name -> proxypb.TestModel.NestedChild + 2, // 1: proxypb.TestModel.child_model_1:type_name -> proxypb.ChildModel1 + 2, // 2: proxypb.TestModel.child_model_2:type_name -> proxypb.ChildModel1 + 2, // 3: proxypb.TestModel.bar:type_name -> proxypb.ChildModel1 + 4, // 4: proxypb.TestModel.recursive_child:type_name -> proxypb.TestModel + 7, // 5: proxypb.TestModel.child_str_map:type_name -> proxypb.TestModel.ChildStrMapEntry + 8, // 6: proxypb.TestModel.str_to_int_map:type_name -> proxypb.TestModel.StrToIntMapEntry + 9, // 7: proxypb.TestModel.str_to_str_map:type_name -> proxypb.TestModel.StrToStrMapEntry + 1, // 8: proxypb.TestModel.category:type_name -> proxypb.TestModel.Category + 0, // 9: proxypb.TestModel.imported_enum:type_name -> proxypb.TestEnum + 2, // 10: proxypb.TestModel.ChildStrMapEntry.value:type_name -> proxypb.ChildModel1 + 5, // 11: proxypb.APIService.Echo:input_type -> proxypb.StringMessage + 4, // 12: proxypb.APIService.TestModelEndpoint:input_type -> proxypb.TestModel + 5, // 13: proxypb.APIService.PathParam:input_type -> proxypb.StringMessage + 5, // 14: proxypb.APIService.Echo:output_type -> proxypb.StringMessage + 4, // 15: proxypb.APIService.TestModelEndpoint:output_type -> proxypb.TestModel + 5, // 16: proxypb.APIService.PathParam:output_type -> proxypb.StringMessage + 14, // [14:17] is the sub-list for method output_type + 11, // [11:14] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name +} + +func init() { file_proxy_proto_init() } +func file_proxy_proto_init() { + if File_proxy_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_proxy_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChildModel1); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proxy_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ChildModel3); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proxy_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TestModel); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proxy_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StringMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proxy_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TestModel_NestedChild); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_proxy_proto_msgTypes[0].OneofWrappers = []interface{}{} + file_proxy_proto_msgTypes[1].OneofWrappers = []interface{}{} + file_proxy_proto_msgTypes[2].OneofWrappers = []interface{}{ + (*TestModel_OneofMember1)(nil), + (*TestModel_OneofMember2)(nil), + (*TestModel_String_)(nil), + (*TestModel_Int64)(nil), + (*TestModel_Double)(nil), + } + file_proxy_proto_msgTypes[4].OneofWrappers = []interface{}{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_proxy_proto_rawDesc, + NumEnums: 2, + NumMessages: 8, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_proxy_proto_goTypes, + DependencyIndexes: file_proxy_proto_depIdxs, + EnumInfos: file_proxy_proto_enumTypes, + MessageInfos: file_proxy_proto_msgTypes, + }.Build() + File_proxy_proto = out.File + file_proxy_proto_rawDesc = nil + file_proxy_proto_goTypes = nil + file_proxy_proto_depIdxs = nil +} diff --git a/integration/proxypb/proxy_grpc.pb.go b/integration/proxypb/proxy_grpc.pb.go new file mode 100644 index 0000000..4185f3b --- /dev/null +++ b/integration/proxypb/proxy_grpc.pb.go @@ -0,0 +1,183 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc v4.25.0 +// source: proxy.proto + +package proxypb + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + APIService_Echo_FullMethodName = "/proxypb.APIService/Echo" + APIService_TestModelEndpoint_FullMethodName = "/proxypb.APIService/TestModelEndpoint" + APIService_PathParam_FullMethodName = "/proxypb.APIService/PathParam" +) + +// APIServiceClient is the client API for APIService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type APIServiceClient interface { + Echo(ctx context.Context, in *StringMessage, opts ...grpc.CallOption) (*StringMessage, error) + TestModelEndpoint(ctx context.Context, in *TestModel, opts ...grpc.CallOption) (*TestModel, error) + PathParam(ctx context.Context, in *StringMessage, opts ...grpc.CallOption) (*StringMessage, error) +} + +type aPIServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewAPIServiceClient(cc grpc.ClientConnInterface) APIServiceClient { + return &aPIServiceClient{cc} +} + +func (c *aPIServiceClient) Echo(ctx context.Context, in *StringMessage, opts ...grpc.CallOption) (*StringMessage, error) { + out := new(StringMessage) + err := c.cc.Invoke(ctx, APIService_Echo_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIServiceClient) TestModelEndpoint(ctx context.Context, in *TestModel, opts ...grpc.CallOption) (*TestModel, error) { + out := new(TestModel) + err := c.cc.Invoke(ctx, APIService_TestModelEndpoint_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIServiceClient) PathParam(ctx context.Context, in *StringMessage, opts ...grpc.CallOption) (*StringMessage, error) { + out := new(StringMessage) + err := c.cc.Invoke(ctx, APIService_PathParam_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// APIServiceServer is the server API for APIService service. +// All implementations must embed UnimplementedAPIServiceServer +// for forward compatibility +type APIServiceServer interface { + Echo(context.Context, *StringMessage) (*StringMessage, error) + TestModelEndpoint(context.Context, *TestModel) (*TestModel, error) + PathParam(context.Context, *StringMessage) (*StringMessage, error) + mustEmbedUnimplementedAPIServiceServer() +} + +// UnimplementedAPIServiceServer must be embedded to have forward compatible implementations. +type UnimplementedAPIServiceServer struct { +} + +func (UnimplementedAPIServiceServer) Echo(context.Context, *StringMessage) (*StringMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") +} +func (UnimplementedAPIServiceServer) TestModelEndpoint(context.Context, *TestModel) (*TestModel, error) { + return nil, status.Errorf(codes.Unimplemented, "method TestModelEndpoint not implemented") +} +func (UnimplementedAPIServiceServer) PathParam(context.Context, *StringMessage) (*StringMessage, error) { + return nil, status.Errorf(codes.Unimplemented, "method PathParam not implemented") +} +func (UnimplementedAPIServiceServer) mustEmbedUnimplementedAPIServiceServer() {} + +// UnsafeAPIServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to APIServiceServer will +// result in compilation errors. +type UnsafeAPIServiceServer interface { + mustEmbedUnimplementedAPIServiceServer() +} + +func RegisterAPIServiceServer(s grpc.ServiceRegistrar, srv APIServiceServer) { + s.RegisterService(&APIService_ServiceDesc, srv) +} + +func _APIService_Echo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StringMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServiceServer).Echo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: APIService_Echo_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServiceServer).Echo(ctx, req.(*StringMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _APIService_TestModelEndpoint_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TestModel) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServiceServer).TestModelEndpoint(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: APIService_TestModelEndpoint_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServiceServer).TestModelEndpoint(ctx, req.(*TestModel)) + } + return interceptor(ctx, in, info, handler) +} + +func _APIService_PathParam_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StringMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServiceServer).PathParam(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: APIService_PathParam_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServiceServer).PathParam(ctx, req.(*StringMessage)) + } + return interceptor(ctx, in, info, handler) +} + +// APIService_ServiceDesc is the grpc.ServiceDesc for APIService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var APIService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "proxypb.APIService", + HandlerType: (*APIServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Echo", + Handler: _APIService_Echo_Handler, + }, + { + MethodName: "TestModelEndpoint", + Handler: _APIService_TestModelEndpoint_Handler, + }, + { + MethodName: "PathParam", + Handler: _APIService_PathParam_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "proxy.proto", +} diff --git a/internal/gen/proxy.go b/internal/gen/proxy.go index 50c90f0..e90f4ed 100644 --- a/internal/gen/proxy.go +++ b/internal/gen/proxy.go @@ -2,6 +2,7 @@ package gen import ( "bytes" + "cmp" "fmt" "os" "path" @@ -163,8 +164,8 @@ func (g *Generator) mapSpec(og *gen.Generator) (mapping Mapping, _ error) { } for s, m := range services { - slices.SortStableFunc(m, func(a, b MethodMapping) bool { - return a.ProtoName < b.ProtoName + slices.SortStableFunc(m, func(a, b MethodMapping) int { + return cmp.Compare(a.ProtoName, b.ProtoName) }) mapping.Services = append(mapping.Services, ServiceMapping{ ProtoName: s.GoName, @@ -174,14 +175,14 @@ func (g *Generator) mapSpec(og *gen.Generator) (mapping Mapping, _ error) { } // Ensure output is stable. - slices.SortStableFunc(mapping.Messages, func(a, b MessageMapping) bool { - return a.ProtoType < b.ProtoType + slices.SortStableFunc(mapping.Messages, func(a, b MessageMapping) int { + return cmp.Compare(a.ProtoType, b.ProtoType) }) - slices.SortStableFunc(mapping.Enums, func(a, b EnumMapping) bool { - return a.ProtoType < b.ProtoType + slices.SortStableFunc(mapping.Enums, func(a, b EnumMapping) int { + return cmp.Compare(a.ProtoType, b.ProtoType) }) - slices.SortStableFunc(mapping.Services, func(a, b ServiceMapping) bool { - return a.ProtoName < b.ProtoName + slices.SortStableFunc(mapping.Services, func(a, b ServiceMapping) int { + return cmp.Compare(a.ProtoName, b.ProtoName) }) return mapping, nil } From d13fbbe59592b1a2d59180b0bf3fa12469f5ba6e Mon Sep 17 00:00:00 2001 From: tdakkota Date: Mon, 13 Nov 2023 10:42:50 +0300 Subject: [PATCH 3/7] chore: fix linter issues --- internal/gen/generator.go | 3 +++ internal/gen/proxy.go | 50 +++++++++++++++++++++++---------------- internal/gen/template.go | 1 + 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/internal/gen/generator.go b/internal/gen/generator.go index 90005f6..8e98fe8 100644 --- a/internal/gen/generator.go +++ b/internal/gen/generator.go @@ -130,6 +130,8 @@ type Generator struct { requests map[string]struct{} descriptorNames map[string]struct{} + pkgName string + messages map[string]*protogen.Message enums map[string]*protogen.Enum ops map[string]*methodSet @@ -160,6 +162,7 @@ func (g *Generator) init() { g.requests = make(map[string]struct{}) g.descriptorNames = make(map[string]struct{}) + g.pkgName = "oas" g.messages = map[string]*protogen.Message{} g.enums = map[string]*protogen.Enum{} diff --git a/internal/gen/proxy.go b/internal/gen/proxy.go index e90f4ed..39e2533 100644 --- a/internal/gen/proxy.go +++ b/internal/gen/proxy.go @@ -77,7 +77,7 @@ func (g *Generator) WriteProxy(plugin *protogen.Plugin) error { return errors.Wrap(err, "write ogen files") } imports[oasPath] = packageImport{ - Name: "oas", + Name: protogen.GoPackageName(g.pkgName), Path: oasPath, } @@ -121,12 +121,12 @@ func (g *Generator) WriteProxy(plugin *protogen.Plugin) error { } func (g *Generator) mapSpec(og *gen.Generator) (mapping Mapping, _ error) { - refName := func(ref jsonschema.Ref) string { + refName := func(ref jsonschema.Ref) (string, error) { idx := strings.LastIndexByte(ref.Ptr, '/') if idx < 0 { - panic(fmt.Sprintf("unexpected ref: %q", ref)) + return "", errors.Errorf("unexpected ref: %q", ref) } - return ref.Ptr[idx+1:] + return ref.Ptr[idx+1:], nil } for _, typ := range og.Types() { @@ -135,7 +135,10 @@ func (g *Generator) mapSpec(og *gen.Generator) (mapping Mapping, _ error) { continue } - name := refName(s.Ref) + name, err := refName(s.Ref) + if err != nil { + return mapping, errors.Wrapf(err, "map type %q", typ.Name) + } if m, ok := g.messages[name]; ok { mapping.Messages = append(mapping.Messages, g.mapMessage(typ, m)) continue @@ -148,19 +151,24 @@ func (g *Generator) mapSpec(og *gen.Generator) (mapping Mapping, _ error) { services := map[*protogen.Service][]MethodMapping{} for _, op := range og.Operations() { - tmpl := op.Spec.Path.String() - ms, ok := g.ops[tmpl] - if !ok { - panic(fmt.Sprintf("unknown path %q", tmpl)) - } + if err := func() error { + tmpl := op.Spec.Path.String() + ms, ok := g.ops[tmpl] + if !ok { + return errors.Errorf("unknown path %q", tmpl) + } - httpMethod := strings.ToUpper(op.Spec.HTTPMethod) - rule, ok := ms.Methods[httpMethod] - if !ok { - panic(fmt.Sprintf("can't find gRPC method for %s %s", httpMethod, op.Spec.Path)) - } + httpMethod := strings.ToUpper(op.Spec.HTTPMethod) + rule, ok := ms.Methods[httpMethod] + if !ok { + return errors.Errorf("can't find gRPC method for %s %s", httpMethod, op.Spec.Path) + } - services[rule.Service] = append(services[rule.Service], g.mapMethod(op, rule)) + services[rule.Service] = append(services[rule.Service], g.mapMethod(op, rule)) + return nil + }(); err != nil { + return mapping, errors.Wrapf(err, "map operation %s", op.PrettyOperationID()) + } } for s, m := range services { @@ -206,7 +214,7 @@ func (g *Generator) mapMethod(ogenOp *ir.Operation, mr methodRule) MethodMapping input := g.mapInput(mr.Rule.Body, ogenOp, mr.Method.Input) output := OutputMapping{ ProtoType: mr.Method.Output.GoIdent.GoName, - OgenType: qualifiedOgenType("oas", ogenOp.Responses.GoType()), + OgenType: qualifiedOgenType(g.pkgName, ogenOp.Responses.GoType()), Ogen: ogenOp.Responses.Type, Proto: mr.Method.Output, } @@ -217,7 +225,7 @@ func (g *Generator) mapMethod(ogenOp *ir.Operation, mr methodRule) MethodMapping ProtoName: mr.Method.GoName, OgenName: ogenOp.Name, OperationID: ogenOp.Spec.OperationID, - ParamsType: qualifiedOgenType("oas", ogenOp.Name+"Params"), + ParamsType: qualifiedOgenType(g.pkgName, ogenOp.Name+"Params"), Input: input, Output: output, } @@ -250,7 +258,7 @@ func (g *Generator) mapInput(bodySel string, ogenOp *ir.Operation, msg *protogen if req := ogenOp.Request; req != nil { body := &BodyMapping{ - OgenType: qualifiedOgenType("oas", req.GoType()), + OgenType: qualifiedOgenType(g.pkgName, req.GoType()), Proto: msg, Ogen: req, } @@ -277,7 +285,7 @@ func (g *Generator) mapSelector(sel string, ogenType *ir.Type, protoType *protog func (g *Generator) mapMessage(ogenType *ir.Type, protoType *protogen.Message) MessageMapping { m := MessageMapping{ ProtoType: protoType.GoIdent.GoName, - OgenType: qualifiedOgenType("oas", ogenType.Go()), + OgenType: qualifiedOgenType(g.pkgName, ogenType.Go()), } ogenFields := make(map[string]*ir.Field, len(ogenType.Fields)) @@ -310,7 +318,7 @@ func (g *Generator) mapEnum(o *ir.Type, p *protogen.Enum) EnumMapping { protoType := p.GoIdent.GoName return EnumMapping{ ProtoType: protoType, - OgenType: qualifiedOgenType("oas", o.Go()), + OgenType: qualifiedOgenType(g.pkgName, o.Go()), EnumNameMap: protoType + "_name", EnumValueMap: protoType + "_value", } diff --git a/internal/gen/template.go b/internal/gen/template.go index 1c65162..14468bf 100644 --- a/internal/gen/template.go +++ b/internal/gen/template.go @@ -13,6 +13,7 @@ import ( "github.com/ogen-go/ogen/gen/ir" ) +// FieldElem carries mapped field information. type FieldElem struct { Ogen *ir.Type Proto *protogen.Field From f44ff70b52be6b482d0f7b3d528413db7115958a Mon Sep 17 00:00:00 2001 From: tdakkota Date: Mon, 13 Nov 2023 10:48:08 +0300 Subject: [PATCH 4/7] refactor(gen): use `cmp` and `slices` from `stdlib` --- internal/gen/generator.go | 7 ++++--- internal/gen/proxy.go | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/internal/gen/generator.go b/internal/gen/generator.go index 8e98fe8..69b06bc 100644 --- a/internal/gen/generator.go +++ b/internal/gen/generator.go @@ -2,6 +2,7 @@ package gen import ( "bytes" + "cmp" "encoding/json" "fmt" "net/http" @@ -256,7 +257,7 @@ func (g *Generator) mkInput(rule HTTPRule, m *protogen.Method, op *ogen.Operatio values := maps.Values(fields) // Sort to make output stable. slices.SortStableFunc(values, func(a, b *protogen.Field) int { - return strings.Compare(string(a.Desc.FullName()), string(b.Desc.FullName())) + return cmp.Compare(string(a.Desc.FullName()), string(b.Desc.FullName())) }) if err := g.mkJSONFields(s, values); err != nil { return "", errors.Wrap(err, "make requestBody schema") @@ -296,9 +297,9 @@ func (g *Generator) mkInput(rule HTTPRule, m *protogen.Method, op *ogen.Operatio // Sort to make output stable. slices.SortStableFunc(op.Parameters, func(a, b *ogen.Parameter) int { if a.In != b.In { - return strings.Compare(a.In, b.In) + return cmp.Compare(a.In, b.In) } - return strings.Compare(a.Name, b.Name) + return cmp.Compare(a.Name, b.Name) }) return tmpl.String(), nil diff --git a/internal/gen/proxy.go b/internal/gen/proxy.go index 39e2533..2fb1177 100644 --- a/internal/gen/proxy.go +++ b/internal/gen/proxy.go @@ -6,12 +6,12 @@ import ( "fmt" "os" "path" + "slices" "strings" "sync" "github.com/go-faster/errors" "golang.org/x/exp/maps" - "golang.org/x/exp/slices" goimports "golang.org/x/tools/imports" "google.golang.org/protobuf/compiler/protogen" From d1a6df89f38c4c8cefadd82019ea3fbcfa73428f Mon Sep 17 00:00:00 2001 From: tdakkota Date: Mon, 13 Nov 2023 11:44:26 +0300 Subject: [PATCH 5/7] chore(gen): add `gotype` annotations --- internal/gen/_template/handler.tmpl | 1 + internal/gen/_template/header.tmpl | 1 + internal/gen/_template/messages.tmpl | 1 + 3 files changed, 3 insertions(+) diff --git a/internal/gen/_template/handler.tmpl b/internal/gen/_template/handler.tmpl index 98053fe..dfbeadc 100644 --- a/internal/gen/_template/handler.tmpl +++ b/internal/gen/_template/handler.tmpl @@ -1,3 +1,4 @@ +{{- /*gotype: github.com/ogen-go/protoc-gen-oas/internal/gen.TemplateConfig*/ -}} {{ define "handler" }} {{- template "header" $ }} diff --git a/internal/gen/_template/header.tmpl b/internal/gen/_template/header.tmpl index 4b5e5ad..d732966 100644 --- a/internal/gen/_template/header.tmpl +++ b/internal/gen/_template/header.tmpl @@ -1,3 +1,4 @@ +{{- /*gotype: github.com/ogen-go/protoc-gen-oas/internal/gen.TemplateConfig*/ -}} {{ define "header" }} // Code generated by protoc-gen-oas, DO NOT EDIT. package {{ $.PackageName }} diff --git a/internal/gen/_template/messages.tmpl b/internal/gen/_template/messages.tmpl index cfc16f2..2fc5758 100644 --- a/internal/gen/_template/messages.tmpl +++ b/internal/gen/_template/messages.tmpl @@ -1,3 +1,4 @@ +{{- /*gotype: github.com/ogen-go/protoc-gen-oas/internal/gen.TemplateConfig*/ -}} {{ define "messages" }} {{- template "header" $ }} From 59e6634eae79a75a7169b4a08433e01fda594d0c Mon Sep 17 00:00:00 2001 From: tdakkota Date: Wed, 6 Nov 2024 13:16:44 +0300 Subject: [PATCH 6/7] fix(gen): properly handle recursive schemas --- internal/gen/schema.go | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/internal/gen/schema.go b/internal/gen/schema.go index e3342e4..3819d22 100644 --- a/internal/gen/schema.go +++ b/internal/gen/schema.go @@ -51,7 +51,18 @@ func mkEnumOgenSchema(ed protoreflect.EnumDescriptor) *ogen.Schema { } func (g *Generator) mkSchema(msg *protogen.Message) error { - s := ogen.NewSchema().SetType("object") + name := descriptorName(msg.Desc) + if g.hasDescriptorName(name) { + return nil + } + g.setDescriptorName(name) + + s := ogen.NewSchema() + { + g.spec.AddSchema(name, s) + g.messages[name] = msg + } + s.SetType("object") if err := g.mkJSONFields(s, msg.Fields); err != nil { return err @@ -62,22 +73,13 @@ func (g *Generator) mkSchema(msg *protogen.Message) error { continue } - if field.Message != nil { - name := descriptorName(field.Desc) - if g.hasDescriptorName(name) { - s.SetRef(descriptorRef(field.Message.Desc)) - - continue - } - - g.setDescriptorName(name) - - if err := g.mkSchema(field.Message); err != nil { + if fmsg := field.Message; fmsg != nil { + if err := g.mkSchema(fmsg); err != nil { return err } } - if field.Enum != nil { - g.mkEnum(field.Enum) + if enum := field.Enum; enum != nil { + g.mkEnum(enum) } } @@ -91,9 +93,6 @@ func (g *Generator) mkSchema(msg *protogen.Message) error { g.mkEnum(e) } - name := descriptorName(msg.Desc) - g.spec.AddSchema(name, s) - g.messages[name] = msg return nil } From d9aa4bab1630c751bad5c3e9b01e9998bd2d1951 Mon Sep 17 00:00:00 2001 From: tdakkota Date: Wed, 6 Nov 2024 13:17:00 +0300 Subject: [PATCH 7/7] chore: commit generated files --- integration/proxypb/oas/oas_cfg_gen.go | 41 +++--- integration/proxypb/oas/oas_client_gen.go | 17 +-- integration/proxypb/oas/oas_handlers_gen.go | 74 ++++++---- integration/proxypb/oas/oas_json_gen.go | 33 +++++ integration/proxypb/oas/oas_labeler_gen.go | 42 ++++++ .../proxypb/oas/oas_response_decoders_gen.go | 9 ++ .../proxypb/oas/oas_response_encoders_gen.go | 6 +- integration/proxypb/oas/oas_router_gen.go | 30 ++++- integration/proxypb/oas/oas_validators_gen.go | 4 + integration/proxypb/openapi.yaml | 17 +++ integration/proxypb/proxy.pb.go | 126 ++++-------------- integration/proxypb/proxy_grpc.pb.go | 36 +++-- 12 files changed, 261 insertions(+), 174 deletions(-) create mode 100644 integration/proxypb/oas/oas_labeler_gen.go diff --git a/integration/proxypb/oas/oas_cfg_gen.go b/integration/proxypb/oas/oas_cfg_gen.go index ddeeee7..fb02c63 100644 --- a/integration/proxypb/oas/oas_cfg_gen.go +++ b/integration/proxypb/oas/oas_cfg_gen.go @@ -44,7 +44,9 @@ func (cfg *otelConfig) initOTEL() { cfg.Tracer = cfg.TracerProvider.Tracer(otelogen.Name, trace.WithInstrumentationVersion(otelogen.SemVersion()), ) - cfg.Meter = cfg.MeterProvider.Meter(otelogen.Name) + cfg.Meter = cfg.MeterProvider.Meter(otelogen.Name, + metric.WithInstrumentationVersion(otelogen.SemVersion()), + ) } // ErrorHandler is error handler. @@ -65,15 +67,14 @@ type ServerOption interface { applyServer(*serverConfig) } -var _ = []ServerOption{ - (optionFunc[serverConfig])(nil), - (otelOptionFunc)(nil), -} +var _ ServerOption = (optionFunc[serverConfig])(nil) func (o optionFunc[C]) applyServer(c *C) { o(c) } +var _ ServerOption = (otelOptionFunc)(nil) + func (o otelOptionFunc) applyServer(c *serverConfig) { o(&c.otelConfig) } @@ -82,8 +83,15 @@ func newServerConfig(opts ...ServerOption) serverConfig { cfg := serverConfig{ NotFound: http.NotFound, MethodNotAllowed: func(w http.ResponseWriter, r *http.Request, allowed string) { - w.Header().Set("Allow", allowed) - w.WriteHeader(http.StatusMethodNotAllowed) + status := http.StatusMethodNotAllowed + if r.Method == "OPTIONS" { + w.Header().Set("Access-Control-Allow-Methods", allowed) + w.Header().Set("Access-Control-Allow-Headers", "Content-Type") + status = http.StatusNoContent + } else { + w.Header().Set("Allow", allowed) + } + w.WriteHeader(status) }, ErrorHandler: ogenerrors.DefaultErrorHandler, Middleware: nil, @@ -113,13 +121,13 @@ func (s baseServer) notAllowed(w http.ResponseWriter, r *http.Request, allowed s func (cfg serverConfig) baseServer() (s baseServer, err error) { s = baseServer{cfg: cfg} - if s.requests, err = s.cfg.Meter.Int64Counter(otelogen.ServerRequestCount); err != nil { + if s.requests, err = otelogen.ServerRequestCountCounter(s.cfg.Meter); err != nil { return s, err } - if s.errors, err = s.cfg.Meter.Int64Counter(otelogen.ServerErrorsCount); err != nil { + if s.errors, err = otelogen.ServerErrorsCountCounter(s.cfg.Meter); err != nil { return s, err } - if s.duration, err = s.cfg.Meter.Float64Histogram(otelogen.ServerDuration); err != nil { + if s.duration, err = otelogen.ServerDurationHistogram(s.cfg.Meter); err != nil { return s, err } return s, nil @@ -135,15 +143,14 @@ type ClientOption interface { applyClient(*clientConfig) } -var _ = []ClientOption{ - (optionFunc[clientConfig])(nil), - (otelOptionFunc)(nil), -} +var _ ClientOption = (optionFunc[clientConfig])(nil) func (o optionFunc[C]) applyClient(c *C) { o(c) } +var _ ClientOption = (otelOptionFunc)(nil) + func (o otelOptionFunc) applyClient(c *clientConfig) { o(&c.otelConfig) } @@ -168,13 +175,13 @@ type baseClient struct { func (cfg clientConfig) baseClient() (c baseClient, err error) { c = baseClient{cfg: cfg} - if c.requests, err = c.cfg.Meter.Int64Counter(otelogen.ClientRequestCount); err != nil { + if c.requests, err = otelogen.ClientRequestCountCounter(c.cfg.Meter); err != nil { return c, err } - if c.errors, err = c.cfg.Meter.Int64Counter(otelogen.ClientErrorsCount); err != nil { + if c.errors, err = otelogen.ClientErrorsCountCounter(c.cfg.Meter); err != nil { return c, err } - if c.duration, err = c.cfg.Meter.Float64Histogram(otelogen.ClientDuration); err != nil { + if c.duration, err = otelogen.ClientDurationHistogram(c.cfg.Meter); err != nil { return c, err } return c, nil diff --git a/integration/proxypb/oas/oas_client_gen.go b/integration/proxypb/oas/oas_client_gen.go index c688b4e..83ed8bb 100644 --- a/integration/proxypb/oas/oas_client_gen.go +++ b/integration/proxypb/oas/oas_client_gen.go @@ -12,7 +12,7 @@ import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/metric" - semconv "go.opentelemetry.io/otel/semconv/v1.19.0" + semconv "go.opentelemetry.io/otel/semconv/v1.26.0" "go.opentelemetry.io/otel/trace" "github.com/ogen-go/ogen/conv" @@ -96,7 +96,7 @@ func (c *Client) Echo(ctx context.Context, request OptString) (*StringMessage, e func (c *Client) sendEcho(ctx context.Context, request OptString) (res *StringMessage, err error) { otelAttrs := []attribute.KeyValue{ otelogen.OperationID("echo"), - semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/echo"), } @@ -169,7 +169,7 @@ func (c *Client) PathParam(ctx context.Context, params PathParamParams) (*String func (c *Client) sendPathParam(ctx context.Context, params PathParamParams) (res *StringMessage, err error) { otelAttrs := []attribute.KeyValue{ otelogen.OperationID("pathParam"), - semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/pathParam/{value}"), } @@ -257,18 +257,9 @@ func (c *Client) TestModelEndpoint(ctx context.Context, request *TestModel) (*Te func (c *Client) sendTestModelEndpoint(ctx context.Context, request *TestModel) (res *TestModel, err error) { otelAttrs := []attribute.KeyValue{ otelogen.OperationID("testModelEndpoint"), - semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/testModel"), } - // Validate request before sending. - if err := func() error { - if err := request.Validate(); err != nil { - return err - } - return nil - }(); err != nil { - return res, errors.Wrap(err, "validate") - } // Run stopwatch. startTime := time.Now() diff --git a/integration/proxypb/oas/oas_handlers_gen.go b/integration/proxypb/oas/oas_handlers_gen.go index 7555a42..3dd1607 100644 --- a/integration/proxypb/oas/oas_handlers_gen.go +++ b/integration/proxypb/oas/oas_handlers_gen.go @@ -11,7 +11,7 @@ import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/metric" - semconv "go.opentelemetry.io/otel/semconv/v1.19.0" + semconv "go.opentelemetry.io/otel/semconv/v1.26.0" "go.opentelemetry.io/otel/trace" ht "github.com/ogen-go/ogen/http" @@ -26,7 +26,7 @@ import ( func (s *Server) handleEchoRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { otelAttrs := []attribute.KeyValue{ otelogen.OperationID("echo"), - semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/echo"), } @@ -37,22 +37,28 @@ func (s *Server) handleEchoRequest(args [0]string, argsEscaped bool, w http.Resp ) defer span.End() + // Add Labeler to context. + labeler := &Labeler{attrs: otelAttrs} + ctx = contextWithLabeler(ctx, labeler) + // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) + attrOpt := metric.WithAttributeSet(labeler.AttributeSet()) + + // Increment request counter. + s.requests.Add(ctx, 1, attrOpt) + // Use floating point division here for higher precision (instead of Millisecond method). - s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), attrOpt) }() - // Increment request counter. - s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) - var ( recordError = func(stage string, err error) { span.RecordError(err) span.SetStatus(codes.Error, stage) - s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + s.errors.Add(ctx, 1, metric.WithAttributeSet(labeler.AttributeSet())) } err error opErrContext = ogenerrors.OperationContext{ @@ -66,7 +72,7 @@ func (s *Server) handleEchoRequest(args [0]string, argsEscaped bool, w http.Resp OperationContext: opErrContext, Err: err, } - recordError("DecodeRequest", err) + defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } @@ -110,13 +116,13 @@ func (s *Server) handleEchoRequest(args [0]string, argsEscaped bool, w http.Resp response, err = s.h.Echo(ctx, request) } if err != nil { - recordError("Internal", err) + defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeEchoResponse(response, w, span); err != nil { - recordError("EncodeResponse", err) + defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } @@ -130,7 +136,7 @@ func (s *Server) handleEchoRequest(args [0]string, argsEscaped bool, w http.Resp func (s *Server) handlePathParamRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { otelAttrs := []attribute.KeyValue{ otelogen.OperationID("pathParam"), - semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/pathParam/{value}"), } @@ -141,22 +147,28 @@ func (s *Server) handlePathParamRequest(args [1]string, argsEscaped bool, w http ) defer span.End() + // Add Labeler to context. + labeler := &Labeler{attrs: otelAttrs} + ctx = contextWithLabeler(ctx, labeler) + // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) + attrOpt := metric.WithAttributeSet(labeler.AttributeSet()) + + // Increment request counter. + s.requests.Add(ctx, 1, attrOpt) + // Use floating point division here for higher precision (instead of Millisecond method). - s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), attrOpt) }() - // Increment request counter. - s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) - var ( recordError = func(stage string, err error) { span.RecordError(err) span.SetStatus(codes.Error, stage) - s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + s.errors.Add(ctx, 1, metric.WithAttributeSet(labeler.AttributeSet())) } err error opErrContext = ogenerrors.OperationContext{ @@ -170,7 +182,7 @@ func (s *Server) handlePathParamRequest(args [1]string, argsEscaped bool, w http OperationContext: opErrContext, Err: err, } - recordError("DecodeParams", err) + defer recordError("DecodeParams", err) s.cfg.ErrorHandler(ctx, w, r, err) return } @@ -214,13 +226,13 @@ func (s *Server) handlePathParamRequest(args [1]string, argsEscaped bool, w http response, err = s.h.PathParam(ctx, params) } if err != nil { - recordError("Internal", err) + defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodePathParamResponse(response, w, span); err != nil { - recordError("EncodeResponse", err) + defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } @@ -234,7 +246,7 @@ func (s *Server) handlePathParamRequest(args [1]string, argsEscaped bool, w http func (s *Server) handleTestModelEndpointRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { otelAttrs := []attribute.KeyValue{ otelogen.OperationID("testModelEndpoint"), - semconv.HTTPMethodKey.String("POST"), + semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/testModel"), } @@ -245,22 +257,28 @@ func (s *Server) handleTestModelEndpointRequest(args [0]string, argsEscaped bool ) defer span.End() + // Add Labeler to context. + labeler := &Labeler{attrs: otelAttrs} + ctx = contextWithLabeler(ctx, labeler) + // Run stopwatch. startTime := time.Now() defer func() { elapsedDuration := time.Since(startTime) + attrOpt := metric.WithAttributeSet(labeler.AttributeSet()) + + // Increment request counter. + s.requests.Add(ctx, 1, attrOpt) + // Use floating point division here for higher precision (instead of Millisecond method). - s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...)) + s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), attrOpt) }() - // Increment request counter. - s.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) - var ( recordError = func(stage string, err error) { span.RecordError(err) span.SetStatus(codes.Error, stage) - s.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + s.errors.Add(ctx, 1, metric.WithAttributeSet(labeler.AttributeSet())) } err error opErrContext = ogenerrors.OperationContext{ @@ -274,7 +292,7 @@ func (s *Server) handleTestModelEndpointRequest(args [0]string, argsEscaped bool OperationContext: opErrContext, Err: err, } - recordError("DecodeRequest", err) + defer recordError("DecodeRequest", err) s.cfg.ErrorHandler(ctx, w, r, err) return } @@ -318,13 +336,13 @@ func (s *Server) handleTestModelEndpointRequest(args [0]string, argsEscaped bool response, err = s.h.TestModelEndpoint(ctx, request) } if err != nil { - recordError("Internal", err) + defer recordError("Internal", err) s.cfg.ErrorHandler(ctx, w, r, err) return } if err := encodeTestModelEndpointResponse(response, w, span); err != nil { - recordError("EncodeResponse", err) + defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) } diff --git a/integration/proxypb/oas/oas_json_gen.go b/integration/proxypb/oas/oas_json_gen.go index 2b10e29..036db3d 100644 --- a/integration/proxypb/oas/oas_json_gen.go +++ b/integration/proxypb/oas/oas_json_gen.go @@ -363,6 +363,39 @@ func (s *OptTestEnum) UnmarshalJSON(data []byte) error { return s.Decode(d) } +// Encode encodes TestModel as json. +func (o OptTestModel) Encode(e *jx.Encoder) { + if !o.Set { + return + } + o.Value.Encode(e) +} + +// Decode decodes TestModel from json. +func (o *OptTestModel) Decode(d *jx.Decoder) error { + if o == nil { + return errors.New("invalid: unable to decode OptTestModel to nil") + } + o.Set = true + if err := o.Value.Decode(d); err != nil { + return err + } + return nil +} + +// MarshalJSON implements stdjson.Marshaler. +func (s OptTestModel) MarshalJSON() ([]byte, error) { + e := jx.Encoder{} + s.Encode(&e) + return e.Bytes(), nil +} + +// UnmarshalJSON implements stdjson.Unmarshaler. +func (s *OptTestModel) UnmarshalJSON(data []byte) error { + d := jx.DecodeBytes(data) + return s.Decode(d) +} + // Encode encodes TestModelCategory as json. func (o OptTestModelCategory) Encode(e *jx.Encoder) { if !o.Set { diff --git a/integration/proxypb/oas/oas_labeler_gen.go b/integration/proxypb/oas/oas_labeler_gen.go new file mode 100644 index 0000000..72f35b1 --- /dev/null +++ b/integration/proxypb/oas/oas_labeler_gen.go @@ -0,0 +1,42 @@ +// Code generated by ogen, DO NOT EDIT. + +package oas + +import ( + "context" + + "go.opentelemetry.io/otel/attribute" +) + +// Labeler is used to allow adding custom attributes to the server request metrics. +type Labeler struct { + attrs []attribute.KeyValue +} + +// Add attributes to the Labeler. +func (l *Labeler) Add(attrs ...attribute.KeyValue) { + l.attrs = append(l.attrs, attrs...) +} + +// AttributeSet returns the attributes added to the Labeler as an attribute.Set. +func (l *Labeler) AttributeSet() attribute.Set { + return attribute.NewSet(l.attrs...) +} + +type labelerContextKey struct{} + +// LabelerFromContext retrieves the Labeler from the provided context, if present. +// +// If no Labeler was found in the provided context a new, empty Labeler is returned and the second +// return value is false. In this case it is safe to use the Labeler but any attributes added to +// it will not be used. +func LabelerFromContext(ctx context.Context) (*Labeler, bool) { + if l, ok := ctx.Value(labelerContextKey{}).(*Labeler); ok { + return l, true + } + return &Labeler{}, false +} + +func contextWithLabeler(ctx context.Context, l *Labeler) context.Context { + return context.WithValue(ctx, labelerContextKey{}, l) +} diff --git a/integration/proxypb/oas/oas_response_decoders_gen.go b/integration/proxypb/oas/oas_response_decoders_gen.go index 7a925aa..dfe9cdf 100644 --- a/integration/proxypb/oas/oas_response_decoders_gen.go +++ b/integration/proxypb/oas/oas_response_decoders_gen.go @@ -129,6 +129,15 @@ func decodeTestModelEndpointResponse(resp *http.Response) (res *TestModel, _ err } return res, err } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } return &response, nil default: return res, validate.InvalidContentType(ct) diff --git a/integration/proxypb/oas/oas_response_encoders_gen.go b/integration/proxypb/oas/oas_response_encoders_gen.go index 0473c83..6e6d0c9 100644 --- a/integration/proxypb/oas/oas_response_encoders_gen.go +++ b/integration/proxypb/oas/oas_response_encoders_gen.go @@ -12,7 +12,7 @@ import ( ) func encodeEchoResponse(response *StringMessage, w http.ResponseWriter, span trace.Span) error { - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(200) span.SetStatus(codes.Ok, http.StatusText(200)) @@ -26,7 +26,7 @@ func encodeEchoResponse(response *StringMessage, w http.ResponseWriter, span tra } func encodePathParamResponse(response *StringMessage, w http.ResponseWriter, span trace.Span) error { - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(200) span.SetStatus(codes.Ok, http.StatusText(200)) @@ -40,7 +40,7 @@ func encodePathParamResponse(response *StringMessage, w http.ResponseWriter, spa } func encodeTestModelEndpointResponse(response *TestModel, w http.ResponseWriter, span trace.Span) error { - w.Header().Set("Content-Type", "application/json") + w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(200) span.SetStatus(codes.Ok, http.StatusText(200)) diff --git a/integration/proxypb/oas/oas_router_gen.go b/integration/proxypb/oas/oas_router_gen.go index 3fc800f..27619ee 100644 --- a/integration/proxypb/oas/oas_router_gen.go +++ b/integration/proxypb/oas/oas_router_gen.go @@ -50,6 +50,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { } switch elem[0] { case '/': // Prefix: "/" + origElem := elem if l := len("/"); len(elem) >= l && elem[0:l] == "/" { elem = elem[l:] } else { @@ -61,6 +62,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { } switch elem[0] { case 'e': // Prefix: "echo" + origElem := elem if l := len("echo"); len(elem) >= l && elem[0:l] == "echo" { elem = elem[l:] } else { @@ -78,7 +80,10 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } + + elem = origElem case 'p': // Prefix: "pathParam/" + origElem := elem if l := len("pathParam/"); len(elem) >= l && elem[0:l] == "pathParam/" { elem = elem[l:] } else { @@ -103,7 +108,10 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } + + elem = origElem case 't': // Prefix: "testModel" + origElem := elem if l := len("testModel"); len(elem) >= l && elem[0:l] == "testModel" { elem = elem[l:] } else { @@ -121,7 +129,11 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } + + elem = origElem } + + elem = origElem } } s.notFound(w, r) @@ -203,6 +215,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { } switch elem[0] { case '/': // Prefix: "/" + origElem := elem if l := len("/"); len(elem) >= l && elem[0:l] == "/" { elem = elem[l:] } else { @@ -214,6 +227,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { } switch elem[0] { case 'e': // Prefix: "echo" + origElem := elem if l := len("echo"); len(elem) >= l && elem[0:l] == "echo" { elem = elem[l:] } else { @@ -221,9 +235,9 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { } if len(elem) == 0 { + // Leaf node. switch method { case "POST": - // Leaf: Echo r.name = "Echo" r.summary = "" r.operationID = "echo" @@ -235,7 +249,10 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { return } } + + elem = origElem case 'p': // Prefix: "pathParam/" + origElem := elem if l := len("pathParam/"); len(elem) >= l && elem[0:l] == "pathParam/" { elem = elem[l:] } else { @@ -248,9 +265,9 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { elem = "" if len(elem) == 0 { + // Leaf node. switch method { case "POST": - // Leaf: PathParam r.name = "PathParam" r.summary = "" r.operationID = "pathParam" @@ -262,7 +279,10 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { return } } + + elem = origElem case 't': // Prefix: "testModel" + origElem := elem if l := len("testModel"); len(elem) >= l && elem[0:l] == "testModel" { elem = elem[l:] } else { @@ -270,9 +290,9 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { } if len(elem) == 0 { + // Leaf node. switch method { case "POST": - // Leaf: TestModelEndpoint r.name = "TestModelEndpoint" r.summary = "" r.operationID = "testModelEndpoint" @@ -284,7 +304,11 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { return } } + + elem = origElem } + + elem = origElem } } return r, false diff --git a/integration/proxypb/oas/oas_validators_gen.go b/integration/proxypb/oas/oas_validators_gen.go index a03cdda..cb35fa5 100644 --- a/integration/proxypb/oas/oas_validators_gen.go +++ b/integration/proxypb/oas/oas_validators_gen.go @@ -24,6 +24,10 @@ func (s TestEnum) Validate() error { } func (s *TestModel) Validate() error { + if s == nil { + return validate.ErrNilPointer + } + var failures []validate.FieldError if err := func() error { if value, ok := s.OptionalFloat.Get(); ok { diff --git a/integration/proxypb/openapi.yaml b/integration/proxypb/openapi.yaml index db73c3f..e9db0c0 100644 --- a/integration/proxypb/openapi.yaml +++ b/integration/proxypb/openapi.yaml @@ -59,6 +59,23 @@ components: type: boolean childStr1: type: string + ChildModel3: + type: object + properties: + subKey: + type: string + bool1: + type: boolean + i32: + type: integer + format: int32 + optStr: + type: string + optBool: + type: boolean + optI32: + type: integer + format: int32 StringMessage: type: object properties: diff --git a/integration/proxypb/proxy.pb.go b/integration/proxypb/proxy.pb.go index 57be32d..a32fb78 100644 --- a/integration/proxypb/proxy.pb.go +++ b/integration/proxypb/proxy.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.31.0 -// protoc v4.25.0 +// protoc-gen-go v1.35.1 +// protoc v4.25.2 // source: proxy.proto package proxypb @@ -140,11 +140,9 @@ type ChildModel1 struct { func (x *ChildModel1) Reset() { *x = ChildModel1{} - if protoimpl.UnsafeEnabled { - mi := &file_proxy_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proxy_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ChildModel1) String() string { @@ -155,7 +153,7 @@ func (*ChildModel1) ProtoMessage() {} func (x *ChildModel1) ProtoReflect() protoreflect.Message { mi := &file_proxy_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -199,11 +197,9 @@ type ChildModel3 struct { func (x *ChildModel3) Reset() { *x = ChildModel3{} - if protoimpl.UnsafeEnabled { - mi := &file_proxy_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proxy_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ChildModel3) String() string { @@ -214,7 +210,7 @@ func (*ChildModel3) ProtoMessage() {} func (x *ChildModel3) ProtoReflect() protoreflect.Message { mi := &file_proxy_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -335,11 +331,9 @@ type TestModel struct { func (x *TestModel) Reset() { *x = TestModel{} - if protoimpl.UnsafeEnabled { - mi := &file_proxy_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proxy_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *TestModel) String() string { @@ -350,7 +344,7 @@ func (*TestModel) ProtoMessage() {} func (x *TestModel) ProtoReflect() protoreflect.Message { mi := &file_proxy_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -743,11 +737,9 @@ type StringMessage struct { func (x *StringMessage) Reset() { *x = StringMessage{} - if protoimpl.UnsafeEnabled { - mi := &file_proxy_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proxy_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *StringMessage) String() string { @@ -758,7 +750,7 @@ func (*StringMessage) ProtoMessage() {} func (x *StringMessage) ProtoReflect() protoreflect.Message { mi := &file_proxy_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -791,11 +783,9 @@ type TestModel_NestedChild struct { func (x *TestModel_NestedChild) Reset() { *x = TestModel_NestedChild{} - if protoimpl.UnsafeEnabled { - mi := &file_proxy_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_proxy_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *TestModel_NestedChild) String() string { @@ -806,7 +796,7 @@ func (*TestModel_NestedChild) ProtoMessage() {} func (x *TestModel_NestedChild) ProtoReflect() protoreflect.Message { mi := &file_proxy_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -1074,7 +1064,7 @@ func file_proxy_proto_rawDescGZIP() []byte { var file_proxy_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_proxy_proto_msgTypes = make([]protoimpl.MessageInfo, 8) -var file_proxy_proto_goTypes = []interface{}{ +var file_proxy_proto_goTypes = []any{ (TestEnum)(0), // 0: proxypb.TestEnum (TestModel_Category)(0), // 1: proxypb.TestModel.Category (*ChildModel1)(nil), // 2: proxypb.ChildModel1 @@ -1116,78 +1106,16 @@ func file_proxy_proto_init() { if File_proxy_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_proxy_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ChildModel1); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proxy_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ChildModel3); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proxy_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestModel); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proxy_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StringMessage); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proxy_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TestModel_NestedChild); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_proxy_proto_msgTypes[0].OneofWrappers = []interface{}{} - file_proxy_proto_msgTypes[1].OneofWrappers = []interface{}{} - file_proxy_proto_msgTypes[2].OneofWrappers = []interface{}{ + file_proxy_proto_msgTypes[0].OneofWrappers = []any{} + file_proxy_proto_msgTypes[1].OneofWrappers = []any{} + file_proxy_proto_msgTypes[2].OneofWrappers = []any{ (*TestModel_OneofMember1)(nil), (*TestModel_OneofMember2)(nil), (*TestModel_String_)(nil), (*TestModel_Int64)(nil), (*TestModel_Double)(nil), } - file_proxy_proto_msgTypes[4].OneofWrappers = []interface{}{} + file_proxy_proto_msgTypes[4].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/integration/proxypb/proxy_grpc.pb.go b/integration/proxypb/proxy_grpc.pb.go index 4185f3b..272c87e 100644 --- a/integration/proxypb/proxy_grpc.pb.go +++ b/integration/proxypb/proxy_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.0 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v4.25.2 // source: proxy.proto package proxypb @@ -15,8 +15,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( APIService_Echo_FullMethodName = "/proxypb.APIService/Echo" @@ -42,8 +42,9 @@ func NewAPIServiceClient(cc grpc.ClientConnInterface) APIServiceClient { } func (c *aPIServiceClient) Echo(ctx context.Context, in *StringMessage, opts ...grpc.CallOption) (*StringMessage, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(StringMessage) - err := c.cc.Invoke(ctx, APIService_Echo_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, APIService_Echo_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -51,8 +52,9 @@ func (c *aPIServiceClient) Echo(ctx context.Context, in *StringMessage, opts ... } func (c *aPIServiceClient) TestModelEndpoint(ctx context.Context, in *TestModel, opts ...grpc.CallOption) (*TestModel, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(TestModel) - err := c.cc.Invoke(ctx, APIService_TestModelEndpoint_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, APIService_TestModelEndpoint_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -60,8 +62,9 @@ func (c *aPIServiceClient) TestModelEndpoint(ctx context.Context, in *TestModel, } func (c *aPIServiceClient) PathParam(ctx context.Context, in *StringMessage, opts ...grpc.CallOption) (*StringMessage, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(StringMessage) - err := c.cc.Invoke(ctx, APIService_PathParam_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, APIService_PathParam_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -70,7 +73,7 @@ func (c *aPIServiceClient) PathParam(ctx context.Context, in *StringMessage, opt // APIServiceServer is the server API for APIService service. // All implementations must embed UnimplementedAPIServiceServer -// for forward compatibility +// for forward compatibility. type APIServiceServer interface { Echo(context.Context, *StringMessage) (*StringMessage, error) TestModelEndpoint(context.Context, *TestModel) (*TestModel, error) @@ -78,9 +81,12 @@ type APIServiceServer interface { mustEmbedUnimplementedAPIServiceServer() } -// UnimplementedAPIServiceServer must be embedded to have forward compatible implementations. -type UnimplementedAPIServiceServer struct { -} +// UnimplementedAPIServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedAPIServiceServer struct{} func (UnimplementedAPIServiceServer) Echo(context.Context, *StringMessage) (*StringMessage, error) { return nil, status.Errorf(codes.Unimplemented, "method Echo not implemented") @@ -92,6 +98,7 @@ func (UnimplementedAPIServiceServer) PathParam(context.Context, *StringMessage) return nil, status.Errorf(codes.Unimplemented, "method PathParam not implemented") } func (UnimplementedAPIServiceServer) mustEmbedUnimplementedAPIServiceServer() {} +func (UnimplementedAPIServiceServer) testEmbeddedByValue() {} // UnsafeAPIServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to APIServiceServer will @@ -101,6 +108,13 @@ type UnsafeAPIServiceServer interface { } func RegisterAPIServiceServer(s grpc.ServiceRegistrar, srv APIServiceServer) { + // If the following call pancis, it indicates UnimplementedAPIServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&APIService_ServiceDesc, srv) }