From 7c1d39b32d5b1f18b0f8e30c030b51134bbb02ad Mon Sep 17 00:00:00 2001 From: Marcos Date: Sat, 13 Aug 2022 21:53:58 +0200 Subject: [PATCH] feat: integer types --- README.md | 47 ++++++++++- builder.go | 42 ++++++++++ compiler.go | 32 ++++++++ field_fixed.go | 189 +++++++++++++++++++++++++++++++++++++++++++ field_var.go | 16 +--- parser.go | 204 +++++++++++++++++++++++++++++------------------ parser_model.go | 101 ----------------------- parser_result.go | 86 -------------------- type_int.go | 155 +++++++++++++++++++++++++++++++++++ type_uint16.go | 62 ++++++++++++-- type_uint32.go | 122 ++++++++++++++++++++++++++++ type_uint64.go | 122 ++++++++++++++++++++++++++++ type_uint8.go | 53 ++++++++++++ type_varchar.go | 17 ++++ utils_helpers.go | 9 +++ utils_types.go | 12 +-- 16 files changed, 971 insertions(+), 298 deletions(-) delete mode 100644 parser_model.go delete mode 100644 parser_result.go create mode 100644 type_int.go create mode 100644 type_uint32.go create mode 100644 type_uint64.go create mode 100644 utils_helpers.go diff --git a/README.md b/README.md index 9dcfb23..97cac3f 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ addition to have an appositive effect on performance. ## Usage +### Parser & compiler + ```go type ( Animal struct { @@ -109,6 +111,46 @@ func main() { ``` +### Single types + +```go +func main () { + intType := parco.Int(binary.LittleEndian) + buf := bytes.NewBuffer(nil) + _ = intType.Compile(math.MaxInt, buf) + n, _ := intType.Parse(buf) + log.Println(n == math.MaxInt) +} +``` + +### 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 | 👷🚧 | ? | + For fully functional examples showing the whole API, refer to [Examples](https://github.com/sonirico/parco/tree/master/examples). @@ -153,7 +195,10 @@ Msgpack_Compile/large_size-12 6274 191314 ns/op ## TODO -- Support for all primitive types: boolean, nil... +- Support for all primitive types: + - Float32/64 + - Optional / Pointer + - Extend interface to include version - Static code generation - Replace `encoding/binary` usage by faster implementations (`WriteByte`) diff --git a/builder.go b/builder.go index f250937..488c3a2 100644 --- a/builder.go +++ b/builder.go @@ -81,6 +81,18 @@ func (b ModelBuilder[T]) UInt8(getter Getter[T, uint8], setter Setter[T, uint8]) return b } +func (b ModelBuilder[T]) Byte(getter Getter[T, byte], setter Setter[T, byte]) ModelBuilder[T] { + b.parser.Byte(setter) + b.compiler.Byte(getter) + return b +} + +func (b ModelBuilder[T]) Int8(getter Getter[T, int8], setter Setter[T, int8]) ModelBuilder[T] { + b.parser.Int8(setter) + b.compiler.Int8(getter) + return b +} + func (b ModelBuilder[T]) UInt16(order binary.ByteOrder, getter Getter[T, uint16], setter Setter[T, uint16]) ModelBuilder[T] { b.parser.UInt16(order, setter) b.compiler.UInt16(order, getter) @@ -99,6 +111,36 @@ func (b ModelBuilder[T]) UInt16BE(getter Getter[T, uint16], setter Setter[T, uin return b } +func (b ModelBuilder[T]) Int32(order binary.ByteOrder, getter Getter[T, int32], setter Setter[T, int32]) ModelBuilder[T] { + b.parser.Int32(order, setter) + b.compiler.Int32(order, getter) + return b +} + +func (b ModelBuilder[T]) UInt32(order binary.ByteOrder, getter Getter[T, uint32], setter Setter[T, uint32]) ModelBuilder[T] { + b.parser.UInt32(order, setter) + b.compiler.UInt32(order, getter) + return b +} + +func (b ModelBuilder[T]) Int64(order binary.ByteOrder, getter Getter[T, int64], setter Setter[T, int64]) ModelBuilder[T] { + b.parser.Int64(order, setter) + b.compiler.Int64(order, getter) + return b +} + +func (b ModelBuilder[T]) UInt64(order binary.ByteOrder, getter Getter[T, uint64], setter Setter[T, uint64]) ModelBuilder[T] { + b.parser.UInt64(order, setter) + b.compiler.UInt64(order, getter) + return b +} + +func (b ModelBuilder[T]) Int(order binary.ByteOrder, getter Getter[T, int], setter Setter[T, int]) ModelBuilder[T] { + b.parser.Int(order, setter) + b.compiler.Int(order, getter) + return b +} + func (b ModelBuilder[T]) Field(f fieldBuilder[T]) ModelBuilder[T] { b.parser.Field(f) b.compiler.Field(f) diff --git a/compiler.go b/compiler.go index 644fe2b..8d2685b 100644 --- a/compiler.go +++ b/compiler.go @@ -57,14 +57,26 @@ func (c *ModelCompiler[T]) Bool(getter Getter[T, bool]) *ModelCompiler[T] { return c.register(BoolFieldGetter[T](Bool(), getter)) } +func (c *ModelCompiler[T]) Byte(getter Getter[T, byte]) *ModelCompiler[T] { + return c.register(UInt8FieldGetter[T](Byte(), getter)) +} + func (c *ModelCompiler[T]) UInt8(getter Getter[T, uint8]) *ModelCompiler[T] { return c.register(UInt8FieldGetter[T](UInt8(), getter)) } +func (c *ModelCompiler[T]) Int8(getter Getter[T, int8]) *ModelCompiler[T] { + return c.register(Int8FieldGetter[T](Int8(), getter)) +} + func (c *ModelCompiler[T]) UInt16(order binary.ByteOrder, getter Getter[T, uint16]) *ModelCompiler[T] { return c.register(UInt16FieldGetter[T](UInt16(order), getter)) } +func (c *ModelCompiler[T]) Int16(order binary.ByteOrder, getter Getter[T, int16]) *ModelCompiler[T] { + return c.register(Int16FieldGetter[T](Int16(order), getter)) +} + func (c *ModelCompiler[T]) UInt16LE(getter Getter[T, uint16]) *ModelCompiler[T] { return c.register(UInt16FieldGetter[T](UInt16LE(), getter)) } @@ -73,6 +85,26 @@ func (c *ModelCompiler[T]) UInt16BE(getter Getter[T, uint16]) *ModelCompiler[T] return c.register(UInt16FieldGetter[T](UInt16BE(), getter)) } +func (c *ModelCompiler[T]) UInt32(order binary.ByteOrder, getter Getter[T, uint32]) *ModelCompiler[T] { + return c.register(UInt32FieldGetter[T](UInt32(order), getter)) +} + +func (c *ModelCompiler[T]) Int32(order binary.ByteOrder, getter Getter[T, int32]) *ModelCompiler[T] { + return c.register(Int32FieldGetter[T](Int32(order), getter)) +} + +func (c *ModelCompiler[T]) UInt64(order binary.ByteOrder, getter Getter[T, uint64]) *ModelCompiler[T] { + return c.register(UInt64FieldGetter[T](UInt64(order), getter)) +} + +func (c *ModelCompiler[T]) Int64(order binary.ByteOrder, getter Getter[T, int64]) *ModelCompiler[T] { + return c.register(Int64FieldGetter[T](Int64(order), getter)) +} + +func (c *ModelCompiler[T]) Int(order binary.ByteOrder, getter Getter[T, int]) *ModelCompiler[T] { + return c.register(IntFieldGetter[T](Int(order), getter)) +} + func (c *ModelCompiler[T]) Field(f fieldCompiler[T]) *ModelCompiler[T] { return c.register(f) } diff --git a/field_fixed.go b/field_fixed.go index 4884cf0..4e90ace 100644 --- a/field_fixed.go +++ b/field_fixed.go @@ -83,6 +83,33 @@ func UInt8FieldSetter[T any]( return UInt8Field[T](tp, nil, setter) } +func Int8Field[T any]( + tp Type[int8], + getter Getter[T, int8], + setter Setter[T, int8], +) Field[T, int8] { + return FixedField[T, int8]{ + Type: tp, + Setter: setter, + Getter: getter, + Pooler: SinglePool, + } +} + +func Int8FieldGetter[T any]( + tp Type[int8], + getter Getter[T, int8], +) Field[T, int8] { + return Int8Field[T](tp, getter, nil) +} + +func Int8FieldSetter[T any]( + tp Type[int8], + setter Setter[T, int8], +) Field[T, int8] { + return Int8Field[T](tp, nil, setter) +} + func UInt16Field[T any]( tp Type[uint16], getter Getter[T, uint16], @@ -110,6 +137,168 @@ func UInt16FieldSetter[T any]( return UInt16Field[T](tp, nil, setter) } +func Int16Field[T any]( + tp Type[int16], + getter Getter[T, int16], + setter Setter[T, int16], +) Field[T, int16] { + return FixedField[T, int16]{ + Type: tp, + Setter: setter, + Getter: getter, + Pooler: SinglePool, + } +} + +func Int16FieldGetter[T any]( + tp Type[int16], + getter Getter[T, int16], +) Field[T, int16] { + return Int16Field[T](tp, getter, nil) +} + +func Int16FieldSetter[T any]( + tp Type[int16], + setter Setter[T, int16], +) Field[T, int16] { + return Int16Field[T](tp, nil, setter) +} + +func UInt32Field[T any]( + tp Type[uint32], + getter Getter[T, uint32], + setter Setter[T, uint32], +) Field[T, uint32] { + return FixedField[T, uint32]{ + Type: tp, + Setter: setter, + Getter: getter, + Pooler: SinglePool, + } +} + +func UInt32FieldGetter[T any]( + tp Type[uint32], + getter Getter[T, uint32], +) Field[T, uint32] { + return UInt32Field[T](tp, getter, nil) +} + +func UInt32FieldSetter[T any]( + tp Type[uint32], + setter Setter[T, uint32], +) Field[T, uint32] { + return UInt32Field[T](tp, nil, setter) +} + +func Int32Field[T any]( + tp Type[int32], + getter Getter[T, int32], + setter Setter[T, int32], +) Field[T, int32] { + return FixedField[T, int32]{ + Type: tp, + Setter: setter, + Getter: getter, + Pooler: SinglePool, + } +} + +func Int32FieldGetter[T any]( + tp Type[int32], + getter Getter[T, int32], +) Field[T, int32] { + return Int32Field[T](tp, getter, nil) +} + +func Int32FieldSetter[T any]( + tp Type[int32], + setter Setter[T, int32], +) Field[T, int32] { + return Int32Field[T](tp, nil, setter) +} + +func UInt64Field[T any]( + tp Type[uint64], + getter Getter[T, uint64], + setter Setter[T, uint64], +) Field[T, uint64] { + return FixedField[T, uint64]{ + Type: tp, + Setter: setter, + Getter: getter, + Pooler: SinglePool, + } +} + +func UInt64FieldGetter[T any]( + tp Type[uint64], + getter Getter[T, uint64], +) Field[T, uint64] { + return UInt64Field[T](tp, getter, nil) +} + +func UInt64FieldSetter[T any]( + tp Type[uint64], + setter Setter[T, uint64], +) Field[T, uint64] { + return UInt64Field[T](tp, nil, setter) +} + +func Int64Field[T any]( + tp Type[int64], + getter Getter[T, int64], + setter Setter[T, int64], +) Field[T, int64] { + return FixedField[T, int64]{ + Type: tp, + Setter: setter, + Getter: getter, + Pooler: SinglePool, + } +} + +func Int64FieldGetter[T any]( + tp Type[int64], + getter Getter[T, int64], +) Field[T, int64] { + return Int64Field[T](tp, getter, nil) +} + +func Int64FieldSetter[T any]( + tp Type[int64], + setter Setter[T, int64], +) Field[T, int64] { + return Int64Field[T](tp, nil, setter) +} + +func IntField[T any]( + tp Type[int], + getter Getter[T, int], + setter Setter[T, int], +) Field[T, int] { + return FixedField[T, int]{ + Type: tp, + Setter: setter, + Getter: getter, + Pooler: SinglePool, + } +} + +func IntFieldGetter[T any]( + tp Type[int], + getter Getter[T, int], +) Field[T, int] { + return IntField[T](tp, getter, nil) +} + +func IntFieldSetter[T any]( + tp Type[int], + setter Setter[T, int], +) Field[T, int] { + return IntField[T](tp, nil, setter) +} + func SkipField[T any]( tp Type[any], ) Field[T, any] { diff --git a/field_var.go b/field_var.go index 2a3e706..28bce8f 100644 --- a/field_var.go +++ b/field_var.go @@ -7,8 +7,8 @@ func StringField[T any]( ) Field[T, string] { return FixedField[T, string]{ Type: tp, - Setter: (setter), - Getter: (getter), + Setter: setter, + Getter: getter, Pooler: SinglePool, } } @@ -26,15 +26,3 @@ func StringFieldSetter[T any]( ) Field[T, string] { return StringField[T](tp, nil, setter) } - -func stringGetter[T any](getter Getter[T, string]) Getter[T, String] { - return func(item *T) String { - return String(getter(item)) - } -} - -func stringSetter[T any](setter Setter[T, string]) Setter[T, String] { - return func(item *T, s String) { - setter(item, s.Unwrap()) - } -} diff --git a/parser.go b/parser.go index 5cc95fc..02aa353 100644 --- a/parser.go +++ b/parser.go @@ -1,79 +1,129 @@ package parco -// -//type ParserResult struct { -// fields []field[any] -//} -// -//func NewParserResult() ParserResult { -// return ParserResult{} -//} -// -//func (p ParserResult) ParseBytes(data []byte) (Result, error) { -// buf := NewBufferCursor(data, 0) -// -// return p.parse(&buf) -//} -// -//func (p ParserResult) Parse(r io.Reader) (Result, error) { -// return p.parse(r) -//} -// -//func (p ParserResult) parse(r io.Reader) (res Result, e error) { -// s := newResult() -// -// for _, f := range p.fields { -// // TODO: Parse lazy -// value, err := f.Type.Parse(r) -// -// if err != nil { -// return s, nil -// } -// -// if _, ok := f.Type.(SkipType[any]); !ok { -// s.data[f.Name] = structItem[any]{ -// field: f, -// value: value, -// } -// } -// } -// return s, nil -//} -// -//func (c ParserResult) SmallVarchar(name string) ParserResult { -// return c.register(name, SmallVarchar[any](nil)) -//} -// -//func (c ParserResult) UInt8(name string) ParserResult { -// return c.register(name, UInt8C[any](nil)) -//} -// -//func (c ParserResult) UInt16(name string, order binary.ByteOrder) ParserResult { -// return c.register(name, UInt16[any](order, nil)) -//} -// -//func (c ParserResult) UInt16BE(name string) ParserResult { -// return c.register(name, UInt16[any](binary.BigEndian, nil)) -//} -// -//func (c ParserResult) UInt16LE(name string) ParserResult { -// return c.register(name, UInt16[any](binary.LittleEndian, nil)) -//} -// -//func (c ParserResult) Array(name string, inner Type[any]) ParserResult { -// return c.register(name, inner) -//} -// -//func (c ParserResult) Field(name string, tp Type[any]) ParserResult { -// return c.register(name, tp) -//} -// -//func (c ParserResult) Skip(pad int) ParserResult { -// return c.register("", SkipType[any]{pad: pad}) -//} -// -//func (c ParserResult) register(name string, tp Type[any]) ParserResult { -// c.fields = append(c.fields, field[any]{Name: name, Type: tp}) -// return c -//} -// +import ( + "encoding/binary" + "io" +) + +type ( + fieldParser[T any] interface { + Parse(item *T, reader io.Reader) error + } + + Parser[T any] interface { + Parse(io.Reader) (T, error) + ParseBytes([]byte) (T, error) + } + + ModelParser[T any] struct { + fields []fieldParser[T] + factory Factory[T] + } +) + +func ParserModel[T any](factory Factory[T]) *ModelParser[T] { + return &ModelParser[T]{factory: factory} +} + +func (p *ModelParser[T]) ParseBytes(data []byte) (T, error) { + buf := NewBufferCursor(data, 0) + + return p.parse(&buf) +} + +func (p *ModelParser[T]) Parse(r io.Reader) (T, error) { + return p.parse(r) +} + +func (p *ModelParser[T]) parse(r io.Reader) (T, error) { + model := p.factory.Get() + + for _, f := range p.fields { + if err := f.Parse(&model, r); err != nil { + return model, nil + } + } + + return model, nil +} + +func (p *ModelParser[T]) Struct(field fieldParser[T]) *ModelParser[T] { + return p.register(field) +} + +func (p *ModelParser[T]) Array(field fieldParser[T]) *ModelParser[T] { + return p.register(field) +} + +func (p *ModelParser[T]) Map(field fieldParser[T]) *ModelParser[T] { + return p.register(field) +} + +func (p *ModelParser[T]) SmallVarchar(setter Setter[T, string]) *ModelParser[T] { + return p.register(StringFieldSetter[T](SmallVarchar(), setter)) +} + +func (p *ModelParser[T]) Varchar(setter Setter[T, string]) *ModelParser[T] { + return p.register(StringFieldSetter[T](Varchar(), setter)) +} + +func (c *ModelParser[T]) Bool(setter Setter[T, bool]) *ModelParser[T] { + return c.register(BoolFieldSetter[T](Bool(), setter)) +} + +func (p *ModelParser[T]) UInt8(setter Setter[T, uint8]) *ModelParser[T] { + return p.register(UInt8FieldSetter[T](UInt8(), setter)) +} + +func (p *ModelParser[T]) Int8(setter Setter[T, int8]) *ModelParser[T] { + return p.register(Int8FieldSetter[T](Int8(), setter)) +} + +func (p *ModelParser[T]) Byte(setter Setter[T, byte]) *ModelParser[T] { + return p.register(UInt8FieldSetter[T](Byte(), setter)) +} + +func (p *ModelParser[T]) UInt16(order binary.ByteOrder, setter Setter[T, uint16]) *ModelParser[T] { + return p.register(UInt16FieldSetter[T](UInt16(order), setter)) +} + +func (p *ModelParser[T]) UInt16LE(setter Setter[T, uint16]) *ModelParser[T] { + return p.register(UInt16FieldSetter[T](UInt16LE(), setter)) +} + +func (p *ModelParser[T]) UInt16BE(setter Setter[T, uint16]) *ModelParser[T] { + return p.register(UInt16FieldSetter[T](UInt16BE(), setter)) +} + +func (p *ModelParser[T]) UInt32(order binary.ByteOrder, setter Setter[T, uint32]) *ModelParser[T] { + return p.register(UInt32FieldSetter[T](UInt32(order), setter)) +} + +func (p *ModelParser[T]) Int32(order binary.ByteOrder, setter Setter[T, int32]) *ModelParser[T] { + return p.register(Int32FieldSetter[T](Int32(order), setter)) +} + +func (p *ModelParser[T]) UInt64(order binary.ByteOrder, setter Setter[T, uint64]) *ModelParser[T] { + return p.register(UInt64FieldSetter[T](UInt64(order), setter)) +} + +func (p *ModelParser[T]) Int64(order binary.ByteOrder, setter Setter[T, int64]) *ModelParser[T] { + return p.register(Int64FieldSetter[T](Int64(order), setter)) +} + +func (p *ModelParser[T]) Int(order binary.ByteOrder, setter Setter[T, int]) *ModelParser[T] { + return p.register(IntFieldSetter[T](Int(order), setter)) +} + +func (p *ModelParser[T]) Field(f fieldParser[T]) *ModelParser[T] { + return p.register(f) +} + +func (p *ModelParser[T]) Skip(pad int) *ModelParser[T] { + return p.register(DefaultSkipField[T](pad)) +} + +func (p *ModelParser[T]) register(f fieldParser[T]) *ModelParser[T] { + p.fields = append(p.fields, f) + return p +} diff --git a/parser_model.go b/parser_model.go deleted file mode 100644 index 0eea8fc..0000000 --- a/parser_model.go +++ /dev/null @@ -1,101 +0,0 @@ -package parco - -import ( - "encoding/binary" - "io" -) - -type ( - fieldParser[T any] interface { - Parse(item *T, reader io.Reader) error - } - - Parser[T any] interface { - Parse(io.Reader) (T, error) - ParseBytes([]byte) (T, error) - } - - ModelParser[T any] struct { - fields []fieldParser[T] - factory Factory[T] - } -) - -func ParserModel[T any](factory Factory[T]) *ModelParser[T] { - return &ModelParser[T]{factory: factory} -} - -func (p *ModelParser[T]) ParseBytes(data []byte) (T, error) { - buf := NewBufferCursor(data, 0) - - return p.parse(&buf) -} - -func (p *ModelParser[T]) Parse(r io.Reader) (T, error) { - return p.parse(r) -} - -func (p *ModelParser[T]) parse(r io.Reader) (T, error) { - model := p.factory.Get() - - for _, f := range p.fields { - if err := f.Parse(&model, r); err != nil { - return model, nil - } - } - - return model, nil -} - -func (p *ModelParser[T]) Struct(field fieldParser[T]) *ModelParser[T] { - return p.register(field) -} - -func (p *ModelParser[T]) Array(field fieldParser[T]) *ModelParser[T] { - return p.register(field) -} - -func (p *ModelParser[T]) Map(field fieldParser[T]) *ModelParser[T] { - return p.register(field) -} - -func (p *ModelParser[T]) SmallVarchar(setter Setter[T, string]) *ModelParser[T] { - return p.register(StringFieldSetter[T](SmallVarchar(), setter)) -} - -func (p *ModelParser[T]) Varchar(setter Setter[T, string]) *ModelParser[T] { - return p.register(StringFieldSetter[T](Varchar(), setter)) -} - -func (c *ModelParser[T]) Bool(setter Setter[T, bool]) *ModelParser[T] { - return c.register(BoolFieldSetter[T](Bool(), setter)) -} - -func (p *ModelParser[T]) UInt8(setter Setter[T, uint8]) *ModelParser[T] { - return p.register(UInt8FieldSetter[T](UInt8(), setter)) -} - -func (p *ModelParser[T]) UInt16(order binary.ByteOrder, setter Setter[T, uint16]) *ModelParser[T] { - return p.register(UInt16FieldSetter[T](UInt16(order), setter)) -} - -func (p *ModelParser[T]) UInt16LE(setter Setter[T, uint16]) *ModelParser[T] { - return p.register(UInt16FieldSetter[T](UInt16LE(), setter)) -} - -func (p *ModelParser[T]) UInt16BE(setter Setter[T, uint16]) *ModelParser[T] { - return p.register(UInt16FieldSetter[T](UInt16BE(), setter)) -} - -func (p *ModelParser[T]) Field(f fieldParser[T]) *ModelParser[T] { - return p.register(f) -} - -func (p *ModelParser[T]) Skip(pad int) *ModelParser[T] { - return p.register(DefaultSkipField[T](pad)) -} - -func (p *ModelParser[T]) register(f fieldParser[T]) *ModelParser[T] { - p.fields = append(p.fields, f) - return p -} diff --git a/parser_result.go b/parser_result.go deleted file mode 100644 index 04acac4..0000000 --- a/parser_result.go +++ /dev/null @@ -1,86 +0,0 @@ -package parco - -//import ( -// "reflect" -//) -// -//type Result struct { -// data map[string]structItem[any] -//} -// -//func (r *Result) getItem(k string) (item structItem[any], err error) { -// item, ok := r.data[k] -// if !ok { -// return item, NewErrFieldNotFoundError(k) -// } -// -// return item, nil -//} -// -//func (r *Result) get(k string) (data any, err error) { -// item, ok := r.data[k] -// if !ok { -// return nil, NewErrFieldNotFoundError(k) -// } -// -// return item.value, nil -//} -// -//func (r *Result) Get(k string) (data []byte, err error) { -// item, ok := r.data[k] -// if !ok { -// return nil, NewErrFieldNotFoundError(k) -// } -// -// return item.data, nil -// -//} -// -//func (r *Result) GetString(k string) (string, error) { -// value, err := r.get(k) -// if err != nil { -// return "", err -// } -// -// str, ok := value.(string) -// if !ok { -// return "", NewErrTypeAssertionError("string", reflect.TypeOf(value).String()) -// } -// return str, nil -//} -// -//func (r *Result) GetUInt8(k string) (uint8, error) { -// bts, err := r.get(k) -// if err != nil { -// return 0, err -// } -// -// str, ok := bts.(uint8) -// if !ok { -// return 0, NewErrTypeAssertionError("uint8", reflect.TypeOf(bts).String()) -// } -// return str, nil -//} -// -//func (r *Result) GetArray(k string) (arr ArrayValue[any], err error) { -// item, err := r.getItem(k) -// if err != nil { -// return -// } -// -// var ok bool -// arr, ok = item.value.(ArrayValue[any]) -// if !ok { -// err = NewErrTypeAssertionError("array", reflect.TypeOf(item.value).String()) -// return -// } -// return arr, nil -// -//} -// -//func newResult() Result { -// return Result{ -// data: make(map[string]structItem[any]), -// } -//} -// diff --git a/type_int.go b/type_int.go new file mode 100644 index 0000000..a5f29ff --- /dev/null +++ b/type_int.go @@ -0,0 +1,155 @@ +package parco + +import ( + "encoding/binary" + "math" +) + +const ( + is64BitsArch = (^uint(0) >> 63) == 1 +) + +var ( + uintBitSize = If[int](is64BitsArch, 8, 4) +) + +func CompileUInt(u uint, box []byte, order binary.ByteOrder) (err error) { + if is64BitsArch { + return CompileUInt64(uint64(u), box, order) + } + return CompileUInt32(uint32(u), box, order) +} + +func ParseUInt(data []byte, order binary.ByteOrder) (uint, error) { + if is64BitsArch { + u64, err := ParseUInt64(data, order) + if err != nil { + return 0, err + } + + return uint(u64), err + } + + u32, err := ParseUInt32(data, order) + if err != nil { + return 0, err + } + + return uint(u32), err +} + +func UInt(order binary.ByteOrder) Type[uint] { + return NewFixedType[uint]( + uintBitSize, + func(data []byte) (uint, error) { + return ParseUInt(data, order) + }, + func(value uint, box []byte) (err error) { + return CompileUInt(value, box, order) + }, + ) +} + +func UIntLE() Type[uint] { + return UInt(binary.LittleEndian) +} + +func UIntBE() Type[uint] { + return UInt(binary.BigEndian) +} + +func UIntHeader(order binary.ByteOrder) Type[int] { + return NewFixedType[int]( + uintBitSize, + func(data []byte) (int, error) { + n, err := ParseUInt(data, order) + m := int(n) + return m, err + }, + func(value int, box []byte) (err error) { + if value < 0 { + return ErrOverflow + } + + return CompileUInt(uint(value), box, order) + }, + ) +} + +func UIntLEHeader() Type[int] { + return UIntHeader(binary.LittleEndian) +} + +func UIntBEHeader() Type[int] { + return UIntHeader(binary.BigEndian) +} + +func CompileInt(i int, box []byte, order binary.ByteOrder) (err error) { + if is64BitsArch { + return CompileInt64(int64(i), box, order) + } + return CompileInt32(int32(i), box, order) +} + +func ParseInt(data []byte, order binary.ByteOrder) (int, error) { + if is64BitsArch { + i64, err := ParseInt64(data, order) + if err != nil { + return 0, err + } + + return int(i64), err + } + + i32, err := ParseInt32(data, order) + if err != nil { + return 0, err + } + + return int(i32), err +} + +func Int(order binary.ByteOrder) Type[int] { + return NewFixedType[int]( + uintBitSize, + func(data []byte) (int, error) { + return ParseInt(data, order) + }, + func(value int, box []byte) (err error) { + return CompileInt(value, box, order) + }, + ) +} + +func IntLE() Type[int] { + return Int(binary.LittleEndian) +} + +func IntBE() Type[int] { + return Int(binary.BigEndian) +} + +func IntHeader(order binary.ByteOrder) Type[int] { + return NewFixedType[int]( + uintBitSize, + func(data []byte) (int, error) { + n, err := ParseInt(data, order) + m := int(n) + return m, err + }, + func(value int, box []byte) (err error) { + if value > math.MaxInt || value < math.MinInt { + return ErrOverflow + } + return CompileInt(value, box, order) + }, + ) +} + +func IntLEHeader() Type[int] { + return IntHeader(binary.LittleEndian) +} + +func IntBEHeader() Type[int] { + return IntHeader(binary.BigEndian) +} diff --git a/type_uint16.go b/type_uint16.go index fa7f8ec..2ac564c 100644 --- a/type_uint16.go +++ b/type_uint16.go @@ -2,6 +2,7 @@ package parco import ( "encoding/binary" + "math" ) func ParseUInt16(data []byte, order binary.ByteOrder) (uint16, error) { @@ -50,7 +51,7 @@ func CompileUInt16(u16 uint16, box []byte, order binary.ByteOrder) (err error) { func UInt16(order binary.ByteOrder) Type[uint16] { return NewFixedType[uint16]( - (2), + 2, ParseUInt16Factory(order), CompileUInt16Factory(order), ) @@ -66,7 +67,7 @@ func UInt16BE() Type[uint16] { func UInt16Header(order binary.ByteOrder) Type[int] { return NewFixedType[int]( - (2), + 2, ParseUInt16HeaderFactory(order), CompileUInt16HeaderFactory(order), ) @@ -80,14 +81,59 @@ func UInt16HeaderBE() Type[int] { return UInt16Header(binary.BigEndian) } -func UInt16Factory(order binary.ByteOrder) Type[uint16] { - return UInt16(order) +// Int16 + +func ParseInt16(data []byte, order binary.ByteOrder) (int16, error) { + if len(data) < 2 { + return 0, NewErrUnSufficientBytesError(2, 0) + } + return int16(order.Uint16(data)), nil } -func UInt16LEFactory() Type[uint16] { - return UInt16(binary.LittleEndian) +func CompileInt16(i16 int16, box []byte, order binary.ByteOrder) (err error) { + return CompileUInt16(uint16(i16), box, order) } -func UInt16BEFactory() Type[uint16] { - return UInt16(binary.BigEndian) +func Int16(order binary.ByteOrder) Type[int16] { + return NewFixedType[int16]( + 2, + func(data []byte) (int16, error) { + return ParseInt16(data, order) + }, + func(i16 int16, box []byte) (err error) { + return CompileInt16(i16, box, order) + }, + ) +} + +func Int16LE() Type[int16] { + return Int16(binary.LittleEndian) +} + +func Int16BE() Type[int16] { + return Int16(binary.BigEndian) +} + +func Int16Header(order binary.ByteOrder) Type[int] { + return NewFixedType[int]( + 2, + func(data []byte) (int, error) { + n, err := ParseInt16(data, order) + return int(n), err + }, + func(i int, box []byte) (err error) { + if i > math.MaxInt16 || i < math.MinInt16 { + return ErrOverflow + } + return CompileInt16(int16(i), box, order) + }, + ) +} + +func Int16LEHeader() Type[int] { + return Int16Header(binary.LittleEndian) +} + +func Int16BEHeader() Type[int] { + return Int16Header(binary.BigEndian) } diff --git a/type_uint32.go b/type_uint32.go new file mode 100644 index 0000000..4c7bb40 --- /dev/null +++ b/type_uint32.go @@ -0,0 +1,122 @@ +package parco + +import ( + "encoding/binary" + "math" +) + +func CompileUInt32(u32 uint32, box []byte, order binary.ByteOrder) (err error) { + order.PutUint32(box, u32) + return +} + +func ParseUInt32(data []byte, order binary.ByteOrder) (uint32, error) { + if len(data) < 4 { + return 0, NewErrUnSufficientBytesError(4, 0) + } + return order.Uint32(data), nil +} + +func UInt32(order binary.ByteOrder) Type[uint32] { + return NewFixedType[uint32]( + 4, + func(data []byte) (uint32, error) { + return ParseUInt32(data, order) + }, + func(value uint32, box []byte) (err error) { + return CompileUInt32(value, box, order) + }, + ) +} + +func UInt32LE() Type[uint32] { + return UInt32(binary.LittleEndian) +} + +func UInt32BE() Type[uint32] { + return UInt32(binary.BigEndian) +} + +func UInt32Header(order binary.ByteOrder) Type[int] { + return NewFixedType[int]( + 4, + func(data []byte) (int, error) { + n, err := ParseUInt32(data, order) + m := int(n) + return m, err + }, + func(value int, box []byte) (err error) { + if value > math.MaxUint32 || value < 0 { + return ErrOverflow + } + + return CompileUInt32(uint32(value), box, order) + }, + ) +} + +func UInt32LEHeader() Type[int] { + return UInt32Header(binary.LittleEndian) +} + +func UInt32BEHeader() Type[int] { + return UInt32Header(binary.BigEndian) +} + +func CompileInt32(i32 int32, box []byte, order binary.ByteOrder) (err error) { + order.PutUint32(box, uint32(i32)) + return +} + +func ParseInt32(data []byte, order binary.ByteOrder) (int32, error) { + if len(data) < 4 { + return 0, NewErrUnSufficientBytesError(4, 0) + } + + return int32(order.Uint32(data)), nil +} + +func Int32(order binary.ByteOrder) Type[int32] { + return NewFixedType[int32]( + 4, + func(data []byte) (int32, error) { + return ParseInt32(data, order) + }, + func(value int32, box []byte) (err error) { + return CompileInt32(value, box, order) + }, + ) +} + +func Int32LE() Type[int32] { + return Int32(binary.LittleEndian) +} + +func Int32BE() Type[int32] { + return Int32(binary.BigEndian) +} + +func Int32Header(order binary.ByteOrder) Type[int] { + return NewFixedType[int]( + 4, + func(data []byte) (int, error) { + n, err := ParseInt32(data, order) + m := int(n) + return m, err + }, + func(value int, box []byte) (err error) { + if value > math.MaxInt32 || value < math.MinInt32 { + return ErrOverflow + } + return CompileInt32(int32(value), box, order) + }, + ) +} + +func Int32LEHeader() Type[int] { + return Int32Header(binary.LittleEndian) +} + +func Int32BEHeader() Type[int] { + return Int32Header(binary.BigEndian) +} diff --git a/type_uint64.go b/type_uint64.go new file mode 100644 index 0000000..01f807e --- /dev/null +++ b/type_uint64.go @@ -0,0 +1,122 @@ +package parco + +import ( + "encoding/binary" + "math" +) + +func CompileUInt64(u64 uint64, box []byte, order binary.ByteOrder) (err error) { + order.PutUint64(box, u64) + return +} + +func ParseUInt64(data []byte, order binary.ByteOrder) (uint64, error) { + if len(data) < 8 { + return 0, NewErrUnSufficientBytesError(4, 0) + } + return order.Uint64(data), nil +} + +func UInt64(order binary.ByteOrder) Type[uint64] { + return NewFixedType[uint64]( + 8, + func(data []byte) (uint64, error) { + return ParseUInt64(data, order) + }, + func(value uint64, box []byte) (err error) { + return CompileUInt64(value, box, order) + }, + ) +} + +func UInt64LE() Type[uint64] { + return UInt64(binary.LittleEndian) +} + +func UInt64BE() Type[uint64] { + return UInt64(binary.BigEndian) +} + +func UInt64Header(order binary.ByteOrder) Type[int] { + return NewFixedType[int]( + 8, + func(data []byte) (int, error) { + n, err := ParseUInt64(data, order) + m := int(n) + return m, err + }, + func(value int, box []byte) (err error) { + if value < 0 { + return ErrOverflow + } + + return CompileUInt64(uint64(value), box, order) + }, + ) +} + +func UInt64LEHeader() Type[int] { + return UInt64Header(binary.LittleEndian) +} + +func UInt64BEHeader() Type[int] { + return UInt64Header(binary.BigEndian) +} + +func CompileInt64(i64 int64, box []byte, order binary.ByteOrder) (err error) { + order.PutUint64(box, uint64(i64)) + return +} + +func ParseInt64(data []byte, order binary.ByteOrder) (int64, error) { + if len(data) < 8 { + return 0, NewErrUnSufficientBytesError(4, 0) + } + + return int64(order.Uint64(data)), nil +} + +func Int64(order binary.ByteOrder) Type[int64] { + return NewFixedType[int64]( + 8, + func(data []byte) (int64, error) { + return ParseInt64(data, order) + }, + func(value int64, box []byte) (err error) { + return CompileInt64(value, box, order) + }, + ) +} + +func Int64LE() Type[int64] { + return Int64(binary.LittleEndian) +} + +func Int64BE() Type[int64] { + return Int64(binary.BigEndian) +} + +func Int64Header(order binary.ByteOrder) Type[int] { + return NewFixedType[int]( + 8, + func(data []byte) (int, error) { + n, err := ParseInt64(data, order) + m := int(n) + return m, err + }, + func(value int, box []byte) (err error) { + if value > math.MaxInt64 || value < math.MinInt64 { + return ErrOverflow + } + return CompileInt64(int64(value), box, order) + }, + ) +} + +func Int64LEHeader() Type[int] { + return Int64Header(binary.LittleEndian) +} + +func Int64BEHeader() Type[int] { + return Int64Header(binary.BigEndian) +} diff --git a/type_uint8.go b/type_uint8.go index e3298e1..09bfa5d 100644 --- a/type_uint8.go +++ b/type_uint8.go @@ -1,5 +1,7 @@ package parco +import "math" + func CompileUInt8(u8 uint8, box []byte) (err error) { box[0] = u8 return @@ -36,6 +38,10 @@ func UInt8() Type[uint8] { ) } +func Byte() Type[byte] { + return UInt8() +} + func UInt8Header() Type[int] { return NewFixedType[int]( 1, @@ -44,6 +50,53 @@ func UInt8Header() Type[int] { ) } +func CompileInt8(i8 int8, box []byte) (err error) { + return CompileUInt8(uint8(i8), box) +} + +func ParseInt8(data []byte) (int8, error) { + if len(data) < 1 { + return 0, NewErrUnSufficientBytesError(1, 0) + } + if data[0] > math.MaxInt8 { + return 0, ErrOverflow + } + return int8(data[0]), nil +} + +func CompileInt8Header(i int, box []byte) (err error) { + if i > math.MaxInt8 || i < math.MinInt8 { + err = ErrOverflow + return + } + box[0] = byte(i) + return +} + +func ParseInt8Header(box []byte) (int, error) { + x, err := ParseInt8(box) + if err != nil { + return 0, err + } + return int(x), nil +} + +func Int8() Type[int8] { + return NewFixedType[int8]( + 1, + ParseInt8, + CompileInt8, + ) +} + +func Int8Header() Type[int] { + return NewFixedType[int]( + 1, + ParseInt8Header, + CompileInt8Header, + ) +} + func Bool() Type[bool] { return NewFixedType[bool]( 1, diff --git a/type_varchar.go b/type_varchar.go index e81b5b4..9fd48ca 100644 --- a/type_varchar.go +++ b/type_varchar.go @@ -25,6 +25,16 @@ func NewVarcharType(header IntType) Type[string] { } } +func String(header IntType) Type[string] { + return varType[string]{ + header: header, + sizer: SizerFunc[string](func(x string) int { return len(x) }), + pool: SinglePool, + parser: ParseStringFactory(), + compiler: CompileStringWriter, + } +} + func SmallVarchar() Type[string] { return NewVarcharType(UInt8Header()) } @@ -37,6 +47,13 @@ func VarcharOrder(order binary.ByteOrder) Type[string] { return NewVarcharType(UInt16Header(order)) } +func Text(order binary.ByteOrder) Type[string] { + return NewVarcharType(UInt32Header(order)) +} +func LongText(order binary.ByteOrder) Type[string] { + return NewVarcharType(UInt64Header(order)) +} + func ParseStringFactory() ParserFunc[string] { return func(data []byte) (string, error) { return ParseString(data) diff --git a/utils_helpers.go b/utils_helpers.go new file mode 100644 index 0000000..61a0b40 --- /dev/null +++ b/utils_helpers.go @@ -0,0 +1,9 @@ +package parco + +func If[T any](condition bool, a, b T) T { + if condition { + return a + } + + return b +} diff --git a/utils_types.go b/utils_types.go index 96a98af..bd588f4 100644 --- a/utils_types.go +++ b/utils_types.go @@ -11,19 +11,9 @@ type ( ) type ( - String string - Slice[T any] []T ) -func (s String) Len() int { - return len(s) -} - -func (s String) Unwrap() string { - return string(s) -} - func (s Slice[T]) Len() int { return len(s) } @@ -44,4 +34,4 @@ func (s Slice[T]) Unwrap() Slice[T] { func (s SizerFunc[T]) Len(item T) int { return s(item) -} \ No newline at end of file +}