M PLAN.md => PLAN.md +11 -1
@@ 212,8 212,18 @@ fiber and bridges client ↔ handler via `fiber.channel`. All four flavors
### M7 — Developer ergonomics
-- [ ] Generated EmmyLua / lua-language-server type annotations so
+- [x] Generated EmmyLua / lua-language-server type annotations so
`t:Person_encode({name=...})` autocompletes in editors.
+ Codegen emits `---@class <full.Name>` per message (with one
+ `---@field` per field), `---@alias <full.Name> integer` per
+ enum, and `---@param` / `---@return` on every `_new`, `_encode`,
+ `_decode`, `_decode_lazy`, `_has_*`, `_clear_*` wrapper. Class
+ identifiers use proto full names verbatim so cross-file
+ references resolve. Lazy view types (`pb.MessageView`,
+ `pb.ArrayView`, `pb.MapView`) are declared inline in
+ `runtime/pb/lazy.lua` so the LSP sees them. Pure comment
+ addition — no runtime impact, 300/300 luatest + 19/19
+ jit-trace gate stay green.
- [ ] `pb.from_pb(file_descriptor_set)` — runtime descriptor parser, lets
apps load schemas at runtime without protoc-time codegen.
- [ ] JSON encoding per the [proto3 JSON spec][proto3json] (canonical and
A cmd/protoc-gen-tarantool/internal/gen/emmylua.go => cmd/protoc-gen-tarantool/internal/gen/emmylua.go +209 -0
@@ 0,0 1,209 @@
+// EmmyLua / lua-language-server annotation emission.
+//
+// Annotations are pure comments — they have no runtime effect — but
+// they teach the Lua language server about generated message shapes,
+// enum aliases, and wrapper function signatures. Users of generated
+// code get autocomplete, type-checking, and rename refactoring for
+// free in any editor that consumes EmmyLua (VS Code + sumneko, Neovim
+// LSP, JetBrains EmmyLua plugin).
+//
+// Output (per file):
+// 1. ---@alias <pkg.Enum> integer (one per enum)
+// 2. ---@class <pkg.Message> (one per message)
+// ---@field <name> <type>
+// ...
+// 3. ---@param / ---@return on each emitted M.<Name>_* function.
+//
+// All three blocks are emitted by gen.go at well-defined points so
+// they live alongside the code they describe.
+//
+// Type mapping (proto -> EmmyLua):
+// - bool -> boolean
+// - string / bytes -> string
+// - float / double -> number
+// - all int kinds -> integer (64-bit are uint64_t/int64_t cdata
+// at runtime; LSP has no cdata model,
+// so they're typed as integer with
+// an inline note)
+// - enum<Name> -> <Name> (alias declared elsewhere)
+// - message<Name> -> <Name> (class declared elsewhere)
+// - repeated<T> -> T[]
+// - map<K,V> -> table<K, V>
+//
+// Field presence:
+// - proto3 explicit `optional` -> trailing `?` on the field name
+// - oneof branch -> trailing `?` (only one is set at a time)
+// - everything else -> no marker (proto3 defaults imply
+// a typed zero value if absent)
+
+package gen
+
+import (
+ "fmt"
+ "strings"
+
+ "google.golang.org/protobuf/compiler/protogen"
+ "google.golang.org/protobuf/reflect/protoreflect"
+)
+
+// emmyTypeName returns the qualified EmmyLua class/alias identifier for a
+// message or enum. We use the proto full name verbatim (with dots), which
+// lua-language-server accepts as a class identifier. This keeps cross-file
+// references straightforward — every file referring to "hello.Person"
+// resolves to the same `---@class hello.Person` block, regardless of which
+// generated `.lua` declared it.
+func emmyTypeName(td protoreflect.Descriptor) string {
+ return string(td.FullName())
+}
+
+// emmyScalarType maps a proto3 scalar kind to its EmmyLua surface type.
+func emmyScalarType(k protoreflect.Kind) string {
+ switch k {
+ case protoreflect.BoolKind:
+ return "boolean"
+ case protoreflect.StringKind, protoreflect.BytesKind:
+ return "string"
+ case protoreflect.FloatKind, protoreflect.DoubleKind:
+ return "number"
+ default:
+ // All int kinds. 64-bit are int64_t/uint64_t cdata at runtime,
+ // but EmmyLua has no model for that; users either compare via
+ // pb.to_int64/pb.to_uint64 or convert with tonumber for small
+ // values. Typing as integer matches user mental model.
+ return "integer"
+ }
+}
+
+// emmyFieldType returns the surface type for one field, accounting for
+// kind (scalar/enum/message/map) and the repeated modifier.
+func emmyFieldType(f *protogen.Field) string {
+ if f.Desc.IsMap() {
+ kf := f.Message.Fields[0]
+ vf := f.Message.Fields[1]
+ return fmt.Sprintf("table<%s, %s>",
+ emmyFieldTypeSingular(kf), emmyFieldTypeSingular(vf))
+ }
+ t := emmyFieldTypeSingular(f)
+ if f.Desc.IsList() {
+ return t + "[]"
+ }
+ return t
+}
+
+func emmyFieldTypeSingular(f *protogen.Field) string {
+ switch {
+ case f.Message != nil:
+ return emmyTypeName(f.Message.Desc)
+ case f.Enum != nil:
+ return emmyTypeName(f.Enum.Desc)
+ default:
+ return emmyScalarType(f.Desc.Kind())
+ }
+}
+
+// emmyFieldOptional reports whether the field should carry a trailing `?`.
+// Two cases: proto3 explicit optional, and oneof branches (only one is
+// set at a time, so every branch is presence-tracked).
+func emmyFieldOptional(f *protogen.Field) bool {
+ if f.Desc.HasOptionalKeyword() {
+ return true
+ }
+ if f.Oneof != nil && !f.Desc.HasOptionalKeyword() {
+ return true
+ }
+ return false
+}
+
+// emitEmmyEnumAlias emits `---@alias <pkg.Enum> integer` for each enum.
+// Could be tightened to `<value> | <value> | ...` but that locks the
+// schema in the annotation; users typically write `M.Status.OK` (an
+// integer literal) so `integer` is the honest type.
+func emitEmmyEnumAlias(w *writer, e *protogen.Enum) {
+ w.line("---@alias %s integer", emmyTypeName(e.Desc))
+}
+
+// emitEmmyMessageClass emits the `---@class` block for one message,
+// listing every field with its surface type and optional marker.
+func emitEmmyMessageClass(w *writer, m *protogen.Message) {
+ w.line("---@class %s", emmyTypeName(m.Desc))
+ for _, f := range m.Fields {
+ name := string(f.Desc.Name())
+ if emmyFieldOptional(f) {
+ name = name + "?"
+ }
+ w.line("---@field %s %s", name, emmyFieldType(f))
+ }
+}
+
+// emitEmmyWrappersHeader prefaces the M.<Name>_new / _encode / _decode /
+// _decode_lazy / has_/clear_ stubs with their EmmyLua annotations. Each
+// wrapper gets its own `---@param` / `---@return` lines printed
+// immediately before the corresponding `function M.<Name>_*(...)` line.
+//
+// emitMessageWrappers (runtime mode) and emitInlineMessage (full mode)
+// each call into this for the typed prelude; the function bodies stay
+// where they were.
+func emitEmmyWrapperAnnotations(w *writer, name string, fullName string, kind emmyWrapperKind) {
+ t := fullName
+ switch kind {
+ case wrapperNew:
+ w.line("---@param t? %s", t)
+ w.line("---@return %s", t)
+ case wrapperEncode:
+ w.line("---@param t %s", t)
+ w.line("---@return string")
+ case wrapperDecode:
+ w.line("---@param b string")
+ w.line("---@return %s", t)
+ case wrapperDecodeLazy:
+ w.line("---@param b string")
+ w.line("---@return pb.MessageView")
+ case wrapperHas:
+ w.line("---@param t %s", t)
+ w.line("---@return boolean")
+ case wrapperClear:
+ w.line("---@param t %s", t)
+ }
+}
+
+type emmyWrapperKind int
+
+const (
+ wrapperNew emmyWrapperKind = iota
+ wrapperEncode
+ wrapperDecode
+ wrapperDecodeLazy
+ wrapperHas
+ wrapperClear
+)
+
+// emitEmmyTypesBlock emits the file's whole types section: every enum
+// alias, every message class. Called once per file by GenerateFile,
+// after the descriptor pre-declarations and before the wrappers.
+func emitEmmyTypesBlock(w *writer, enums []*protogen.Enum, msgs []*protogen.Message) {
+ if len(enums) == 0 && len(msgs) == 0 {
+ return
+ }
+ w.line("-- EmmyLua / lua-language-server type annotations.")
+ w.line("-- These are comments — no runtime effect. They give editors")
+ w.line("-- autocomplete and type-checking for the generated wrappers.")
+ for _, e := range enums {
+ emitEmmyEnumAlias(w, e)
+ }
+ if len(enums) > 0 {
+ w.line("")
+ }
+ for i, m := range msgs {
+ emitEmmyMessageClass(w, m)
+ if i < len(msgs)-1 {
+ w.line("")
+ }
+ }
+ w.line("")
+}
+
+// emmyMessageFullName is a convenience wrapper used by the wrapper
+// emitters to resolve the right `---@class` identifier for a message.
+func emmyMessageFullName(m *protogen.Message) string {
+ return strings.TrimSpace(string(m.Desc.FullName()))
+}
M cmd/protoc-gen-tarantool/internal/gen/gen.go => cmd/protoc-gen-tarantool/internal/gen/gen.go +15 -2
@@ 92,6 92,11 @@ func GenerateFile(plug *protogen.Plugin, file *protogen.File, cfg Config) error
emitMessageFields(w, file, m, imports, cfg.Prefix)
}
+ // 3a) EmmyLua type annotations (---@class per message, ---@alias per
+ // enum). Emitted between the descriptors and the wrappers so the
+ // wrapper annotations a few lines down can reference these class names.
+ emitEmmyTypesBlock(w, allEnums, allMsgs)
+
// 4) Wrappers: _new / _encode / _decode.
for _, m := range allMsgs {
switch cfg.Mode {
@@ 375,23 380,31 @@ func typeRef(file *protogen.File, td protoreflect.Descriptor, selfPath string, i
// has_<field> / clear_<field> for each explicit-optional field.
func emitMessageWrappers(w *writer, file *protogen.File, m *protogen.Message) {
name := luaTypeName(m.Desc.FullName(), file.Desc.Package())
+ full := emmyMessageFullName(m)
+
+ emitEmmyWrapperAnnotations(w, name, full, wrapperNew)
w.line("function M.%s_new(t) return t or {} end", name)
+ emitEmmyWrapperAnnotations(w, name, full, wrapperEncode)
w.line("function M.%s_encode(t) return pb.encode(M.%s_descriptor, t) end", name, name)
+ emitEmmyWrapperAnnotations(w, name, full, wrapperDecode)
w.line("function M.%s_decode(b) return pb.decode(M.%s_descriptor, b) end", name, name)
+ emitEmmyWrapperAnnotations(w, name, full, wrapperDecodeLazy)
w.line("function M.%s_decode_lazy(b) return pb.decode_lazy(M.%s_descriptor, b) end", name, name)
- emitOptionalAccessors(w, name, m)
+ emitOptionalAccessors(w, name, m, full)
w.line("")
}
// emitOptionalAccessors writes M.<Name>_has_<field>(t) and _clear_<field>(t)
// for every field marked with proto3 explicit `optional`.
-func emitOptionalAccessors(w *writer, name string, m *protogen.Message) {
+func emitOptionalAccessors(w *writer, name string, m *protogen.Message, fullName string) {
for _, f := range m.Fields {
if !f.Desc.HasOptionalKeyword() {
continue
}
fname := string(f.Desc.Name())
+ emitEmmyWrapperAnnotations(w, name, fullName, wrapperHas)
w.line("function M.%s_has_%s(t) return t.%s ~= nil end", name, fname, fname)
+ emitEmmyWrapperAnnotations(w, name, fullName, wrapperClear)
w.line("function M.%s_clear_%s(t) t.%s = nil end", name, fname, fname)
}
}
M cmd/protoc-gen-tarantool/internal/gen/inline.go => cmd/protoc-gen-tarantool/internal/gen/inline.go +6 -1
@@ 13,19 13,23 @@ import (
// each scalar field's encode/decode call resolves to one wire.<typed> call.
func emitInlineMessage(w *writer, file *protogen.File, m *protogen.Message, imports map[string]string, prefix string) {
name := luaTypeName(m.Desc.FullName(), file.Desc.Package())
+ full := emmyMessageFullName(m)
selfPath := luaPackagePath(file.Desc, prefix)
+ emitEmmyWrapperAnnotations(w, name, full, wrapperNew)
w.line("function M.%s_new(t) return t or {} end", name)
w.line("")
emitInlineEncode(w, name, m, file, selfPath, imports, prefix)
emitInlineDecode(w, name, m, file, selfPath, imports, prefix)
+ emitEmmyWrapperAnnotations(w, name, full, wrapperDecodeLazy)
w.line("function M.%s_decode_lazy(b) return pb.decode_lazy(M.%s_descriptor, b) end", name, name)
- emitOptionalAccessors(w, name, m)
+ emitOptionalAccessors(w, name, m, full)
w.line("")
}
func emitInlineEncode(w *writer, name string, m *protogen.Message, file *protogen.File, selfPath string, imports map[string]string, prefix string) {
+ emitEmmyWrapperAnnotations(w, name, emmyMessageFullName(m), wrapperEncode)
w.line("function M.%s_encode(t)", name)
w.line(" if type(t) ~= 'table' then")
w.line(" error(\"expected table for %s, got \" .. type(t), 0)", m.Desc.FullName())
@@ 196,6 200,7 @@ func emitInlineEncodeRepeated(w *writer, f *protogen.Field, tag, fname string, f
}
func emitInlineDecode(w *writer, name string, m *protogen.Message, file *protogen.File, selfPath string, imports map[string]string, prefix string) {
+ emitEmmyWrapperAnnotations(w, name, emmyMessageFullName(m), wrapperDecode)
w.line("function M.%s_decode(buf)", name)
w.line(" if type(buf) ~= 'string' then")
w.line(" error(\"expected string for %s decode, got \" .. type(buf), 0)", m.Desc.FullName())
M examples/expected/full/conformance/conformance_pb.lua => examples/expected/full/conformance/conformance_pb.lua +79 -0
@@ 90,8 90,51 @@ M.JspbEncodingConfig_descriptor.fields = {
}
pb.finalize_message(M.JspbEncodingConfig_descriptor)
+-- EmmyLua / lua-language-server type annotations.
+-- These are comments — no runtime effect. They give editors
+-- autocomplete and type-checking for the generated wrappers.
+---@alias conformance.WireFormat integer
+---@alias conformance.TestCategory integer
+
+---@class conformance.TestStatus
+---@field name string
+---@field failure_message string
+---@field matched_name string
+
+---@class conformance.FailureSet
+---@field test conformance.TestStatus[]
+
+---@class conformance.ConformanceRequest
+---@field protobuf_payload? string
+---@field json_payload? string
+---@field jspb_payload? string
+---@field text_payload? string
+---@field requested_output_format conformance.WireFormat
+---@field message_type string
+---@field test_category conformance.TestCategory
+---@field jspb_encoding_options conformance.JspbEncodingConfig
+---@field print_unknown_fields boolean
+
+---@class conformance.ConformanceResponse
+---@field parse_error? string
+---@field serialize_error? string
+---@field timeout_error? string
+---@field runtime_error? string
+---@field protobuf_payload? string
+---@field json_payload? string
+---@field skipped? string
+---@field jspb_payload? string
+---@field text_payload? string
+
+---@class conformance.JspbEncodingConfig
+---@field use_jspb_array_any_format boolean
+
+---@param t? conformance.TestStatus
+---@return conformance.TestStatus
function M.TestStatus_new(t) return t or {} end
+---@param t conformance.TestStatus
+---@return string
function M.TestStatus_encode(t)
if type(t) ~= 'table' then
error("expected table for conformance.TestStatus, got " .. type(t), 0)
@@ 121,6 164,8 @@ function M.TestStatus_encode(t)
return table.concat(out)
end
+---@param b string
+---@return conformance.TestStatus
function M.TestStatus_decode(buf)
if type(buf) ~= 'string' then
error("expected string for conformance.TestStatus decode, got " .. type(buf), 0)
@@ 154,10 199,16 @@ function M.TestStatus_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.TestStatus_decode_lazy(b) return pb.decode_lazy(M.TestStatus_descriptor, b) end
+---@param t? conformance.FailureSet
+---@return conformance.FailureSet
function M.FailureSet_new(t) return t or {} end
+---@param t conformance.FailureSet
+---@return string
function M.FailureSet_encode(t)
if type(t) ~= 'table' then
error("expected table for conformance.FailureSet, got " .. type(t), 0)
@@ 178,6 229,8 @@ function M.FailureSet_encode(t)
return table.concat(out)
end
+---@param b string
+---@return conformance.FailureSet
function M.FailureSet_decode(buf)
if type(buf) ~= 'string' then
error("expected string for conformance.FailureSet decode, got " .. type(buf), 0)
@@ 205,10 258,16 @@ function M.FailureSet_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.FailureSet_decode_lazy(b) return pb.decode_lazy(M.FailureSet_descriptor, b) end
+---@param t? conformance.ConformanceRequest
+---@return conformance.ConformanceRequest
function M.ConformanceRequest_new(t) return t or {} end
+---@param t conformance.ConformanceRequest
+---@return string
function M.ConformanceRequest_encode(t)
if type(t) ~= 'table' then
error("expected table for conformance.ConformanceRequest, got " .. type(t), 0)
@@ 293,6 352,8 @@ function M.ConformanceRequest_encode(t)
return table.concat(out)
end
+---@param b string
+---@return conformance.ConformanceRequest
function M.ConformanceRequest_decode(buf)
if type(buf) ~= 'string' then
error("expected string for conformance.ConformanceRequest decode, got " .. type(buf), 0)
@@ 368,10 429,16 @@ function M.ConformanceRequest_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.ConformanceRequest_decode_lazy(b) return pb.decode_lazy(M.ConformanceRequest_descriptor, b) end
+---@param t? conformance.ConformanceResponse
+---@return conformance.ConformanceResponse
function M.ConformanceResponse_new(t) return t or {} end
+---@param t conformance.ConformanceResponse
+---@return string
function M.ConformanceResponse_encode(t)
if type(t) ~= 'table' then
error("expected table for conformance.ConformanceResponse, got " .. type(t), 0)
@@ 447,6 514,8 @@ function M.ConformanceResponse_encode(t)
return table.concat(out)
end
+---@param b string
+---@return conformance.ConformanceResponse
function M.ConformanceResponse_decode(buf)
if type(buf) ~= 'string' then
error("expected string for conformance.ConformanceResponse decode, got " .. type(buf), 0)
@@ 576,10 645,16 @@ function M.ConformanceResponse_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.ConformanceResponse_decode_lazy(b) return pb.decode_lazy(M.ConformanceResponse_descriptor, b) end
+---@param t? conformance.JspbEncodingConfig
+---@return conformance.JspbEncodingConfig
function M.JspbEncodingConfig_new(t) return t or {} end
+---@param t conformance.JspbEncodingConfig
+---@return string
function M.JspbEncodingConfig_encode(t)
if type(t) ~= 'table' then
error("expected table for conformance.JspbEncodingConfig, got " .. type(t), 0)
@@ 597,6 672,8 @@ function M.JspbEncodingConfig_encode(t)
return table.concat(out)
end
+---@param b string
+---@return conformance.JspbEncodingConfig
function M.JspbEncodingConfig_decode(buf)
if type(buf) ~= 'string' then
error("expected string for conformance.JspbEncodingConfig decode, got " .. type(buf), 0)
@@ 622,6 699,8 @@ function M.JspbEncodingConfig_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.JspbEncodingConfig_decode_lazy(b) return pb.decode_lazy(M.JspbEncodingConfig_descriptor, b) end
return M
M examples/expected/full/hello/hello_pb.lua => examples/expected/full/hello/hello_pb.lua +104 -0
@@ 93,8 93,65 @@ M.Person_descriptor.fields = {
}
pb.finalize_message(M.Person_descriptor)
+-- EmmyLua / lua-language-server type annotations.
+-- These are comments — no runtime effect. They give editors
+-- autocomplete and type-checking for the generated wrappers.
+---@alias hello.Status integer
+
+---@class hello.Result
+---@field id integer
+---@field text? string
+---@field code? integer
+---@field details? hello.Address
+
+---@class hello.HelloRequest
+---@field name string
+
+---@class hello.HelloReply
+---@field greeting string
+
+---@class hello.Event
+---@field title string
+---@field created_at google.protobuf.Timestamp
+---@field duration google.protobuf.Duration
+---@field ack google.protobuf.Empty
+---@field retry_count google.protobuf.Int32Value
+---@field note google.protobuf.StringValue
+---@field is_admin google.protobuf.BoolValue
+---@field payload google.protobuf.Struct
+---@field attribute google.protobuf.Value
+---@field tags google.protobuf.ListValue
+---@field extension google.protobuf.Any
+---@field update_mask google.protobuf.FieldMask
+
+---@class hello.Address
+---@field street string
+---@field city string
+---@field zip integer
+---@field apartment? string
+
+---@class hello.Person
+---@field name string
+---@field age integer
+---@field emails string[]
+---@field status hello.Status
+---@field address hello.Address
+---@field friends hello.Person[]
+---@field lucky_numbers integer[]
+---@field avatar string
+---@field user_id integer
+---@field balance integer
+---@field weight_kg number
+---@field ages_by_nickname table<string, integer>
+---@field nickname_by_age table<integer, string>
+---@field addresses_by_label table<string, hello.Address>
+
+---@param t? hello.Result
+---@return hello.Result
function M.Result_new(t) return t or {} end
+---@param t hello.Result
+---@return string
function M.Result_encode(t)
if type(t) ~= 'table' then
error("expected table for hello.Result, got " .. type(t), 0)
@@ 134,6 191,8 @@ function M.Result_encode(t)
return table.concat(out)
end
+---@param b string
+---@return hello.Result
function M.Result_decode(buf)
if type(buf) ~= 'string' then
error("expected string for hello.Result decode, got " .. type(buf), 0)
@@ 177,10 236,16 @@ function M.Result_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.Result_decode_lazy(b) return pb.decode_lazy(M.Result_descriptor, b) end
+---@param t? hello.HelloRequest
+---@return hello.HelloRequest
function M.HelloRequest_new(t) return t or {} end
+---@param t hello.HelloRequest
+---@return string
function M.HelloRequest_encode(t)
if type(t) ~= 'table' then
error("expected table for hello.HelloRequest, got " .. type(t), 0)
@@ 198,6 263,8 @@ function M.HelloRequest_encode(t)
return table.concat(out)
end
+---@param b string
+---@return hello.HelloRequest
function M.HelloRequest_decode(buf)
if type(buf) ~= 'string' then
error("expected string for hello.HelloRequest decode, got " .. type(buf), 0)
@@ 223,10 290,16 @@ function M.HelloRequest_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.HelloRequest_decode_lazy(b) return pb.decode_lazy(M.HelloRequest_descriptor, b) end
+---@param t? hello.HelloReply
+---@return hello.HelloReply
function M.HelloReply_new(t) return t or {} end
+---@param t hello.HelloReply
+---@return string
function M.HelloReply_encode(t)
if type(t) ~= 'table' then
error("expected table for hello.HelloReply, got " .. type(t), 0)
@@ 244,6 317,8 @@ function M.HelloReply_encode(t)
return table.concat(out)
end
+---@param b string
+---@return hello.HelloReply
function M.HelloReply_decode(buf)
if type(buf) ~= 'string' then
error("expected string for hello.HelloReply decode, got " .. type(buf), 0)
@@ 269,10 344,16 @@ function M.HelloReply_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.HelloReply_decode_lazy(b) return pb.decode_lazy(M.HelloReply_descriptor, b) end
+---@param t? hello.Event
+---@return hello.Event
function M.Event_new(t) return t or {} end
+---@param t hello.Event
+---@return string
function M.Event_encode(t)
if type(t) ~= 'table' then
error("expected table for hello.Event, got " .. type(t), 0)
@@ 356,6 437,8 @@ function M.Event_encode(t)
return table.concat(out)
end
+---@param b string
+---@return hello.Event
function M.Event_decode(buf)
if type(buf) ~= 'string' then
error("expected string for hello.Event decode, got " .. type(buf), 0)
@@ 491,10 574,16 @@ function M.Event_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.Event_decode_lazy(b) return pb.decode_lazy(M.Event_descriptor, b) end
+---@param t? hello.Address
+---@return hello.Address
function M.Address_new(t) return t or {} end
+---@param t hello.Address
+---@return string
function M.Address_encode(t)
if type(t) ~= 'table' then
error("expected table for hello.Address, got " .. type(t), 0)
@@ 530,6 619,8 @@ function M.Address_encode(t)
return table.concat(out)
end
+---@param b string
+---@return hello.Address
function M.Address_decode(buf)
if type(buf) ~= 'string' then
error("expected string for hello.Address decode, got " .. type(buf), 0)
@@ 567,12 658,21 @@ function M.Address_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.Address_decode_lazy(b) return pb.decode_lazy(M.Address_descriptor, b) end
+---@param t hello.Address
+---@return boolean
function M.Address_has_apartment(t) return t.apartment ~= nil end
+---@param t hello.Address
function M.Address_clear_apartment(t) t.apartment = nil end
+---@param t? hello.Person
+---@return hello.Person
function M.Person_new(t) return t or {} end
+---@param t hello.Person
+---@return string
function M.Person_encode(t)
if type(t) ~= 'table' then
error("expected table for hello.Person, got " .. type(t), 0)
@@ 721,6 821,8 @@ function M.Person_encode(t)
return table.concat(out)
end
+---@param b string
+---@return hello.Person
function M.Person_decode(buf)
if type(buf) ~= 'string' then
error("expected string for hello.Person decode, got " .. type(buf), 0)
@@ 868,6 970,8 @@ function M.Person_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.Person_decode_lazy(b) return pb.decode_lazy(M.Person_descriptor, b) end
-- Service: hello.Greeter
M examples/expected/full/protobuf_test_messages/proto3/test_messages_proto3_pb.lua => examples/expected/full/protobuf_test_messages/proto3/test_messages_proto3_pb.lua +214 -0
@@ 234,8 234,186 @@ M.EnumOnlyProto3_descriptor.fields = {
}
pb.finalize_message(M.EnumOnlyProto3_descriptor)
+-- EmmyLua / lua-language-server type annotations.
+-- These are comments — no runtime effect. They give editors
+-- autocomplete and type-checking for the generated wrappers.
+---@alias protobuf_test_messages.proto3.ForeignEnum integer
+---@alias protobuf_test_messages.proto3.TestAllTypesProto3.NestedEnum integer
+---@alias protobuf_test_messages.proto3.TestAllTypesProto3.AliasedEnum integer
+---@alias protobuf_test_messages.proto3.EnumOnlyProto3.Bool integer
+
+---@class protobuf_test_messages.proto3.TestAllTypesProto3
+---@field optional_int32 integer
+---@field optional_int64 integer
+---@field optional_uint32 integer
+---@field optional_uint64 integer
+---@field optional_sint32 integer
+---@field optional_sint64 integer
+---@field optional_fixed32 integer
+---@field optional_fixed64 integer
+---@field optional_sfixed32 integer
+---@field optional_sfixed64 integer
+---@field optional_float number
+---@field optional_double number
+---@field optional_bool boolean
+---@field optional_string string
+---@field optional_bytes string
+---@field optional_nested_message protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage
+---@field optional_foreign_message protobuf_test_messages.proto3.ForeignMessage
+---@field optional_nested_enum protobuf_test_messages.proto3.TestAllTypesProto3.NestedEnum
+---@field optional_foreign_enum protobuf_test_messages.proto3.ForeignEnum
+---@field optional_aliased_enum protobuf_test_messages.proto3.TestAllTypesProto3.AliasedEnum
+---@field optional_string_piece string
+---@field optional_cord string
+---@field recursive_message protobuf_test_messages.proto3.TestAllTypesProto3
+---@field repeated_int32 integer[]
+---@field repeated_int64 integer[]
+---@field repeated_uint32 integer[]
+---@field repeated_uint64 integer[]
+---@field repeated_sint32 integer[]
+---@field repeated_sint64 integer[]
+---@field repeated_fixed32 integer[]
+---@field repeated_fixed64 integer[]
+---@field repeated_sfixed32 integer[]
+---@field repeated_sfixed64 integer[]
+---@field repeated_float number[]
+---@field repeated_double number[]
+---@field repeated_bool boolean[]
+---@field repeated_string string[]
+---@field repeated_bytes string[]
+---@field repeated_nested_message protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage[]
+---@field repeated_foreign_message protobuf_test_messages.proto3.ForeignMessage[]
+---@field repeated_nested_enum protobuf_test_messages.proto3.TestAllTypesProto3.NestedEnum[]
+---@field repeated_foreign_enum protobuf_test_messages.proto3.ForeignEnum[]
+---@field repeated_string_piece string[]
+---@field repeated_cord string[]
+---@field packed_int32 integer[]
+---@field packed_int64 integer[]
+---@field packed_uint32 integer[]
+---@field packed_uint64 integer[]
+---@field packed_sint32 integer[]
+---@field packed_sint64 integer[]
+---@field packed_fixed32 integer[]
+---@field packed_fixed64 integer[]
+---@field packed_sfixed32 integer[]
+---@field packed_sfixed64 integer[]
+---@field packed_float number[]
+---@field packed_double number[]
+---@field packed_bool boolean[]
+---@field packed_nested_enum protobuf_test_messages.proto3.TestAllTypesProto3.NestedEnum[]
+---@field unpacked_int32 integer[]
+---@field unpacked_int64 integer[]
+---@field unpacked_uint32 integer[]
+---@field unpacked_uint64 integer[]
+---@field unpacked_sint32 integer[]
+---@field unpacked_sint64 integer[]
+---@field unpacked_fixed32 integer[]
+---@field unpacked_fixed64 integer[]
+---@field unpacked_sfixed32 integer[]
+---@field unpacked_sfixed64 integer[]
+---@field unpacked_float number[]
+---@field unpacked_double number[]
+---@field unpacked_bool boolean[]
+---@field unpacked_nested_enum protobuf_test_messages.proto3.TestAllTypesProto3.NestedEnum[]
+---@field map_int32_int32 table<integer, integer>
+---@field map_int64_int64 table<integer, integer>
+---@field map_uint32_uint32 table<integer, integer>
+---@field map_uint64_uint64 table<integer, integer>
+---@field map_sint32_sint32 table<integer, integer>
+---@field map_sint64_sint64 table<integer, integer>
+---@field map_fixed32_fixed32 table<integer, integer>
+---@field map_fixed64_fixed64 table<integer, integer>
+---@field map_sfixed32_sfixed32 table<integer, integer>
+---@field map_sfixed64_sfixed64 table<integer, integer>
+---@field map_int32_float table<integer, number>
+---@field map_int32_double table<integer, number>
+---@field map_bool_bool table<boolean, boolean>
+---@field map_string_string table<string, string>
+---@field map_string_bytes table<string, string>
+---@field map_string_nested_message table<string, protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage>
+---@field map_string_foreign_message table<string, protobuf_test_messages.proto3.ForeignMessage>
+---@field map_string_nested_enum table<string, protobuf_test_messages.proto3.TestAllTypesProto3.NestedEnum>
+---@field map_string_foreign_enum table<string, protobuf_test_messages.proto3.ForeignEnum>
+---@field oneof_uint32? integer
+---@field oneof_nested_message? protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage
+---@field oneof_string? string
+---@field oneof_bytes? string
+---@field oneof_bool? boolean
+---@field oneof_uint64? integer
+---@field oneof_float? number
+---@field oneof_double? number
+---@field oneof_enum? protobuf_test_messages.proto3.TestAllTypesProto3.NestedEnum
+---@field oneof_null_value? google.protobuf.NullValue
+---@field optional_bool_wrapper google.protobuf.BoolValue
+---@field optional_int32_wrapper google.protobuf.Int32Value
+---@field optional_int64_wrapper google.protobuf.Int64Value
+---@field optional_uint32_wrapper google.protobuf.UInt32Value
+---@field optional_uint64_wrapper google.protobuf.UInt64Value
+---@field optional_float_wrapper google.protobuf.FloatValue
+---@field optional_double_wrapper google.protobuf.DoubleValue
+---@field optional_string_wrapper google.protobuf.StringValue
+---@field optional_bytes_wrapper google.protobuf.BytesValue
+---@field repeated_bool_wrapper google.protobuf.BoolValue[]
+---@field repeated_int32_wrapper google.protobuf.Int32Value[]
+---@field repeated_int64_wrapper google.protobuf.Int64Value[]
+---@field repeated_uint32_wrapper google.protobuf.UInt32Value[]
+---@field repeated_uint64_wrapper google.protobuf.UInt64Value[]
+---@field repeated_float_wrapper google.protobuf.FloatValue[]
+---@field repeated_double_wrapper google.protobuf.DoubleValue[]
+---@field repeated_string_wrapper google.protobuf.StringValue[]
+---@field repeated_bytes_wrapper google.protobuf.BytesValue[]
+---@field optional_duration google.protobuf.Duration
+---@field optional_timestamp google.protobuf.Timestamp
+---@field optional_field_mask google.protobuf.FieldMask
+---@field optional_struct google.protobuf.Struct
+---@field optional_any google.protobuf.Any
+---@field optional_value google.protobuf.Value
+---@field optional_null_value google.protobuf.NullValue
+---@field optional_empty google.protobuf.Empty
+---@field repeated_duration google.protobuf.Duration[]
+---@field repeated_timestamp google.protobuf.Timestamp[]
+---@field repeated_fieldmask google.protobuf.FieldMask[]
+---@field repeated_struct google.protobuf.Struct[]
+---@field repeated_any google.protobuf.Any[]
+---@field repeated_value google.protobuf.Value[]
+---@field repeated_list_value google.protobuf.ListValue[]
+---@field repeated_empty google.protobuf.Empty[]
+---@field fieldname1 integer
+---@field field_name2 integer
+---@field _field_name3 integer
+---@field field__name4_ integer
+---@field field0name5 integer
+---@field field_0_name6 integer
+---@field fieldName7 integer
+---@field FieldName8 integer
+---@field field_Name9 integer
+---@field Field_Name10 integer
+---@field FIELD_NAME11 integer
+---@field FIELD_name12 integer
+---@field __field_name13 integer
+---@field __Field_name14 integer
+---@field field__name15 integer
+---@field field__Name16 integer
+---@field field_name17__ integer
+---@field Field_name18__ integer
+
+---@class protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage
+---@field a integer
+---@field corecursive protobuf_test_messages.proto3.TestAllTypesProto3
+
+---@class protobuf_test_messages.proto3.ForeignMessage
+---@field c integer
+
+---@class protobuf_test_messages.proto3.NullHypothesisProto3
+
+---@class protobuf_test_messages.proto3.EnumOnlyProto3
+
+---@param t? protobuf_test_messages.proto3.TestAllTypesProto3
+---@return protobuf_test_messages.proto3.TestAllTypesProto3
function M.TestAllTypesProto3_new(t) return t or {} end
+---@param t protobuf_test_messages.proto3.TestAllTypesProto3
+---@return string
function M.TestAllTypesProto3_encode(t)
if type(t) ~= 'table' then
error("expected table for protobuf_test_messages.proto3.TestAllTypesProto3, got " .. type(t), 0)
@@ 1704,6 1882,8 @@ function M.TestAllTypesProto3_encode(t)
return table.concat(out)
end
+---@param b string
+---@return protobuf_test_messages.proto3.TestAllTypesProto3
function M.TestAllTypesProto3_decode(buf)
if type(buf) ~= 'string' then
error("expected string for protobuf_test_messages.proto3.TestAllTypesProto3 decode, got " .. type(buf), 0)
@@ 3439,10 3619,16 @@ function M.TestAllTypesProto3_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.TestAllTypesProto3_decode_lazy(b) return pb.decode_lazy(M.TestAllTypesProto3_descriptor, b) end
+---@param t? protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage
+---@return protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage
function M.TestAllTypesProto3_NestedMessage_new(t) return t or {} end
+---@param t protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage
+---@return string
function M.TestAllTypesProto3_NestedMessage_encode(t)
if type(t) ~= 'table' then
error("expected table for protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage, got " .. type(t), 0)
@@ 3466,6 3652,8 @@ function M.TestAllTypesProto3_NestedMessage_encode(t)
return table.concat(out)
end
+---@param b string
+---@return protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage
function M.TestAllTypesProto3_NestedMessage_decode(buf)
if type(buf) ~= 'string' then
error("expected string for protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage decode, got " .. type(buf), 0)
@@ 3501,10 3689,16 @@ function M.TestAllTypesProto3_NestedMessage_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.TestAllTypesProto3_NestedMessage_decode_lazy(b) return pb.decode_lazy(M.TestAllTypesProto3_NestedMessage_descriptor, b) end
+---@param t? protobuf_test_messages.proto3.ForeignMessage
+---@return protobuf_test_messages.proto3.ForeignMessage
function M.ForeignMessage_new(t) return t or {} end
+---@param t protobuf_test_messages.proto3.ForeignMessage
+---@return string
function M.ForeignMessage_encode(t)
if type(t) ~= 'table' then
error("expected table for protobuf_test_messages.proto3.ForeignMessage, got " .. type(t), 0)
@@ 3522,6 3716,8 @@ function M.ForeignMessage_encode(t)
return table.concat(out)
end
+---@param b string
+---@return protobuf_test_messages.proto3.ForeignMessage
function M.ForeignMessage_decode(buf)
if type(buf) ~= 'string' then
error("expected string for protobuf_test_messages.proto3.ForeignMessage decode, got " .. type(buf), 0)
@@ 3547,10 3743,16 @@ function M.ForeignMessage_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.ForeignMessage_decode_lazy(b) return pb.decode_lazy(M.ForeignMessage_descriptor, b) end
+---@param t? protobuf_test_messages.proto3.NullHypothesisProto3
+---@return protobuf_test_messages.proto3.NullHypothesisProto3
function M.NullHypothesisProto3_new(t) return t or {} end
+---@param t protobuf_test_messages.proto3.NullHypothesisProto3
+---@return string
function M.NullHypothesisProto3_encode(t)
if type(t) ~= 'table' then
error("expected table for protobuf_test_messages.proto3.NullHypothesisProto3, got " .. type(t), 0)
@@ 3562,6 3764,8 @@ function M.NullHypothesisProto3_encode(t)
return table.concat(out)
end
+---@param b string
+---@return protobuf_test_messages.proto3.NullHypothesisProto3
function M.NullHypothesisProto3_decode(buf)
if type(buf) ~= 'string' then
error("expected string for protobuf_test_messages.proto3.NullHypothesisProto3 decode, got " .. type(buf), 0)
@@ 3584,10 3788,16 @@ function M.NullHypothesisProto3_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.NullHypothesisProto3_decode_lazy(b) return pb.decode_lazy(M.NullHypothesisProto3_descriptor, b) end
+---@param t? protobuf_test_messages.proto3.EnumOnlyProto3
+---@return protobuf_test_messages.proto3.EnumOnlyProto3
function M.EnumOnlyProto3_new(t) return t or {} end
+---@param t protobuf_test_messages.proto3.EnumOnlyProto3
+---@return string
function M.EnumOnlyProto3_encode(t)
if type(t) ~= 'table' then
error("expected table for protobuf_test_messages.proto3.EnumOnlyProto3, got " .. type(t), 0)
@@ 3599,6 3809,8 @@ function M.EnumOnlyProto3_encode(t)
return table.concat(out)
end
+---@param b string
+---@return protobuf_test_messages.proto3.EnumOnlyProto3
function M.EnumOnlyProto3_decode(buf)
if type(buf) ~= 'string' then
error("expected string for protobuf_test_messages.proto3.EnumOnlyProto3 decode, got " .. type(buf), 0)
@@ 3621,6 3833,8 @@ function M.EnumOnlyProto3_decode(buf)
return result
end
+---@param b string
+---@return pb.MessageView
function M.EnumOnlyProto3_decode_lazy(b) return pb.decode_lazy(M.EnumOnlyProto3_descriptor, b) end
return M
M examples/expected/runtime/conformance/conformance_pb.lua => examples/expected/runtime/conformance/conformance_pb.lua +79 -0
@@ 90,29 90,108 @@ M.JspbEncodingConfig_descriptor.fields = {
}
pb.finalize_message(M.JspbEncodingConfig_descriptor)
+-- EmmyLua / lua-language-server type annotations.
+-- These are comments — no runtime effect. They give editors
+-- autocomplete and type-checking for the generated wrappers.
+---@alias conformance.WireFormat integer
+---@alias conformance.TestCategory integer
+
+---@class conformance.TestStatus
+---@field name string
+---@field failure_message string
+---@field matched_name string
+
+---@class conformance.FailureSet
+---@field test conformance.TestStatus[]
+
+---@class conformance.ConformanceRequest
+---@field protobuf_payload? string
+---@field json_payload? string
+---@field jspb_payload? string
+---@field text_payload? string
+---@field requested_output_format conformance.WireFormat
+---@field message_type string
+---@field test_category conformance.TestCategory
+---@field jspb_encoding_options conformance.JspbEncodingConfig
+---@field print_unknown_fields boolean
+
+---@class conformance.ConformanceResponse
+---@field parse_error? string
+---@field serialize_error? string
+---@field timeout_error? string
+---@field runtime_error? string
+---@field protobuf_payload? string
+---@field json_payload? string
+---@field skipped? string
+---@field jspb_payload? string
+---@field text_payload? string
+
+---@class conformance.JspbEncodingConfig
+---@field use_jspb_array_any_format boolean
+
+---@param t? conformance.TestStatus
+---@return conformance.TestStatus
function M.TestStatus_new(t) return t or {} end
+---@param t conformance.TestStatus
+---@return string
function M.TestStatus_encode(t) return pb.encode(M.TestStatus_descriptor, t) end
+---@param b string
+---@return conformance.TestStatus
function M.TestStatus_decode(b) return pb.decode(M.TestStatus_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.TestStatus_decode_lazy(b) return pb.decode_lazy(M.TestStatus_descriptor, b) end
+---@param t? conformance.FailureSet
+---@return conformance.FailureSet
function M.FailureSet_new(t) return t or {} end
+---@param t conformance.FailureSet
+---@return string
function M.FailureSet_encode(t) return pb.encode(M.FailureSet_descriptor, t) end
+---@param b string
+---@return conformance.FailureSet
function M.FailureSet_decode(b) return pb.decode(M.FailureSet_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.FailureSet_decode_lazy(b) return pb.decode_lazy(M.FailureSet_descriptor, b) end
+---@param t? conformance.ConformanceRequest
+---@return conformance.ConformanceRequest
function M.ConformanceRequest_new(t) return t or {} end
+---@param t conformance.ConformanceRequest
+---@return string
function M.ConformanceRequest_encode(t) return pb.encode(M.ConformanceRequest_descriptor, t) end
+---@param b string
+---@return conformance.ConformanceRequest
function M.ConformanceRequest_decode(b) return pb.decode(M.ConformanceRequest_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.ConformanceRequest_decode_lazy(b) return pb.decode_lazy(M.ConformanceRequest_descriptor, b) end
+---@param t? conformance.ConformanceResponse
+---@return conformance.ConformanceResponse
function M.ConformanceResponse_new(t) return t or {} end
+---@param t conformance.ConformanceResponse
+---@return string
function M.ConformanceResponse_encode(t) return pb.encode(M.ConformanceResponse_descriptor, t) end
+---@param b string
+---@return conformance.ConformanceResponse
function M.ConformanceResponse_decode(b) return pb.decode(M.ConformanceResponse_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.ConformanceResponse_decode_lazy(b) return pb.decode_lazy(M.ConformanceResponse_descriptor, b) end
+---@param t? conformance.JspbEncodingConfig
+---@return conformance.JspbEncodingConfig
function M.JspbEncodingConfig_new(t) return t or {} end
+---@param t conformance.JspbEncodingConfig
+---@return string
function M.JspbEncodingConfig_encode(t) return pb.encode(M.JspbEncodingConfig_descriptor, t) end
+---@param b string
+---@return conformance.JspbEncodingConfig
function M.JspbEncodingConfig_decode(b) return pb.decode(M.JspbEncodingConfig_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.JspbEncodingConfig_decode_lazy(b) return pb.decode_lazy(M.JspbEncodingConfig_descriptor, b) end
return M
M examples/expected/runtime/hello/hello_pb.lua => examples/expected/runtime/hello/hello_pb.lua +104 -0
@@ 93,36 93,140 @@ M.Person_descriptor.fields = {
}
pb.finalize_message(M.Person_descriptor)
+-- EmmyLua / lua-language-server type annotations.
+-- These are comments — no runtime effect. They give editors
+-- autocomplete and type-checking for the generated wrappers.
+---@alias hello.Status integer
+
+---@class hello.Result
+---@field id integer
+---@field text? string
+---@field code? integer
+---@field details? hello.Address
+
+---@class hello.HelloRequest
+---@field name string
+
+---@class hello.HelloReply
+---@field greeting string
+
+---@class hello.Event
+---@field title string
+---@field created_at google.protobuf.Timestamp
+---@field duration google.protobuf.Duration
+---@field ack google.protobuf.Empty
+---@field retry_count google.protobuf.Int32Value
+---@field note google.protobuf.StringValue
+---@field is_admin google.protobuf.BoolValue
+---@field payload google.protobuf.Struct
+---@field attribute google.protobuf.Value
+---@field tags google.protobuf.ListValue
+---@field extension google.protobuf.Any
+---@field update_mask google.protobuf.FieldMask
+
+---@class hello.Address
+---@field street string
+---@field city string
+---@field zip integer
+---@field apartment? string
+
+---@class hello.Person
+---@field name string
+---@field age integer
+---@field emails string[]
+---@field status hello.Status
+---@field address hello.Address
+---@field friends hello.Person[]
+---@field lucky_numbers integer[]
+---@field avatar string
+---@field user_id integer
+---@field balance integer
+---@field weight_kg number
+---@field ages_by_nickname table<string, integer>
+---@field nickname_by_age table<integer, string>
+---@field addresses_by_label table<string, hello.Address>
+
+---@param t? hello.Result
+---@return hello.Result
function M.Result_new(t) return t or {} end
+---@param t hello.Result
+---@return string
function M.Result_encode(t) return pb.encode(M.Result_descriptor, t) end
+---@param b string
+---@return hello.Result
function M.Result_decode(b) return pb.decode(M.Result_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.Result_decode_lazy(b) return pb.decode_lazy(M.Result_descriptor, b) end
+---@param t? hello.HelloRequest
+---@return hello.HelloRequest
function M.HelloRequest_new(t) return t or {} end
+---@param t hello.HelloRequest
+---@return string
function M.HelloRequest_encode(t) return pb.encode(M.HelloRequest_descriptor, t) end
+---@param b string
+---@return hello.HelloRequest
function M.HelloRequest_decode(b) return pb.decode(M.HelloRequest_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.HelloRequest_decode_lazy(b) return pb.decode_lazy(M.HelloRequest_descriptor, b) end
+---@param t? hello.HelloReply
+---@return hello.HelloReply
function M.HelloReply_new(t) return t or {} end
+---@param t hello.HelloReply
+---@return string
function M.HelloReply_encode(t) return pb.encode(M.HelloReply_descriptor, t) end
+---@param b string
+---@return hello.HelloReply
function M.HelloReply_decode(b) return pb.decode(M.HelloReply_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.HelloReply_decode_lazy(b) return pb.decode_lazy(M.HelloReply_descriptor, b) end
+---@param t? hello.Event
+---@return hello.Event
function M.Event_new(t) return t or {} end
+---@param t hello.Event
+---@return string
function M.Event_encode(t) return pb.encode(M.Event_descriptor, t) end
+---@param b string
+---@return hello.Event
function M.Event_decode(b) return pb.decode(M.Event_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.Event_decode_lazy(b) return pb.decode_lazy(M.Event_descriptor, b) end
+---@param t? hello.Address
+---@return hello.Address
function M.Address_new(t) return t or {} end
+---@param t hello.Address
+---@return string
function M.Address_encode(t) return pb.encode(M.Address_descriptor, t) end
+---@param b string
+---@return hello.Address
function M.Address_decode(b) return pb.decode(M.Address_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.Address_decode_lazy(b) return pb.decode_lazy(M.Address_descriptor, b) end
+---@param t hello.Address
+---@return boolean
function M.Address_has_apartment(t) return t.apartment ~= nil end
+---@param t hello.Address
function M.Address_clear_apartment(t) t.apartment = nil end
+---@param t? hello.Person
+---@return hello.Person
function M.Person_new(t) return t or {} end
+---@param t hello.Person
+---@return string
function M.Person_encode(t) return pb.encode(M.Person_descriptor, t) end
+---@param b string
+---@return hello.Person
function M.Person_decode(b) return pb.decode(M.Person_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.Person_decode_lazy(b) return pb.decode_lazy(M.Person_descriptor, b) end
-- Service: hello.Greeter
M examples/expected/runtime/protobuf_test_messages/proto3/test_messages_proto3_pb.lua => examples/expected/runtime/protobuf_test_messages/proto3/test_messages_proto3_pb.lua +214 -0
@@ 234,29 234,243 @@ M.EnumOnlyProto3_descriptor.fields = {
}
pb.finalize_message(M.EnumOnlyProto3_descriptor)
+-- EmmyLua / lua-language-server type annotations.
+-- These are comments — no runtime effect. They give editors
+-- autocomplete and type-checking for the generated wrappers.
+---@alias protobuf_test_messages.proto3.ForeignEnum integer
+---@alias protobuf_test_messages.proto3.TestAllTypesProto3.NestedEnum integer
+---@alias protobuf_test_messages.proto3.TestAllTypesProto3.AliasedEnum integer
+---@alias protobuf_test_messages.proto3.EnumOnlyProto3.Bool integer
+
+---@class protobuf_test_messages.proto3.TestAllTypesProto3
+---@field optional_int32 integer
+---@field optional_int64 integer
+---@field optional_uint32 integer
+---@field optional_uint64 integer
+---@field optional_sint32 integer
+---@field optional_sint64 integer
+---@field optional_fixed32 integer
+---@field optional_fixed64 integer
+---@field optional_sfixed32 integer
+---@field optional_sfixed64 integer
+---@field optional_float number
+---@field optional_double number
+---@field optional_bool boolean
+---@field optional_string string
+---@field optional_bytes string
+---@field optional_nested_message protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage
+---@field optional_foreign_message protobuf_test_messages.proto3.ForeignMessage
+---@field optional_nested_enum protobuf_test_messages.proto3.TestAllTypesProto3.NestedEnum
+---@field optional_foreign_enum protobuf_test_messages.proto3.ForeignEnum
+---@field optional_aliased_enum protobuf_test_messages.proto3.TestAllTypesProto3.AliasedEnum
+---@field optional_string_piece string
+---@field optional_cord string
+---@field recursive_message protobuf_test_messages.proto3.TestAllTypesProto3
+---@field repeated_int32 integer[]
+---@field repeated_int64 integer[]
+---@field repeated_uint32 integer[]
+---@field repeated_uint64 integer[]
+---@field repeated_sint32 integer[]
+---@field repeated_sint64 integer[]
+---@field repeated_fixed32 integer[]
+---@field repeated_fixed64 integer[]
+---@field repeated_sfixed32 integer[]
+---@field repeated_sfixed64 integer[]
+---@field repeated_float number[]
+---@field repeated_double number[]
+---@field repeated_bool boolean[]
+---@field repeated_string string[]
+---@field repeated_bytes string[]
+---@field repeated_nested_message protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage[]
+---@field repeated_foreign_message protobuf_test_messages.proto3.ForeignMessage[]
+---@field repeated_nested_enum protobuf_test_messages.proto3.TestAllTypesProto3.NestedEnum[]
+---@field repeated_foreign_enum protobuf_test_messages.proto3.ForeignEnum[]
+---@field repeated_string_piece string[]
+---@field repeated_cord string[]
+---@field packed_int32 integer[]
+---@field packed_int64 integer[]
+---@field packed_uint32 integer[]
+---@field packed_uint64 integer[]
+---@field packed_sint32 integer[]
+---@field packed_sint64 integer[]
+---@field packed_fixed32 integer[]
+---@field packed_fixed64 integer[]
+---@field packed_sfixed32 integer[]
+---@field packed_sfixed64 integer[]
+---@field packed_float number[]
+---@field packed_double number[]
+---@field packed_bool boolean[]
+---@field packed_nested_enum protobuf_test_messages.proto3.TestAllTypesProto3.NestedEnum[]
+---@field unpacked_int32 integer[]
+---@field unpacked_int64 integer[]
+---@field unpacked_uint32 integer[]
+---@field unpacked_uint64 integer[]
+---@field unpacked_sint32 integer[]
+---@field unpacked_sint64 integer[]
+---@field unpacked_fixed32 integer[]
+---@field unpacked_fixed64 integer[]
+---@field unpacked_sfixed32 integer[]
+---@field unpacked_sfixed64 integer[]
+---@field unpacked_float number[]
+---@field unpacked_double number[]
+---@field unpacked_bool boolean[]
+---@field unpacked_nested_enum protobuf_test_messages.proto3.TestAllTypesProto3.NestedEnum[]
+---@field map_int32_int32 table<integer, integer>
+---@field map_int64_int64 table<integer, integer>
+---@field map_uint32_uint32 table<integer, integer>
+---@field map_uint64_uint64 table<integer, integer>
+---@field map_sint32_sint32 table<integer, integer>
+---@field map_sint64_sint64 table<integer, integer>
+---@field map_fixed32_fixed32 table<integer, integer>
+---@field map_fixed64_fixed64 table<integer, integer>
+---@field map_sfixed32_sfixed32 table<integer, integer>
+---@field map_sfixed64_sfixed64 table<integer, integer>
+---@field map_int32_float table<integer, number>
+---@field map_int32_double table<integer, number>
+---@field map_bool_bool table<boolean, boolean>
+---@field map_string_string table<string, string>
+---@field map_string_bytes table<string, string>
+---@field map_string_nested_message table<string, protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage>
+---@field map_string_foreign_message table<string, protobuf_test_messages.proto3.ForeignMessage>
+---@field map_string_nested_enum table<string, protobuf_test_messages.proto3.TestAllTypesProto3.NestedEnum>
+---@field map_string_foreign_enum table<string, protobuf_test_messages.proto3.ForeignEnum>
+---@field oneof_uint32? integer
+---@field oneof_nested_message? protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage
+---@field oneof_string? string
+---@field oneof_bytes? string
+---@field oneof_bool? boolean
+---@field oneof_uint64? integer
+---@field oneof_float? number
+---@field oneof_double? number
+---@field oneof_enum? protobuf_test_messages.proto3.TestAllTypesProto3.NestedEnum
+---@field oneof_null_value? google.protobuf.NullValue
+---@field optional_bool_wrapper google.protobuf.BoolValue
+---@field optional_int32_wrapper google.protobuf.Int32Value
+---@field optional_int64_wrapper google.protobuf.Int64Value
+---@field optional_uint32_wrapper google.protobuf.UInt32Value
+---@field optional_uint64_wrapper google.protobuf.UInt64Value
+---@field optional_float_wrapper google.protobuf.FloatValue
+---@field optional_double_wrapper google.protobuf.DoubleValue
+---@field optional_string_wrapper google.protobuf.StringValue
+---@field optional_bytes_wrapper google.protobuf.BytesValue
+---@field repeated_bool_wrapper google.protobuf.BoolValue[]
+---@field repeated_int32_wrapper google.protobuf.Int32Value[]
+---@field repeated_int64_wrapper google.protobuf.Int64Value[]
+---@field repeated_uint32_wrapper google.protobuf.UInt32Value[]
+---@field repeated_uint64_wrapper google.protobuf.UInt64Value[]
+---@field repeated_float_wrapper google.protobuf.FloatValue[]
+---@field repeated_double_wrapper google.protobuf.DoubleValue[]
+---@field repeated_string_wrapper google.protobuf.StringValue[]
+---@field repeated_bytes_wrapper google.protobuf.BytesValue[]
+---@field optional_duration google.protobuf.Duration
+---@field optional_timestamp google.protobuf.Timestamp
+---@field optional_field_mask google.protobuf.FieldMask
+---@field optional_struct google.protobuf.Struct
+---@field optional_any google.protobuf.Any
+---@field optional_value google.protobuf.Value
+---@field optional_null_value google.protobuf.NullValue
+---@field optional_empty google.protobuf.Empty
+---@field repeated_duration google.protobuf.Duration[]
+---@field repeated_timestamp google.protobuf.Timestamp[]
+---@field repeated_fieldmask google.protobuf.FieldMask[]
+---@field repeated_struct google.protobuf.Struct[]
+---@field repeated_any google.protobuf.Any[]
+---@field repeated_value google.protobuf.Value[]
+---@field repeated_list_value google.protobuf.ListValue[]
+---@field repeated_empty google.protobuf.Empty[]
+---@field fieldname1 integer
+---@field field_name2 integer
+---@field _field_name3 integer
+---@field field__name4_ integer
+---@field field0name5 integer
+---@field field_0_name6 integer
+---@field fieldName7 integer
+---@field FieldName8 integer
+---@field field_Name9 integer
+---@field Field_Name10 integer
+---@field FIELD_NAME11 integer
+---@field FIELD_name12 integer
+---@field __field_name13 integer
+---@field __Field_name14 integer
+---@field field__name15 integer
+---@field field__Name16 integer
+---@field field_name17__ integer
+---@field Field_name18__ integer
+
+---@class protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage
+---@field a integer
+---@field corecursive protobuf_test_messages.proto3.TestAllTypesProto3
+
+---@class protobuf_test_messages.proto3.ForeignMessage
+---@field c integer
+
+---@class protobuf_test_messages.proto3.NullHypothesisProto3
+
+---@class protobuf_test_messages.proto3.EnumOnlyProto3
+
+---@param t? protobuf_test_messages.proto3.TestAllTypesProto3
+---@return protobuf_test_messages.proto3.TestAllTypesProto3
function M.TestAllTypesProto3_new(t) return t or {} end
+---@param t protobuf_test_messages.proto3.TestAllTypesProto3
+---@return string
function M.TestAllTypesProto3_encode(t) return pb.encode(M.TestAllTypesProto3_descriptor, t) end
+---@param b string
+---@return protobuf_test_messages.proto3.TestAllTypesProto3
function M.TestAllTypesProto3_decode(b) return pb.decode(M.TestAllTypesProto3_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.TestAllTypesProto3_decode_lazy(b) return pb.decode_lazy(M.TestAllTypesProto3_descriptor, b) end
+---@param t? protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage
+---@return protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage
function M.TestAllTypesProto3_NestedMessage_new(t) return t or {} end
+---@param t protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage
+---@return string
function M.TestAllTypesProto3_NestedMessage_encode(t) return pb.encode(M.TestAllTypesProto3_NestedMessage_descriptor, t) end
+---@param b string
+---@return protobuf_test_messages.proto3.TestAllTypesProto3.NestedMessage
function M.TestAllTypesProto3_NestedMessage_decode(b) return pb.decode(M.TestAllTypesProto3_NestedMessage_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.TestAllTypesProto3_NestedMessage_decode_lazy(b) return pb.decode_lazy(M.TestAllTypesProto3_NestedMessage_descriptor, b) end
+---@param t? protobuf_test_messages.proto3.ForeignMessage
+---@return protobuf_test_messages.proto3.ForeignMessage
function M.ForeignMessage_new(t) return t or {} end
+---@param t protobuf_test_messages.proto3.ForeignMessage
+---@return string
function M.ForeignMessage_encode(t) return pb.encode(M.ForeignMessage_descriptor, t) end
+---@param b string
+---@return protobuf_test_messages.proto3.ForeignMessage
function M.ForeignMessage_decode(b) return pb.decode(M.ForeignMessage_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.ForeignMessage_decode_lazy(b) return pb.decode_lazy(M.ForeignMessage_descriptor, b) end
+---@param t? protobuf_test_messages.proto3.NullHypothesisProto3
+---@return protobuf_test_messages.proto3.NullHypothesisProto3
function M.NullHypothesisProto3_new(t) return t or {} end
+---@param t protobuf_test_messages.proto3.NullHypothesisProto3
+---@return string
function M.NullHypothesisProto3_encode(t) return pb.encode(M.NullHypothesisProto3_descriptor, t) end
+---@param b string
+---@return protobuf_test_messages.proto3.NullHypothesisProto3
function M.NullHypothesisProto3_decode(b) return pb.decode(M.NullHypothesisProto3_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.NullHypothesisProto3_decode_lazy(b) return pb.decode_lazy(M.NullHypothesisProto3_descriptor, b) end
+---@param t? protobuf_test_messages.proto3.EnumOnlyProto3
+---@return protobuf_test_messages.proto3.EnumOnlyProto3
function M.EnumOnlyProto3_new(t) return t or {} end
+---@param t protobuf_test_messages.proto3.EnumOnlyProto3
+---@return string
function M.EnumOnlyProto3_encode(t) return pb.encode(M.EnumOnlyProto3_descriptor, t) end
+---@param b string
+---@return protobuf_test_messages.proto3.EnumOnlyProto3
function M.EnumOnlyProto3_decode(b) return pb.decode(M.EnumOnlyProto3_descriptor, b) end
+---@param b string
+---@return pb.MessageView
function M.EnumOnlyProto3_decode_lazy(b) return pb.decode_lazy(M.EnumOnlyProto3_descriptor, b) end
return M
M runtime/pb/lazy.lua => runtime/pb/lazy.lua +24 -0
@@ 19,6 19,30 @@
-- wrapped in an EagerView with the same getter surface, so callers
-- don't have to special-case Timestamp/Duration/Struct/etc.
+---@class pb.MessageView
+---@field get fun(self: pb.MessageView, name: string): any
+---@field has fun(self: pb.MessageView, name: string): boolean
+---@field which fun(self: pb.MessageView, oneof_name: string): string?
+---@field iter fun(self: pb.MessageView): fun(): string?, any
+---@field names fun(self: pb.MessageView): fun(): string?
+---@field set fun(self: pb.MessageView, name: string, value: any)
+---@field is_dirty fun(self: pb.MessageView): boolean
+---@field totable fun(self: pb.MessageView): table
+---@field encode fun(self: pb.MessageView): string
+---
+---@class pb.ArrayView
+---@field len fun(self: pb.ArrayView): integer
+---@field at fun(self: pb.ArrayView, i: integer): any
+---@field iter fun(self: pb.ArrayView): fun(): integer?, any
+---@field tolist fun(self: pb.ArrayView): any[]
+---
+---@class pb.MapView
+---@field get fun(self: pb.MapView, k: any): any
+---@field has fun(self: pb.MapView, k: any): boolean
+---@field keys fun(self: pb.MapView): any[]
+---@field iter fun(self: pb.MapView): fun(): any?, any
+---@field totable fun(self: pb.MapView): table
+
local wire = require('pb.wire')
local codec = require('pb.codec')