Skip to content

Commit

Permalink
feat: optional types (pointers)
Browse files Browse the repository at this point in the history
  • Loading branch information
sonirico committed Aug 13, 2022
1 parent 7c1d39b commit d80e257
Show file tree
Hide file tree
Showing 17 changed files with 321 additions and 268 deletions.
61 changes: 35 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type (
Grades map[string]uint8
EvenOrOdd bool
Pet Animal
Pointer *int
}
)

Expand Down Expand Up @@ -80,6 +81,13 @@ func main() {
animalBuilder,
),
).
Option(
parco.OptionField[Example, int](
parco.Int(binary.LittleEndian),
func(e *Example, value *int) { e.Pointer = value },
func(e *Example) *int { return e.Pointer },
),
).
ParCo()

ex := Example{
Expand All @@ -89,6 +97,7 @@ func main() {
Friends: []string{"@boliri", "@danirod", "@enrigles", "@f3r"},
EvenOrOdd: true,
Pet: Animal{Age: 3, Specie: "cat"},
Pointer: parco.Ptr(73),
}

output := bytes.NewBuffer(nil)
Expand All @@ -108,7 +117,6 @@ func main() {
panic("not equals")
}
}

```

### Single types
Expand All @@ -125,31 +133,32 @@ func main () {

### Supported fields

| Field | Status | Size |
|---------------|--------|------------------------------|
| byte || 1 |
| int8 || 1 |
| uint8 || 1 |
| int16 || 2 |
| uint16 || 2 |
| int32 || 4 |
| uint32 || 4 |
| int64 || 8 |
| uint64 || 8 |
| float32 | 👷🚧 | 4 |
| float64 | 👷🚧 | 8 |
| int || 4/8 |
| bool || 1 |
| small varchar || dyn (up to 255) |
| varchar || dyn (up to 65535) |
| text || dyn (up to max uint32 chars) |
| long text || dyn (up to max uint64 chars) |
| string || dyn |
| bytes (blob) || dyn |
| map || - |
| slice || - |
| struct || - |
| time.Time | 👷🚧 | ? |
| Field | Status | Size |
|-----------------------|--------|------------------------------|
| byte || 1 |
| int8 || 1 |
| uint8 || 1 |
| int16 || 2 |
| uint16 || 2 |
| int32 || 4 |
| uint32 || 4 |
| int64 || 8 |
| uint64 || 8 |
| float32 | 👷🚧 | 4 |
| float64 | 👷🚧 | 8 |
| int || 4/8 |
| bool || 1 |
| small varchar || dyn (up to 255) |
| varchar || dyn (up to 65535) |
| text || dyn (up to max uint32 chars) |
| long text || dyn (up to max uint64 chars) |
| string || dyn |
| bytes (blob) || dyn |
| map || - |
| slice || - |
| struct || - |
| time.Time | 👷🚧 | ? |
| optional[T] (pointer) || 1 + inner size |

For fully functional examples showing the whole API, refer to [Examples](https://github.com/sonirico/parco/tree/master/examples).

Expand Down
26 changes: 16 additions & 10 deletions builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,19 @@ type (
ModelBuilder[T any] struct {
fields []fieldBuilder[T]

parser *ModelParser[T]
parser *Parser[T]

compiler *ModelCompiler[T]
compiler *Compiler[T]
}
)

func Builder[T any](factory Factory[T]) ModelBuilder[T] {
return ModelBuilder[T]{
parser: ParserModel(factory),
compiler: CompilerModel[T](),
}
}

func (b ModelBuilder[T]) Compile(value T, w io.Writer) error {
return b.compiler.Compile(value, w)
}
Expand All @@ -28,14 +35,7 @@ func (b ModelBuilder[T]) Parse(r io.Reader) (T, error) {
return b.parser.Parse(r)
}

func Builder[T any](factory Factory[T]) ModelBuilder[T] {
return ModelBuilder[T]{
parser: ParserModel(factory),
compiler: CompilerModel[T](),
}
}

func (b ModelBuilder[T]) ParCo() (Parser[T], Compiler[T]) {
func (b ModelBuilder[T]) ParCo() (*Parser[T], *Compiler[T]) {
return b.parser, b.compiler
}

Expand Down Expand Up @@ -141,6 +141,12 @@ func (b ModelBuilder[T]) Int(order binary.ByteOrder, getter Getter[T, int], sett
return b
}

func (b ModelBuilder[T]) Option(field fieldBuilder[T]) ModelBuilder[T] {
b.parser.Option(field)
b.compiler.Option(field)
return b
}

func (b ModelBuilder[T]) Field(f fieldBuilder[T]) ModelBuilder[T] {
b.parser.Field(f)
b.compiler.Field(f)
Expand Down
56 changes: 28 additions & 28 deletions compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@ type (
Compile(item *T, writer io.Writer) error
}

Compiler[T any] interface {
Compile(T, io.Writer) error
}

ModelCompiler[T any] struct {
Compiler[T any] struct {
fields []fieldCompiler[T]
}
)

func (c ModelCompiler[T]) Compile(value T, w io.Writer) error {
func (c Compiler[T]) Compile(value T, w io.Writer) error {
for _, f := range c.fields {
if err := f.Compile(&value, w); err != nil {
return err
Expand All @@ -29,87 +25,91 @@ func (c ModelCompiler[T]) Compile(value T, w io.Writer) error {
return nil
}

func CompilerModel[T any]() *ModelCompiler[T] {
return &ModelCompiler[T]{}
func CompilerModel[T any]() *Compiler[T] {
return &Compiler[T]{}
}

func (c *ModelCompiler[T]) Struct(field fieldCompiler[T]) *ModelCompiler[T] {
func (c *Compiler[T]) Struct(field fieldCompiler[T]) *Compiler[T] {
return c.register(field)
}

func (c *ModelCompiler[T]) Array(field fieldCompiler[T]) *ModelCompiler[T] {
func (c *Compiler[T]) Array(field fieldCompiler[T]) *Compiler[T] {
return c.register(field)
}

func (c *ModelCompiler[T]) Map(field fieldCompiler[T]) *ModelCompiler[T] {
func (c *Compiler[T]) Map(field fieldCompiler[T]) *Compiler[T] {
return c.register(field)
}

func (c *ModelCompiler[T]) Varchar(getter Getter[T, string]) *ModelCompiler[T] {
func (c *Compiler[T]) Varchar(getter Getter[T, string]) *Compiler[T] {
return c.register(StringFieldGetter[T](Varchar(), getter))
}

func (c *ModelCompiler[T]) SmallVarchar(getter Getter[T, string]) *ModelCompiler[T] {
func (c *Compiler[T]) SmallVarchar(getter Getter[T, string]) *Compiler[T] {
return c.register(StringFieldGetter[T](SmallVarchar(), getter))
}

func (c *ModelCompiler[T]) Bool(getter Getter[T, bool]) *ModelCompiler[T] {
func (c *Compiler[T]) Bool(getter Getter[T, bool]) *Compiler[T] {
return c.register(BoolFieldGetter[T](Bool(), getter))
}

func (c *ModelCompiler[T]) Byte(getter Getter[T, byte]) *ModelCompiler[T] {
func (c *Compiler[T]) Byte(getter Getter[T, byte]) *Compiler[T] {
return c.register(UInt8FieldGetter[T](Byte(), getter))
}

func (c *ModelCompiler[T]) UInt8(getter Getter[T, uint8]) *ModelCompiler[T] {
func (c *Compiler[T]) UInt8(getter Getter[T, uint8]) *Compiler[T] {
return c.register(UInt8FieldGetter[T](UInt8(), getter))
}

func (c *ModelCompiler[T]) Int8(getter Getter[T, int8]) *ModelCompiler[T] {
func (c *Compiler[T]) Int8(getter Getter[T, int8]) *Compiler[T] {
return c.register(Int8FieldGetter[T](Int8(), getter))
}

func (c *ModelCompiler[T]) UInt16(order binary.ByteOrder, getter Getter[T, uint16]) *ModelCompiler[T] {
func (c *Compiler[T]) UInt16(order binary.ByteOrder, getter Getter[T, uint16]) *Compiler[T] {
return c.register(UInt16FieldGetter[T](UInt16(order), getter))
}

func (c *ModelCompiler[T]) Int16(order binary.ByteOrder, getter Getter[T, int16]) *ModelCompiler[T] {
func (c *Compiler[T]) Int16(order binary.ByteOrder, getter Getter[T, int16]) *Compiler[T] {
return c.register(Int16FieldGetter[T](Int16(order), getter))
}

func (c *ModelCompiler[T]) UInt16LE(getter Getter[T, uint16]) *ModelCompiler[T] {
func (c *Compiler[T]) UInt16LE(getter Getter[T, uint16]) *Compiler[T] {
return c.register(UInt16FieldGetter[T](UInt16LE(), getter))
}

func (c *ModelCompiler[T]) UInt16BE(getter Getter[T, uint16]) *ModelCompiler[T] {
func (c *Compiler[T]) UInt16BE(getter Getter[T, uint16]) *Compiler[T] {
return c.register(UInt16FieldGetter[T](UInt16BE(), getter))
}

func (c *ModelCompiler[T]) UInt32(order binary.ByteOrder, getter Getter[T, uint32]) *ModelCompiler[T] {
func (c *Compiler[T]) UInt32(order binary.ByteOrder, getter Getter[T, uint32]) *Compiler[T] {
return c.register(UInt32FieldGetter[T](UInt32(order), getter))
}

func (c *ModelCompiler[T]) Int32(order binary.ByteOrder, getter Getter[T, int32]) *ModelCompiler[T] {
func (c *Compiler[T]) Int32(order binary.ByteOrder, getter Getter[T, int32]) *Compiler[T] {
return c.register(Int32FieldGetter[T](Int32(order), getter))
}

func (c *ModelCompiler[T]) UInt64(order binary.ByteOrder, getter Getter[T, uint64]) *ModelCompiler[T] {
func (c *Compiler[T]) UInt64(order binary.ByteOrder, getter Getter[T, uint64]) *Compiler[T] {
return c.register(UInt64FieldGetter[T](UInt64(order), getter))
}

func (c *ModelCompiler[T]) Int64(order binary.ByteOrder, getter Getter[T, int64]) *ModelCompiler[T] {
func (c *Compiler[T]) Int64(order binary.ByteOrder, getter Getter[T, int64]) *Compiler[T] {
return c.register(Int64FieldGetter[T](Int64(order), getter))
}

func (c *ModelCompiler[T]) Int(order binary.ByteOrder, getter Getter[T, int]) *ModelCompiler[T] {
func (c *Compiler[T]) Int(order binary.ByteOrder, getter Getter[T, int]) *Compiler[T] {
return c.register(IntFieldGetter[T](Int(order), getter))
}

func (c *ModelCompiler[T]) Field(f fieldCompiler[T]) *ModelCompiler[T] {
func (c *Compiler[T]) Option(f fieldCompiler[T]) *Compiler[T] {
return c.register(f)
}

func (c *Compiler[T]) Field(f fieldCompiler[T]) *Compiler[T] {
return c.register(f)
}

func (c *ModelCompiler[T]) register(field fieldCompiler[T]) *ModelCompiler[T] {
func (c *Compiler[T]) register(field fieldCompiler[T]) *Compiler[T] {
c.fields = append(c.fields, field)
return c
}
4 changes: 2 additions & 2 deletions compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func fillMap(le int) map[string]uint8 {
return r
}

func newCompiler(arrLen int) *ModelCompiler[TestStruct] {
func newCompiler(arrLen int) *Compiler[TestStruct] {
var arrayHeadType IntType
if arrLen < 256 {
arrayHeadType = UInt8Header()
Expand Down Expand Up @@ -133,7 +133,7 @@ func parcoDiscardCompilerFactory(t TestStruct) compileFuncType {

func benchmarkCompile(b *testing.B, tests []TestStruct, compileFuncFactory compileFuncFactory) {
for _, test := range tests {
// creating compiler needs different field types as per different test payloads
// creating Compiler needs different field types as per different test payloads
compileFunc := compileFuncFactory(test)
b.Run(test.Name, func(b *testing.B) {
var totalBytes int
Expand Down
10 changes: 10 additions & 0 deletions examples/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"bytes"
"encoding/binary"
"log"
"reflect"

Expand All @@ -21,6 +22,7 @@ type (
Grades map[string]uint8
EvenOrOdd bool
Pet Animal
Pointer *int
}
)

Expand Down Expand Up @@ -74,6 +76,13 @@ func main() {
animalBuilder,
),
).
Option(
parco.OptionField[Example, int](
parco.Int(binary.LittleEndian),
func(e *Example, value *int) { e.Pointer = value },
func(e *Example) *int { return e.Pointer },
),
).
ParCo()

ex := Example{
Expand All @@ -83,6 +92,7 @@ func main() {
Friends: []string{"@boliri", "@danirod", "@enrigles", "@f3r"},
EvenOrOdd: true,
Pet: Animal{Age: 3, Specie: "cat"},
Pointer: parco.Ptr(73),
}

output := bytes.NewBuffer(nil)
Expand Down
9 changes: 9 additions & 0 deletions examples/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"bytes"
"encoding/binary"
"log"

"github.com/sonirico/parco"
Expand All @@ -20,6 +21,7 @@ type (
Grades map[string]uint8
EvenOrOdd bool
Pet Animal
Pointer *int
}
)

Expand Down Expand Up @@ -68,6 +70,12 @@ func main() {
},
animalCompiler,
),
).
Option(
parco.OptionFieldGetter[Example, int](
parco.Int(binary.LittleEndian),
func(e *Example) *int { return e.Pointer },
),
)

ex := Example{
Expand All @@ -83,6 +91,7 @@ func main() {
Age: 3,
Specie: "cat",
},
Pointer: parco.Ptr(1),
}

output := bytes.NewBuffer(nil)
Expand Down
Loading

0 comments on commit d80e257

Please sign in to comment.