-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Conversion of some protobuf types to lua types (#1)
- add support for strings - add support for numbers - add support for bools - add support for message - add support for google.protobuf.timestamp
- Loading branch information
1 parent
0de4061
commit dbd7692
Showing
38 changed files
with
3,596 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
on: | ||
push: | ||
paths-ignore: | ||
- '**/**.md' | ||
|
||
concurrency: ci-${{ github.ref }} | ||
|
||
name: protobuf-go-ci | ||
|
||
jobs: | ||
ci: | ||
name: "CI" | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Install go | ||
uses: actions/setup-go@v3 | ||
with: | ||
go-version: '^1.20.0' | ||
- name: "Installed go version" | ||
run: go version | ||
- name: "Build" | ||
run: | | ||
go build ./... | ||
- name: "Test" | ||
run: | | ||
go test ./... -race -coverprofile=coverage.out | ||
- name: "Code coverage" | ||
uses: codecov/codecov-action@v3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
on: | ||
workflow_dispatch | ||
|
||
env: | ||
MAJOR_MINOR_PATCH: 0.1.0 | ||
FEATURE_BRANCH_BUILD: 1 | ||
|
||
concurrency: release-${{ github.ref }} | ||
|
||
name: protobuf-go-release | ||
|
||
jobs: | ||
publish: | ||
name: "Publish" | ||
runs-on: ubuntu-latest | ||
permissions: | ||
contents: write | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Version suffix | ||
id: version_suffix | ||
run: | | ||
if [[ ${{ github.ref }} == "refs/heads/${{ github.event.repository.default_branch }}" ]]; then | ||
echo 'for default branch pipeline' | ||
USE=false | ||
SUFFIX='' | ||
EXTENSION='' | ||
else | ||
echo 'for feature branch pipeline' | ||
USE=true | ||
SUFFIX=${GITHUB_REF##*/}.${{env.FEATURE_BRANCH_BUILD}} | ||
EXTENSION="-${SUFFIX}" | ||
fi | ||
echo 'use_version_suffix' $USE | ||
echo 'version_suffix: ' $SUFFIX | ||
echo "use_version_suffix=$USE" >> $GITHUB_OUTPUT | ||
echo "version_suffix=$SUFFIX" >> $GITHUB_OUTPUT | ||
echo "extension=$EXTENSION" >> $GITHUB_OUTPUT | ||
- name : Semantic version | ||
id: semantic_version | ||
run: | | ||
SEMANTIC_VERSION="${{ env.MAJOR_MINOR_PATCH }}" | ||
SEMANTIC_VERSION="${SEMANTIC_VERSION}${{ steps.version_suffix.outputs.extension }}" | ||
echo 'MAJOR_MINOR_PATCH: ' $MAJOR_MINOR_PATCH | ||
echo 'SEMANTIC_VERSION: ' $SEMANTIC_VERSION | ||
echo "semantic_version=$SEMANTIC_VERSION" >> $GITHUB_OUTPUT | ||
echo "major_minor_patch=$MAJOR_MINOR_PATCH" >> $GITHUB_OUTPUT | ||
- name: Create semantic versioning git tag for golang | ||
uses: actions/github-script@v6 | ||
with: | ||
script: | | ||
github.rest.git.createRef({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
ref: "refs/tags/v${{ steps.semantic_version.outputs.semantic_version }}", | ||
sha: context.sha | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# If you prefer the allow list template instead of the deny list, see community template: | ||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore | ||
# | ||
# Binaries for programs and plugins | ||
*.exe | ||
*.exe~ | ||
*.dll | ||
*.so | ||
*.dylib | ||
|
||
# Test binary, built with `go test -c` | ||
*.test | ||
|
||
# Output of the go coverage tool, specifically when used with LiteIDE | ||
*.out | ||
|
||
# Dependency directories (remove the comment below to include it) | ||
# vendor/ | ||
|
||
# Go workspace file | ||
go.work | ||
|
||
# Downloaded proto compiler | ||
internal/encoding/testing/protoc/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"[go]": { | ||
"editor.insertSpaces": false, | ||
"editor.formatOnSave": false, | ||
"editor.codeActionsOnSave": { | ||
"source.organizeImports": true | ||
}, | ||
"editor.suggest.snippetsPreventQuickSuggestions": false, | ||
}, | ||
"go.lintOnSave": "package" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<picture> | ||
<img alt="Protobuf icon" src="/documentation/img/file-type-protobuf.svg" width="25%" height="25%"> | ||
</picture> | ||
<picture> | ||
<img alt="Heart" src="https://github.githubassets.com/images/icons/emoji/unicode/2764.png"> | ||
</picture> | ||
<picture> | ||
<img alt="Lua icon" src="/documentation/img/file-type-lua.svg" width="25%" height="25%"> | ||
</picture> | ||
<picture> | ||
<img alt="Heart" src="https://github.githubassets.com/images/icons/emoji/unicode/2764.png"> | ||
</picture> | ||
<picture> | ||
<img alt="Latex icon" src="/documentation/img/latex.svg" width="25%" height="25%"> | ||
</picture> | ||
|
||
# Go related code for protocol buffers | ||
This repository contains Go implementation for [protocol buffers](https://protobuf.dev). | ||
|
||
The code design is based on [protocolbuffers/protobuf-go](https://github.com/protocolbuffers/protobuf-go). | ||
|
||
## Packages | ||
* [`encoding/protolua`]: | ||
Package `protolua` converts protobuf messages to lua data types mostly using tables. | ||
One way conversion is only supported for now. | ||
Limited support of protobuf types because for it is only in usage in context of LuaTex. | ||
|
||
# Status | ||
[![protobuf-go-ci](https://github.com/KinNeko-De/protobuf-go/actions/workflows/ci.yml/badge.svg)](https://github.com/KinNeko-De/protobuf-go/actions/workflows/ci.yml) | ||
[![codecov](https://codecov.io/gh/KinNeko-De/protobuf-go/branch/main/graph/badge.svg?token=yvQYJ6kpYr)](https://codecov.io/gh/KinNeko-De/protobuf-go) | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
package protolua | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
"google.golang.org/protobuf/proto" | ||
"google.golang.org/protobuf/reflect/protoreflect" | ||
) | ||
|
||
// Marshal converts the given proto.Message into a lua table using default options. | ||
// Supports only proto3 messages currently. | ||
func Marshal(m proto.Message) ([]byte, error) { | ||
return LuaMarshalOption{}.Marshal(m) | ||
} | ||
|
||
type ( | ||
EncodingRun struct { | ||
*Encoder | ||
options LuaMarshalOption | ||
} | ||
|
||
MarshalFunc func(EncodingRun, protoreflect.Message) error | ||
|
||
LuaMarshalOption struct { | ||
Format struct { | ||
// If set to false the output is formated as one line (default) | ||
// If set to true the output is formated in multiple line with indent (better for humans) | ||
Multiline bool | ||
} | ||
|
||
// Defines how the name of message are crated | ||
// If set to nil, [protolua.JsonName] will be used | ||
KeyName interface { | ||
keyName(protoreflect.FieldDescriptor) string | ||
} | ||
|
||
// Additional Marshalers for non standard proto messages | ||
// see [protolua.GoogleWellKnownTypesMarshaler] for an example | ||
AdditionalMarshalers []interface { | ||
Handle(fullName protoreflect.FullName) (MarshalFunc, error) | ||
} | ||
} | ||
) | ||
|
||
// Marshal convert the given proto.Message into a lua table using the given options. | ||
func (o LuaMarshalOption) Marshal(m proto.Message) ([]byte, error) { | ||
return o.marshal(m) | ||
} | ||
|
||
func (option LuaMarshalOption) marshal(m proto.Message) ([]byte, error) { | ||
if m == nil { | ||
return nil, errors.New("message can not be nil") | ||
} | ||
|
||
setDefaults(&option) | ||
indent := "" | ||
if option.Format.Multiline { | ||
indent = DefaultIndent | ||
} | ||
|
||
encoder, err := NewEncoder(indent) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
encodingRun := EncodingRun{encoder, option} | ||
|
||
bytes, err2 := marshalRootMessage(m.ProtoReflect(), encodingRun) | ||
if err2 != nil { | ||
return bytes, err2 | ||
} | ||
|
||
return encodingRun.Encoder.Bytes(), nil | ||
} | ||
|
||
func setDefaults(option *LuaMarshalOption) { | ||
if option.KeyName == nil { | ||
option.KeyName = JsonName{} | ||
} | ||
} | ||
|
||
func marshalRootMessage(m protoreflect.Message, encodingRun EncodingRun) ([]byte, error) { | ||
// The json name is not populated, so the Protobuf name is used hereX | ||
encodingRun.Encoder.WriteKey(string(m.Descriptor().Name())) | ||
|
||
if err := encodingRun.marshalMessage(m); err != nil { | ||
return nil, err | ||
} | ||
return nil, nil | ||
} | ||
|
||
// marshalMessage marshals the message and fields in the given protoreflect.Message. | ||
func (e EncodingRun) marshalMessage(m protoreflect.Message) error { | ||
if m.Descriptor().Syntax() != protoreflect.Proto3 { | ||
return errors.New("only proto3 syntax is supported") | ||
} | ||
|
||
for _, marshaler := range e.options.AdditionalMarshalers { | ||
marshalFunc, unsupportedTypeError := marshaler.Handle(m.Descriptor().FullName()) | ||
shouldReturn, returnValue := isHandledByOtherMarshaler(unsupportedTypeError, marshalFunc, e, m) | ||
if shouldReturn { | ||
return returnValue | ||
} | ||
} | ||
|
||
marshalFunc, unsupportedTypeError := GoogleWellKnownTypesMarshaler{}.Handle(m.Descriptor().FullName()) | ||
shouldReturn, returnValue := isHandledByOtherMarshaler(unsupportedTypeError, marshalFunc, e, m) | ||
if shouldReturn { | ||
return returnValue | ||
} | ||
|
||
if !m.IsValid() { | ||
e.Encoder.WriteNull() | ||
return nil | ||
} | ||
|
||
var err error | ||
e.Encoder.StartObject() | ||
defer e.Encoder.EndObject() | ||
|
||
fields := m.Descriptor().Fields() | ||
upper := fields.Len() | ||
for i := 0; i < upper; i++ { | ||
currentField := fields.Get(i) | ||
name := e.options.KeyName.keyName(currentField) | ||
|
||
if err = e.Encoder.WriteKey(name); err != nil { | ||
return err | ||
} | ||
if err = e.marshalValue(m.Get(currentField), currentField); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return err | ||
} | ||
|
||
func isHandledByOtherMarshaler(unsupportedTypeError error, marshalFunc MarshalFunc, e EncodingRun, m protoreflect.Message) (bool, error) { | ||
if unsupportedTypeError != nil { | ||
return true, unsupportedTypeError | ||
} | ||
if marshalFunc != nil { | ||
return true, marshalFunc(e, m) | ||
} | ||
return false, nil | ||
} | ||
|
||
func (e EncodingRun) marshalValue(val protoreflect.Value, fd protoreflect.FieldDescriptor) error { | ||
switch { | ||
case fd.IsList(): | ||
return e.marshalList(val.List(), fd) | ||
case fd.IsMap(): | ||
return e.marshalMap(val.Map(), fd) | ||
default: | ||
return e.marshalSingular(val, fd) | ||
} | ||
} | ||
|
||
func (e EncodingRun) marshalSingular(val protoreflect.Value, fd protoreflect.FieldDescriptor) error { | ||
if !val.IsValid() { | ||
return nil | ||
} | ||
|
||
switch kind := fd.Kind(); kind { | ||
case protoreflect.BoolKind: | ||
e.WriteBool(val.Bool()) | ||
|
||
case protoreflect.StringKind: | ||
if err := e.Encoder.WriteString(val.String()); err != nil { | ||
return err | ||
} | ||
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, | ||
protoreflect.Uint32Kind, protoreflect.Fixed32Kind, | ||
protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind, | ||
protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind: | ||
e.Encoder.WriteNumber(val.String()) | ||
|
||
case protoreflect.FloatKind: | ||
return errors.New("float is not supported yet") | ||
|
||
case protoreflect.DoubleKind: | ||
return errors.New("float is not supported yet") | ||
|
||
case protoreflect.BytesKind: | ||
return errors.New("byte is not supported yet") | ||
|
||
case protoreflect.EnumKind: | ||
return errors.New("enum is not supported yet") | ||
|
||
case protoreflect.MessageKind, protoreflect.GroupKind: | ||
if err := e.marshalMessage(val.Message()); err != nil { | ||
return err | ||
} | ||
|
||
default: | ||
panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind)) | ||
} | ||
return nil | ||
} | ||
|
||
func (e EncodingRun) marshalList(list protoreflect.List, fd protoreflect.FieldDescriptor) error { | ||
|
||
e.Encoder.StartArray() | ||
defer e.Encoder.EndArray() | ||
|
||
for i := 0; i < list.Len(); i++ { | ||
item := list.Get(i) | ||
e.Encoder.WriteIndexedList(i + 1) | ||
if err := e.marshalSingular(item, fd); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (e EncodingRun) marshalMap(mmap protoreflect.Map, fd protoreflect.FieldDescriptor) error { | ||
return errors.New("maps are not supported yet") | ||
} | ||
|
Oops, something went wrong.