diff --git a/README.md b/README.md index 77395c1..1e705f8 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Built for game networking where every byte and allocation matters. ## Installation ```bash -go install edmand46/arpack/cmd/arpack@latest +go install github.com/edmand46/arpack/cmd/arpack@latest ``` ## Usage diff --git a/cmd/arpack/main.go b/cmd/arpack/main.go index 1ddf833..3a36264 100644 --- a/cmd/arpack/main.go +++ b/cmd/arpack/main.go @@ -1,8 +1,8 @@ package main import ( - "edmand46/arpack/generator" - "edmand46/arpack/parser" + "github.com/edmand46/arpack/generator" + "github.com/edmand46/arpack/parser" "flag" "fmt" "log" diff --git a/e2e/e2e_test.go b/e2e/e2e_test.go index f1e7187..8f3320c 100644 --- a/e2e/e2e_test.go +++ b/e2e/e2e_test.go @@ -2,8 +2,8 @@ package e2e import ( "bytes" - "edmand46/arpack/generator" - "edmand46/arpack/parser" + "github.com/edmand46/arpack/generator" + "github.com/edmand46/arpack/parser" "fmt" "math" "os" diff --git a/generator/csharp.go b/generator/csharp.go index 398e16d..8a8623c 100644 --- a/generator/csharp.go +++ b/generator/csharp.go @@ -1,18 +1,15 @@ package generator import ( - "edmand46/arpack/parser" + "github.com/edmand46/arpack/parser" "fmt" "strings" ) -// GenerateCSharp генерирует C# unsafe код для списка сообщений. -// namespace — пространство имён (например, "Ragono.Messages"). func GenerateCSharp(messages []parser.Message, namespace string) ([]byte, error) { return GenerateCSharpSchema(parser.Schema{Messages: messages}, namespace) } -// GenerateCSharpSchema генерирует C# код для полной схемы, включая enum-ы. func GenerateCSharpSchema(schema parser.Schema, namespace string) ([]byte, error) { messages := schema.Messages var b strings.Builder @@ -34,11 +31,9 @@ func GenerateCSharpSchema(schema parser.Schema, namespace string) ([]byte, error enumNames[enum.Name] = struct{}{} } - wroteSection := false for _, enum := range schema.Enums { writeCSharpEnum(&b, enum) b.WriteString("\n") - wroteSection = true } for i, msg := range messages { @@ -47,8 +42,6 @@ func GenerateCSharpSchema(schema parser.Schema, namespace string) ([]byte, error } if i < len(messages)-1 { b.WriteString("\n") - } else if wroteSection { - // leave a single blank line between the last enum and the first struct only } } @@ -75,13 +68,11 @@ func writeCSharpMessage(b *strings.Builder, msg parser.Message, enumNames map[st b.WriteString(msg.Name) b.WriteString("\n {\n") - // Поля for _, f := range msg.Fields { fmt.Fprintf(b, " public %s %s;\n", csharpTypeName(f, enumNames), f.Name) } b.WriteString("\n") - // Serialize b.WriteString(" public int Serialize(byte* buffer)\n") b.WriteString(" {\n") b.WriteString(" byte* ptr = buffer;\n") @@ -97,7 +88,6 @@ func writeCSharpMessage(b *strings.Builder, msg parser.Message, enumNames map[st b.WriteString(" return (int)(ptr - buffer);\n") b.WriteString(" }\n\n") - // Deserialize fmt.Fprintf(b, " public static int Deserialize(byte* buffer, out %s msg)\n", msg.Name) b.WriteString(" {\n") b.WriteString(" byte* ptr = buffer;\n") @@ -135,8 +125,6 @@ func writeCSharpBoolGroupDeserialize(b *strings.Builder, recv string, bools []pa } } -// --- Serialize --- - func writeCSharpSerializeField(b *strings.Builder, f parser.Field, indent string, enumNames map[string]struct{}) error { switch f.Kind { case parser.KindPrimitive: @@ -220,7 +208,6 @@ func writeCSharpSerializePrimitive( case parser.KindUint64: fmt.Fprintf(b, "%s*(ulong*)ptr = %s; ptr += 8;\n", indent, valueExpr) case parser.KindString: - // UTF-8: uint16 byteCount + bytes lenVar := "_slen" + sanitizeVarName(access) fmt.Fprintf(b, "%sint %s = %s != null ? Encoding.UTF8.GetByteCount(%s) : 0;\n", indent, lenVar, valueExpr, valueExpr) @@ -250,8 +237,6 @@ func writeCSharpSerializeQuant(b *strings.Builder, access string, f parser.Field return nil } -// --- Deserialize --- - func writeCSharpDeserializeField( b *strings.Builder, recv string, diff --git a/generator/generator_test.go b/generator/generator_test.go index ec38f16..f3c4935 100644 --- a/generator/generator_test.go +++ b/generator/generator_test.go @@ -1,7 +1,7 @@ package generator import ( - "edmand46/arpack/parser" + "github.com/edmand46/arpack/parser" "os" "os/exec" "path/filepath" diff --git a/generator/go.go b/generator/go.go index cf595fc..7bb944e 100644 --- a/generator/go.go +++ b/generator/go.go @@ -1,19 +1,16 @@ package generator import ( - "edmand46/arpack/parser" + "github.com/edmand46/arpack/parser" "fmt" "go/format" "strings" ) -// GenerateGo генерирует Go-код сериализации для списка сообщений. -// pkgName — имя пакета в котором будет сгенерированный файл. func GenerateGo(messages []parser.Message, pkgName string) ([]byte, error) { return GenerateGoSchema(parser.Schema{Messages: messages}, pkgName) } -// GenerateGoSchema генерирует Go-код сериализации для полной схемы. func GenerateGoSchema(schema parser.Schema, pkgName string) ([]byte, error) { messages := schema.Messages var b strings.Builder @@ -46,7 +43,6 @@ func GenerateGoSchema(schema parser.Schema, pkgName string) ([]byte, error) { func writeGoMessage(b *strings.Builder, msg parser.Message) error { segs := segmentFields(msg.Fields) - // Marshal fmt.Fprintf(b, "func (m *%s) Marshal(buf []byte) []byte {\n", msg.Name) for i, seg := range segs { if seg.single != nil { @@ -59,7 +55,6 @@ func writeGoMessage(b *strings.Builder, msg parser.Message) error { } b.WriteString("\treturn buf\n}\n\n") - // Unmarshal — возвращает кол-во потреблённых байт fmt.Fprintf(b, "func (m *%s) Unmarshal(data []byte) (int, error) {\n", msg.Name) minSize := packedMinWireSize(msg.Fields) fmt.Fprintf(b, "\tif len(data) < %d {\n", minSize) @@ -99,8 +94,6 @@ func writeGoBoolGroupUnmarshal(b *strings.Builder, recv string, bools []parser.F } } -// --- Marshal --- - func writeGoMarshalField(b *strings.Builder, recv string, f parser.Field, indent string) error { access := recv + "." + f.Name switch f.Kind { @@ -197,8 +190,6 @@ func writeGoMarshalQuant(b *strings.Builder, access string, f parser.Field, inde return nil } -// --- Unmarshal --- - func writeGoUnmarshalField(b *strings.Builder, recv string, f parser.Field, indent string) error { access := recv + "." + f.Name switch f.Kind { @@ -361,7 +352,6 @@ func goUnmarshalValueExpr(expr string, f parser.Field) string { return f.NamedType + "(" + expr + ")" } -// sanitizeVarName превращает "m.Pos[_i]" в "_mPos_i". func sanitizeVarName(s string) string { var b strings.Builder for _, c := range s { diff --git a/generator/segment.go b/generator/segment.go index 0095e6d..4ca610c 100644 --- a/generator/segment.go +++ b/generator/segment.go @@ -1,20 +1,16 @@ package generator -import "edmand46/arpack/parser" +import "github.com/edmand46/arpack/parser" -// segment — либо группа bool (1–8 полей → 1 байт), либо одиночное поле. type segment struct { - bools []parser.Field // non-empty: bool-группа - single *parser.Field // non-nil: любое не-bool поле + bools []parser.Field + single *parser.Field } -// isBoolField возвращает true если поле — нативный bool (не массив, не слайс). func isBoolField(f parser.Field) bool { return f.Kind == parser.KindPrimitive && f.Primitive == parser.KindBool } -// segmentFields разбивает поля структуры на сегменты. -// Последовательные bool-поля группируются по 8 в один сегмент. func segmentFields(fields []parser.Field) []segment { var segs []segment i := 0 @@ -25,7 +21,6 @@ func segmentFields(fields []parser.Field) []segment { i++ continue } - // Собираем последовательные bool-поля группами по 8 for i < len(fields) && isBoolField(fields[i]) { var group []parser.Field for i < len(fields) && isBoolField(fields[i]) && len(group) < 8 { @@ -38,7 +33,6 @@ func segmentFields(fields []parser.Field) []segment { return segs } -// packedMinWireSize вычисляет минимальный размер буфера с учётом упаковки bool. func packedMinWireSize(fields []parser.Field) int { total := 0 for _, seg := range segmentFields(fields) { @@ -50,7 +44,6 @@ func packedMinWireSize(fields []parser.Field) int { total += s } } else { - // Группа bool → 1 байт total += 1 } } diff --git a/go.mod b/go.mod index 6b25261..b0fbf4e 100644 --- a/go.mod +++ b/go.mod @@ -1 +1 @@ -module edmand46/arpack +module github.com/edmand46/arpack diff --git a/parser/parser.go b/parser/parser.go index ee258fd..e0d52aa 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -12,7 +12,6 @@ import ( "strings" ) -// ParseFile парсит Go-файл и возвращает список сообщений. func ParseFile(path string) ([]Message, error) { schema, err := ParseSchemaFile(path) if err != nil { @@ -21,7 +20,6 @@ func ParseFile(path string) ([]Message, error) { return schema.Messages, nil } -// ParseSource парсит исходный код из строки (удобно для тестов). func ParseSource(src string) ([]Message, error) { schema, err := ParseSchemaSource(src) if err != nil { @@ -30,7 +28,6 @@ func ParseSource(src string) ([]Message, error) { return schema.Messages, nil } -// ParseSchemaFile парсит файл и возвращает полную схему: сообщения и enum-ы. func ParseSchemaFile(path string) (Schema, error) { fset := token.NewFileSet() @@ -42,7 +39,6 @@ func ParseSchemaFile(path string) (Schema, error) { return parseASTFile(fset, f) } -// ParseSchemaSource парсит исходник и возвращает полную схему. func ParseSchemaSource(src string) (Schema, error) { fset := token.NewFileSet() @@ -200,7 +196,7 @@ func parseStruct( for _, astField := range st.Fields.List { if len(astField.Names) == 0 { - continue // embedded field, пропускаем + continue } var rawTag string diff --git a/parser/types.go b/parser/types.go index d3b7e35..d40da68 100644 --- a/parser/types.go +++ b/parser/types.go @@ -1,6 +1,5 @@ package parser -// PrimitiveKind — конкретный примитивный тип. type PrimitiveKind int const ( @@ -18,24 +17,21 @@ const ( KindString ) -// FieldKind — категория поля. type FieldKind int const ( - KindPrimitive FieldKind = iota // float, int, uint, bool, string - KindNested // ссылка на другой Message - KindFixedArray // [N]T - KindSlice // []T + KindPrimitive FieldKind = iota + KindNested + KindFixedArray + KindSlice ) -// QuantInfo описывает квантизацию float → uint8/uint16. type QuantInfo struct { Min float64 Max float64 - Bits int // 8 или 16, default 16 + Bits int // 8 or 16, default 16 } -// MaxUint — максимальное целое значение для данного числа бит. func (q *QuantInfo) MaxUint() float64 { if q.Bits == 8 { return 255 @@ -43,31 +39,24 @@ func (q *QuantInfo) MaxUint() float64 { return 65535 } -// WireBytes — размер на проводе в байтах. func (q *QuantInfo) WireBytes() int { return q.Bits / 8 } -// Field — одно поле структуры-сообщения. type Field struct { Name string Kind FieldKind - // KindPrimitive Primitive PrimitiveKind NamedType string - Quant *QuantInfo // nil если нет квантизации + Quant *QuantInfo - // KindNested TypeName string - // KindFixedArray / KindSlice Elem *Field - FixedLen int // >0 только для KindFixedArray + FixedLen int } -// WireSize — размер в байтах на проводе. -// Возвращает -1 для полей переменного размера. func (f *Field) WireSize() int { switch f.Kind { case KindPrimitive: @@ -76,7 +65,7 @@ func (f *Field) WireSize() int { } return primitiveWireSize(f.Primitive) case KindNested: - return -1 // зависит от конкретного типа, узнаём через Message.MinWireSize + return -1 case KindFixedArray: elemSize := f.Elem.WireSize() if elemSize == -1 { @@ -84,7 +73,7 @@ func (f *Field) WireSize() int { } return f.FixedLen * elemSize case KindSlice: - return -1 // uint16 len + переменная часть + return -1 } return 0 } @@ -105,7 +94,6 @@ func primitiveWireSize(k PrimitiveKind) int { return 0 } -// IsIntegralPrimitive — подходит ли тип как базовый для enum. func IsIntegralPrimitive(k PrimitiveKind) bool { switch k { case KindInt8, KindInt16, KindInt32, KindInt64, KindUint8, KindUint16, KindUint32, KindUint64: @@ -114,7 +102,6 @@ func IsIntegralPrimitive(k PrimitiveKind) bool { return false } -// GoTypeName — имя типа в Go. func (f *Field) GoTypeName() string { switch f.Kind { case KindPrimitive: @@ -132,7 +119,6 @@ func (f *Field) GoTypeName() string { return "unknown" } -// CSharpTypeName — имя типа в C#. func (f *Field) CSharpTypeName() string { switch f.Kind { case KindPrimitive: @@ -180,7 +166,6 @@ func primitiveGoName(k PrimitiveKind) string { return "unknown" } -// GoPrimitiveTypeName — базовый примитивный тип поля в Go. func (f *Field) GoPrimitiveTypeName() string { return primitiveGoName(f.Primitive) } @@ -215,7 +200,6 @@ func primitiveCSharpName(k PrimitiveKind) string { return "unknown" } -// CSharpPrimitiveTypeName — базовый примитивный тип поля в C#. func (f *Field) CSharpPrimitiveTypeName() string { return primitiveCSharpName(f.Primitive) } @@ -234,42 +218,35 @@ func itoa(n int) string { return string(buf[pos:]) } -// Message — описание одной структуры-сообщения. type Message struct { PackageName string Name string Fields []Field } -// EnumValue — одно именованное значение enum. type EnumValue struct { Name string Value string } -// Enum — enum-подобный тип на основе именованного примитива. type Enum struct { Name string Primitive PrimitiveKind Values []EnumValue } -// Schema — полная модель входного файла. type Schema struct { PackageName string Messages []Message Enums []Enum } -// MinWireSize — минимальный гарантированный размер в байтах. -// Для вложенных типов считается только если размер известен заранее. -// Строки и слайсы считаются как 2 байта (length prefix). func (m *Message) MinWireSize() int { total := 0 for _, f := range m.Fields { s := f.WireSize() if s == -1 { - total += 2 // минимум: length prefix + total += 2 } else { total += s } @@ -277,7 +254,6 @@ func (m *Message) MinWireSize() int { return total } -// HasVariableFields — есть ли поля переменного размера. func (m *Message) HasVariableFields() bool { for _, f := range m.Fields { if f.WireSize() == -1 {