diff --git a/.golangci.yml b/.golangci.yml index df8327f..a333128 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -8,18 +8,22 @@ formatters: - goimports linters: - enable: - - forbidigo - - gocritic - - lll - - reassign - - unconvert - - gosec - - errorlint - - godot - - revive - - testpackage - - unused + default: all + + disable: + - dupl + - cyclop + - wsl + - nlreturn + - ireturn + - wrapcheck + + exclusions: + rules: + - path-except: cmd/generator/*.go + linters: + - forbidigo + - gochecknoglobals settings: godot: @@ -27,3 +31,31 @@ linters: lll: line-length: 120 tab-width: 4 + wsl_v5: + allow-first-in-block: true + allow-whole-block: false + branch-max-lines: 2 + case-max-lines: 0 + default: all + disable: + - return + - assign-exclusive + - assign-expr + depguard: + rules: + main: + files: + - "$all" + - "!$test" + allow: + - $gostd + - "github.com/vmihailenco/msgpack/v5" + - "golang.org/x/text" + test: + files: + - "$test" + allow: + - $gostd + - "github.com/stretchr/testify" + - "github.com/vmihailenco/msgpack/v5" + - "github.com/tarantool/go-option" diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bbbe49..ecedc83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ Versioning](http://semver.org/spec/v2.0.0.html) except to the first release. ### Added +* Implemented optional types for builtin go types int*, uint*, float*, + bytes, string, bool. + + ### Changed ### Fixed diff --git a/bool.go b/bool.go new file mode 100644 index 0000000..dea514e --- /dev/null +++ b/bool.go @@ -0,0 +1,90 @@ +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type Bool struct { + value bool + exists bool +} + +func SomeBool(value bool) Bool { + return Bool{ + value: value, + exists: true, + } +} + +func NoneBool() Bool { + return Bool{ + exists: false, + value: zero[bool](), + } +} + +func (o Bool) IsSome() bool { + return o.exists +} + +func (o Bool) IsZero() bool { + return !o.exists +} + +func (o Bool) Get() (bool, bool) { + return o.value, o.exists +} + +func (o Bool) MustGet() bool { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o Bool) Unwrap() bool { + return o.value +} + +func (o Bool) UnwrapOr(defaultValue bool) bool { + if o.exists { + return o.value + } + return defaultValue +} + +func (o Bool) UnwrapOrElse(defaultValue func() bool) bool { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o Bool) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return encodeBool(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *Bool) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case checkBool(code): + o.exists = true + o.value, err = decodeBool(decoder) + return err + default: + return newFailedToDecodeError("Bool", code) + } +} diff --git a/bool_test.go b/bool_test.go new file mode 100644 index 0000000..21838a1 --- /dev/null +++ b/bool_test.go @@ -0,0 +1,38 @@ +package option_test + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/vmihailenco/msgpack/v5" + + "github.com/tarantool/go-option" +) + +func TestOptionalBool(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + + enc := msgpack.NewEncoder(&buf) + dec := msgpack.NewDecoder(&buf) + + someBool := option.SomeBool(true) + assert.True(t, someBool.IsSome(), "Expected IsPresent() to return true") + require.NoError(t, someBool.EncodeMsgpack(enc)) + + var shouldBeSomeBool option.Bool + require.NoError(t, shouldBeSomeBool.DecodeMsgpack(dec)) + assert.True(t, shouldBeSomeBool.IsSome(), "Expected IsPresent() to return true") + assert.Equal(t, someBool.Unwrap(), shouldBeSomeBool.Unwrap(), "Expected Value() to return the same value") + + emptyBool := option.NoneBool() + assert.False(t, emptyBool.IsSome(), "Expected IsPresent() to return false") + require.NoError(t, emptyBool.EncodeMsgpack(enc)) + + var shouldBeEmptyBool option.Bool + require.NoError(t, shouldBeEmptyBool.DecodeMsgpack(dec)) + assert.False(t, shouldBeEmptyBool.IsSome(), "Expected IsPresent() to return false") +} diff --git a/bytes.go b/bytes.go new file mode 100644 index 0000000..0e33fd2 --- /dev/null +++ b/bytes.go @@ -0,0 +1,90 @@ +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type Bytes struct { + value []byte + exists bool +} + +func SomeBytes(value []byte) Bytes { + return Bytes{ + value: value, + exists: true, + } +} + +func NoneBytes() Bytes { + return Bytes{ + exists: false, + value: zero[[]byte](), + } +} + +func (o Bytes) IsSome() bool { + return o.exists +} + +func (o Bytes) IsZero() bool { + return !o.exists +} + +func (o Bytes) Get() ([]byte, bool) { + return o.value, o.exists +} + +func (o Bytes) MustGet() []byte { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o Bytes) Unwrap() []byte { + return o.value +} + +func (o Bytes) UnwrapOr(defaultValue []byte) []byte { + if o.exists { + return o.value + } + return defaultValue +} + +func (o Bytes) UnwrapOrElse(defaultValue func() []byte) []byte { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o Bytes) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return encodeBytes(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *Bytes) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case checkBytes(code): + o.exists = true + o.value, err = decodeBytes(decoder) + return err + default: + return newFailedToDecodeError("Bytes", code) + } +} diff --git a/bytes_test.go b/bytes_test.go new file mode 100644 index 0000000..d394c05 --- /dev/null +++ b/bytes_test.go @@ -0,0 +1,38 @@ +package option_test + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/vmihailenco/msgpack/v5" + + "github.com/tarantool/go-option" +) + +func TestOptionalBytes(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + + enc := msgpack.NewEncoder(&buf) + dec := msgpack.NewDecoder(&buf) + + someBytes := option.SomeBytes([]byte("1234")) + assert.True(t, someBytes.IsSome(), "Expected IsPresent() to return true") + require.NoError(t, someBytes.EncodeMsgpack(enc)) + + var shouldBeSomeBytes option.Bytes + require.NoError(t, shouldBeSomeBytes.DecodeMsgpack(dec)) + assert.True(t, shouldBeSomeBytes.IsSome(), "Expected IsPresent() to return true") + assert.Equal(t, someBytes.Unwrap(), shouldBeSomeBytes.Unwrap(), "Expected Value() to return the same value") + + emptyBytes := option.NoneBytes() + assert.False(t, emptyBytes.IsSome(), "Expected IsPresent() to return false") + require.NoError(t, emptyBytes.EncodeMsgpack(enc)) + + var shouldBeEmptyBytes option.Bytes + require.NoError(t, shouldBeEmptyBytes.DecodeMsgpack(dec)) + assert.False(t, shouldBeEmptyBytes.IsSome(), "Expected IsPresent() to return false") +} diff --git a/cmd/generator/generator.go b/cmd/generator/generator.go new file mode 100644 index 0000000..7170037 --- /dev/null +++ b/cmd/generator/generator.go @@ -0,0 +1,339 @@ +package main + +import ( + "bytes" + "flag" + "fmt" + "go/format" + "os" + "path/filepath" + "slices" + "text/template" + + "golang.org/x/text/cases" + "golang.org/x/text/language" +) + +const ( + defaultGoPermissions = 0644 +) + +var ( + outputDirectory string + verbose bool +) + +type generatorDef struct { + Name string + Type string + DecodeFunc string + EncoderFunc string + CheckerFunc string +} + +func structToMap(def generatorDef) map[string]interface{} { + caser := cases.Title(language.English) + + out := map[string]interface{}{ + "Name": caser.String(def.Name), + "Type": def.Name, + "DecodeFunc": def.DecodeFunc, + "EncoderFunc": def.EncoderFunc, + "CheckerFunc": def.CheckerFunc, + } + + if def.Type != "" { + out["Type"] = def.Type + } + + return out +} + +var DefaultTypes = []generatorDef{ + { + Name: "int", + Type: "int", + DecodeFunc: "decodeInt", + EncoderFunc: "encodeInt", + CheckerFunc: "checkNumber", + }, + { + Name: "int8", + Type: "int8", + DecodeFunc: "decodeInt8", + EncoderFunc: "encodeInt8", + CheckerFunc: "checkNumber", + }, + { + Name: "int16", + Type: "int16", + DecodeFunc: "decodeInt16", + EncoderFunc: "encodeInt16", + CheckerFunc: "checkNumber", + }, + { + Name: "int32", + Type: "int32", + DecodeFunc: "decodeInt32", + EncoderFunc: "encodeInt32", + CheckerFunc: "checkNumber", + }, + { + Name: "int64", + Type: "int64", + DecodeFunc: "decodeInt64", + EncoderFunc: "encodeInt64", + CheckerFunc: "checkNumber", + }, + { + Name: "uint", + Type: "uint", + DecodeFunc: "decodeUint", + EncoderFunc: "encodeUint", + CheckerFunc: "checkNumber", + }, + { + Name: "uint8", + Type: "uint8", + DecodeFunc: "decodeUint8", + EncoderFunc: "encodeUint8", + CheckerFunc: "checkNumber", + }, + { + Name: "uint16", + Type: "uint16", + DecodeFunc: "decodeUint16", + EncoderFunc: "encodeUint16", + CheckerFunc: "checkNumber", + }, + { + Name: "uint32", + Type: "uint32", + DecodeFunc: "decodeUint32", + EncoderFunc: "encodeUint32", + CheckerFunc: "checkNumber", + }, + { + Name: "uint64", + Type: "uint64", + DecodeFunc: "decodeUint64", + EncoderFunc: "encodeUint64", + CheckerFunc: "checkNumber", + }, + { + Name: "float32", + Type: "float32", + DecodeFunc: "decodeFloat32", + EncoderFunc: "encodeFloat32", + CheckerFunc: "checkFloat", + }, + { + Name: "float64", + Type: "float64", + DecodeFunc: "decodeFloat64", + EncoderFunc: "encodeFloat64", + CheckerFunc: "checkFloat", + }, + { + Name: "string", + Type: "string", + DecodeFunc: "decodeString", + EncoderFunc: "encodeString", + CheckerFunc: "checkString", + }, + { + Name: "bytes", + Type: "[]byte", + DecodeFunc: "decodeBytes", + EncoderFunc: "encodeBytes", + CheckerFunc: "checkBytes", + }, + { + Name: "bool", + Type: "bool", + DecodeFunc: "decodeBool", + EncoderFunc: "encodeBool", + CheckerFunc: "checkBool", + }, +} + +var tplText = ` +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package {{ .packageName }} + +import ( + {{ range $i, $import := .imports }} + "{{ $import }}" + {{ end }} + + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type {{.Name}} struct { + value {{.Type}} + exists bool +} + +func Some{{.Name}}(value {{.Type}}) {{.Name}} { + return {{.Name}}{ + value: value, + exists: true, + } +} + +func None{{.Name}}() {{.Name}} { + return {{.Name}}{ + exists: false, + value: zero[{{.Type}}](), + } +} + +func (o {{.Name}}) IsSome() bool { + return o.exists +} + +func (o {{.Name}}) IsZero() bool { + return !o.exists +} + +func (o {{.Name}}) Get() ({{.Type}}, bool) { + return o.value, o.exists +} + +func (o {{.Name}}) MustGet() {{.Type}} { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o {{.Name}}) Unwrap() {{.Type}} { + return o.value +} + +func (o {{.Name}}) UnwrapOr(defaultValue {{.Type}}) {{.Type}} { + if o.exists { + return o.value + } + return defaultValue +} + +func (o {{.Name}}) UnwrapOrElse(defaultValue func() {{.Type}}) {{.Type}} { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o {{.Name}}) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return {{ .EncoderFunc }}(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *{{.Name}}) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case {{ .CheckerFunc }}(code): + o.exists = true + o.value, err = {{ .DecodeFunc }}(decoder) + return err + default: + return newFailedToDecodeError("{{.Name}}", code) + } +} +` + +func printFile(prefix string, data []byte) { + for _, line := range bytes.Split(data, []byte("\n")) { + fmt.Println(prefix + string(line)) + } +} + +func generateAndWrite() error { + tmpl, err := template.New("internal").Parse(tplText) + if err != nil { + return fmt.Errorf("failed to parse template: %w", err) + } + + outputData := make(map[string][]byte, len(DefaultTypes)) + + var data bytes.Buffer + + // 1. Generate code for each type. + for _, generatedType := range DefaultTypes { + tmplData := structToMap(generatedType) + tmplData["packageName"] = "option" // Package name is option, since generator is used for option only right now. + tmplData["imports"] = []string{} // No additional imports are needed right now. + + err := tmpl.Execute(&data, tmplData) + if err != nil { + return fmt.Errorf("failed to execute template: %w", err) + } + + outputData[generatedType.Name] = slices.Clone(data.Bytes()) + data.Reset() + } + + // 2. Format code using gofmt. + for name, origData := range outputData { + data, err := format.Source(origData) + if err != nil { + if verbose { + printFile("> ", origData) + } + return fmt.Errorf("failed to format code: %w", err) + } + + outputData[name] = data + } + + // 3. Write resulting code to files. + for name, data := range outputData { + err = os.WriteFile(filepath.Join(outputDirectory, name+".go"), data, defaultGoPermissions) + if err != nil { + return fmt.Errorf("failed to write file: %w", err) + } + } + + return nil +} + +func main() { + flag.StringVar(&outputDirectory, "output", ".", "output directory") + flag.BoolVar(&verbose, "verbose", false, "print verbose output") + flag.Parse() + + // Get absolute path for output directory. + absOutputDirectory, err := filepath.Abs(outputDirectory) + if err != nil { + fmt.Printf("failed to get absolute path for output directory (%s): %s\n", outputDirectory, err.Error()) + os.Exit(1) + } + + // Check if output directory exists and is directory. + switch fInfo, err := os.Stat(absOutputDirectory); { + case err != nil: + fmt.Println("failed to stat output directory: ", err.Error()) + os.Exit(1) + case !fInfo.IsDir(): + fmt.Printf("output directory '%s' is not a directory\n", absOutputDirectory) + os.Exit(1) + } + + err = generateAndWrite() + if err != nil { + fmt.Println("failed to generate or write code: ", err.Error()) + os.Exit(1) + } +} diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..8c43d4e --- /dev/null +++ b/errors.go @@ -0,0 +1,19 @@ +package option + +import ( + "fmt" +) + +// FailedToDecodeError is returned when decoding failed due to invalid code in msgpack stream. +type FailedToDecodeError struct { + Type string + Code byte +} + +func (d FailedToDecodeError) Error() string { + return fmt.Sprintf("failed to decode %s, invalid code: %d", d.Type, d.Code) +} + +func newFailedToDecodeError(tp string, code byte) error { + return FailedToDecodeError{Type: tp, Code: code} +} diff --git a/float32.go b/float32.go new file mode 100644 index 0000000..77b6f51 --- /dev/null +++ b/float32.go @@ -0,0 +1,90 @@ +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type Float32 struct { + value float32 + exists bool +} + +func SomeFloat32(value float32) Float32 { + return Float32{ + value: value, + exists: true, + } +} + +func NoneFloat32() Float32 { + return Float32{ + exists: false, + value: zero[float32](), + } +} + +func (o Float32) IsSome() bool { + return o.exists +} + +func (o Float32) IsZero() bool { + return !o.exists +} + +func (o Float32) Get() (float32, bool) { + return o.value, o.exists +} + +func (o Float32) MustGet() float32 { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o Float32) Unwrap() float32 { + return o.value +} + +func (o Float32) UnwrapOr(defaultValue float32) float32 { + if o.exists { + return o.value + } + return defaultValue +} + +func (o Float32) UnwrapOrElse(defaultValue func() float32) float32 { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o Float32) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return encodeFloat32(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *Float32) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case checkFloat(code): + o.exists = true + o.value, err = decodeFloat32(decoder) + return err + default: + return newFailedToDecodeError("Float32", code) + } +} diff --git a/float64.go b/float64.go new file mode 100644 index 0000000..dd0f81d --- /dev/null +++ b/float64.go @@ -0,0 +1,90 @@ +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type Float64 struct { + value float64 + exists bool +} + +func SomeFloat64(value float64) Float64 { + return Float64{ + value: value, + exists: true, + } +} + +func NoneFloat64() Float64 { + return Float64{ + exists: false, + value: zero[float64](), + } +} + +func (o Float64) IsSome() bool { + return o.exists +} + +func (o Float64) IsZero() bool { + return !o.exists +} + +func (o Float64) Get() (float64, bool) { + return o.value, o.exists +} + +func (o Float64) MustGet() float64 { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o Float64) Unwrap() float64 { + return o.value +} + +func (o Float64) UnwrapOr(defaultValue float64) float64 { + if o.exists { + return o.value + } + return defaultValue +} + +func (o Float64) UnwrapOrElse(defaultValue func() float64) float64 { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o Float64) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return encodeFloat64(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *Float64) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case checkFloat(code): + o.exists = true + o.value, err = decodeFloat64(decoder) + return err + default: + return newFailedToDecodeError("Float64", code) + } +} diff --git a/float_test.go b/float_test.go new file mode 100644 index 0000000..847287d --- /dev/null +++ b/float_test.go @@ -0,0 +1,66 @@ +package option_test + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/vmihailenco/msgpack/v5" + + "github.com/tarantool/go-option" +) + +func TestOptionalFloat32(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + + enc := msgpack.NewEncoder(&buf) + dec := msgpack.NewDecoder(&buf) + + someFloat32 := option.SomeFloat32(3.11) + assert.True(t, someFloat32.IsSome(), "Expected IsPresent() to return true") + require.NoError(t, someFloat32.EncodeMsgpack(enc)) + + var shouldBeSomeFloat32 option.Float32 + require.NoError(t, shouldBeSomeFloat32.DecodeMsgpack(dec)) + assert.True(t, shouldBeSomeFloat32.IsSome(), "Expected IsPresent() to return true") + assert.InEpsilon(t, someFloat32.Unwrap(), shouldBeSomeFloat32.Unwrap(), 1e-6, + "Expected Value() to return the same value") + + emptyFloat32 := option.NoneFloat32() + assert.False(t, emptyFloat32.IsSome(), "Expected IsPresent() to return false") + require.NoError(t, emptyFloat32.EncodeMsgpack(enc)) + + var shouldBeEmptyFloat32 option.Float32 + require.NoError(t, shouldBeEmptyFloat32.DecodeMsgpack(dec)) + assert.False(t, shouldBeEmptyFloat32.IsSome(), "Expected IsPresent() to return false") +} + +func TestOptionalFloat64(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + + enc := msgpack.NewEncoder(&buf) + dec := msgpack.NewDecoder(&buf) + + someFloat64 := option.SomeFloat64(3.11) + assert.True(t, someFloat64.IsSome(), "Expected IsPresent() to return true") + require.NoError(t, someFloat64.EncodeMsgpack(enc)) + + var shouldBeSomeFloat64 option.Float64 + require.NoError(t, shouldBeSomeFloat64.DecodeMsgpack(dec)) + assert.True(t, shouldBeSomeFloat64.IsSome(), "Expected IsPresent() to return true") + assert.InEpsilon(t, someFloat64.Unwrap(), shouldBeSomeFloat64.Unwrap(), 1e-6, + "Expected Value() to return the same value") + + emptyFloat64 := option.NoneFloat64() + assert.False(t, emptyFloat64.IsSome(), "Expected IsPresent() to return false") + require.NoError(t, emptyFloat64.EncodeMsgpack(enc)) + + var shouldBeEmptyFloat64 option.Float64 + require.NoError(t, shouldBeEmptyFloat64.DecodeMsgpack(dec)) + assert.False(t, shouldBeEmptyFloat64.IsSome(), "Expected IsPresent() to return false") +} diff --git a/generate.go b/generate.go new file mode 100644 index 0000000..28864ac --- /dev/null +++ b/generate.go @@ -0,0 +1,2 @@ +//go:generate go run ./cmd/generator --output ./ +package option diff --git a/go.mod b/go.mod index 1287fed..69fde24 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,18 @@ module github.com/tarantool/go-option -go 1.23 +go 1.23.0 + +toolchain go1.24.4 + +require ( + github.com/stretchr/testify v1.10.0 + github.com/vmihailenco/msgpack/v5 v5.4.1 + golang.org/x/text v0.28.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum index e69de29..099fcea 100644 --- a/go.sum +++ b/go.sum @@ -0,0 +1,16 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers.go b/helpers.go new file mode 100644 index 0000000..dab749a --- /dev/null +++ b/helpers.go @@ -0,0 +1,160 @@ +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +func checkNumber(code byte) bool { + switch { + case msgpcode.IsFixedNum(code): + return true + case code == msgpcode.Int8 || code == msgpcode.Int16 || code == msgpcode.Int32 || code == msgpcode.Int64: + return true + case code == msgpcode.Uint8 || code == msgpcode.Uint16 || code == msgpcode.Uint32 || code == msgpcode.Uint64: + return true + default: + return false + } +} + +func decodeInt(decoder *msgpack.Decoder) (int, error) { + return decoder.DecodeInt() +} + +func decodeInt8(decoder *msgpack.Decoder) (int8, error) { + return decoder.DecodeInt8() +} + +func decodeInt16(decoder *msgpack.Decoder) (int16, error) { + return decoder.DecodeInt16() +} + +func decodeInt32(decoder *msgpack.Decoder) (int32, error) { + return decoder.DecodeInt32() +} + +func decodeInt64(decoder *msgpack.Decoder) (int64, error) { + return decoder.DecodeInt64() +} + +func decodeUint(decoder *msgpack.Decoder) (uint, error) { + return decoder.DecodeUint() +} + +func decodeUint8(decoder *msgpack.Decoder) (uint8, error) { + return decoder.DecodeUint8() +} + +func decodeUint16(decoder *msgpack.Decoder) (uint16, error) { + return decoder.DecodeUint16() +} + +func decodeUint32(decoder *msgpack.Decoder) (uint32, error) { + return decoder.DecodeUint32() +} + +func decodeUint64(decoder *msgpack.Decoder) (uint64, error) { + return decoder.DecodeUint64() +} + +func encodeInt(encoder *msgpack.Encoder, val int) error { + return encoder.EncodeInt(int64(val)) +} + +func encodeInt8(encoder *msgpack.Encoder, val int8) error { + return encoder.EncodeInt(int64(val)) +} + +func encodeInt16(encoder *msgpack.Encoder, val int16) error { + return encoder.EncodeInt(int64(val)) +} + +func encodeInt32(encoder *msgpack.Encoder, val int32) error { + return encoder.EncodeInt(int64(val)) +} + +func encodeInt64(encoder *msgpack.Encoder, val int64) error { + return encoder.EncodeInt(val) +} + +func encodeUint(encoder *msgpack.Encoder, val uint) error { + return encoder.EncodeUint(uint64(val)) +} + +func encodeUint8(encoder *msgpack.Encoder, val uint8) error { + return encoder.EncodeUint(uint64(val)) +} + +func encodeUint16(encoder *msgpack.Encoder, val uint16) error { + return encoder.EncodeUint(uint64(val)) +} + +func encodeUint32(encoder *msgpack.Encoder, val uint32) error { + return encoder.EncodeUint(uint64(val)) +} + +func encodeUint64(encoder *msgpack.Encoder, val uint64) error { + return encoder.EncodeUint(val) +} + +func checkFloat(code byte) bool { + return checkNumber(code) || code == msgpcode.Float || code == msgpcode.Double +} + +func decodeFloat32(decoder *msgpack.Decoder) (float32, error) { + return decoder.DecodeFloat32() +} + +func encodeFloat32(encoder *msgpack.Encoder, val float32) error { + return encoder.EncodeFloat32(val) +} + +func decodeFloat64(decoder *msgpack.Decoder) (float64, error) { + return decoder.DecodeFloat64() +} + +func encodeFloat64(encoder *msgpack.Encoder, val float64) error { + return encoder.EncodeFloat64(val) +} + +func checkString(code byte) bool { + return msgpcode.IsBin(code) || msgpcode.IsString(code) +} + +func decodeString(decoder *msgpack.Decoder) (string, error) { + return decoder.DecodeString() +} + +func encodeString(encoder *msgpack.Encoder, val string) error { + return encoder.EncodeString(val) +} + +func checkBytes(code byte) bool { + return msgpcode.IsBin(code) || msgpcode.IsString(code) +} + +func decodeBytes(decoder *msgpack.Decoder) ([]byte, error) { + return decoder.DecodeBytes() +} + +func encodeBytes(encoder *msgpack.Encoder, b []byte) error { + return encoder.EncodeBytes(b) +} + +func checkBool(code byte) bool { + return code == msgpcode.True || code == msgpcode.False +} + +func decodeBool(decoder *msgpack.Decoder) (bool, error) { + return decoder.DecodeBool() +} + +func encodeBool(encoder *msgpack.Encoder, b bool) error { + return encoder.EncodeBool(b) +} + +func zero[T any]() T { + var zero T + return zero +} diff --git a/int.go b/int.go new file mode 100644 index 0000000..2895b5d --- /dev/null +++ b/int.go @@ -0,0 +1,90 @@ +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type Int struct { + value int + exists bool +} + +func SomeInt(value int) Int { + return Int{ + value: value, + exists: true, + } +} + +func NoneInt() Int { + return Int{ + exists: false, + value: zero[int](), + } +} + +func (o Int) IsSome() bool { + return o.exists +} + +func (o Int) IsZero() bool { + return !o.exists +} + +func (o Int) Get() (int, bool) { + return o.value, o.exists +} + +func (o Int) MustGet() int { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o Int) Unwrap() int { + return o.value +} + +func (o Int) UnwrapOr(defaultValue int) int { + if o.exists { + return o.value + } + return defaultValue +} + +func (o Int) UnwrapOrElse(defaultValue func() int) int { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o Int) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return encodeInt(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *Int) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case checkNumber(code): + o.exists = true + o.value, err = decodeInt(decoder) + return err + default: + return newFailedToDecodeError("Int", code) + } +} diff --git a/int16.go b/int16.go new file mode 100644 index 0000000..8a9f498 --- /dev/null +++ b/int16.go @@ -0,0 +1,90 @@ +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type Int16 struct { + value int16 + exists bool +} + +func SomeInt16(value int16) Int16 { + return Int16{ + value: value, + exists: true, + } +} + +func NoneInt16() Int16 { + return Int16{ + exists: false, + value: zero[int16](), + } +} + +func (o Int16) IsSome() bool { + return o.exists +} + +func (o Int16) IsZero() bool { + return !o.exists +} + +func (o Int16) Get() (int16, bool) { + return o.value, o.exists +} + +func (o Int16) MustGet() int16 { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o Int16) Unwrap() int16 { + return o.value +} + +func (o Int16) UnwrapOr(defaultValue int16) int16 { + if o.exists { + return o.value + } + return defaultValue +} + +func (o Int16) UnwrapOrElse(defaultValue func() int16) int16 { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o Int16) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return encodeInt16(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *Int16) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case checkNumber(code): + o.exists = true + o.value, err = decodeInt16(decoder) + return err + default: + return newFailedToDecodeError("Int16", code) + } +} diff --git a/int32.go b/int32.go new file mode 100644 index 0000000..cb7ab19 --- /dev/null +++ b/int32.go @@ -0,0 +1,90 @@ +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type Int32 struct { + value int32 + exists bool +} + +func SomeInt32(value int32) Int32 { + return Int32{ + value: value, + exists: true, + } +} + +func NoneInt32() Int32 { + return Int32{ + exists: false, + value: zero[int32](), + } +} + +func (o Int32) IsSome() bool { + return o.exists +} + +func (o Int32) IsZero() bool { + return !o.exists +} + +func (o Int32) Get() (int32, bool) { + return o.value, o.exists +} + +func (o Int32) MustGet() int32 { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o Int32) Unwrap() int32 { + return o.value +} + +func (o Int32) UnwrapOr(defaultValue int32) int32 { + if o.exists { + return o.value + } + return defaultValue +} + +func (o Int32) UnwrapOrElse(defaultValue func() int32) int32 { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o Int32) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return encodeInt32(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *Int32) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case checkNumber(code): + o.exists = true + o.value, err = decodeInt32(decoder) + return err + default: + return newFailedToDecodeError("Int32", code) + } +} diff --git a/int64.go b/int64.go new file mode 100644 index 0000000..bd948a5 --- /dev/null +++ b/int64.go @@ -0,0 +1,90 @@ +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type Int64 struct { + value int64 + exists bool +} + +func SomeInt64(value int64) Int64 { + return Int64{ + value: value, + exists: true, + } +} + +func NoneInt64() Int64 { + return Int64{ + exists: false, + value: zero[int64](), + } +} + +func (o Int64) IsSome() bool { + return o.exists +} + +func (o Int64) IsZero() bool { + return !o.exists +} + +func (o Int64) Get() (int64, bool) { + return o.value, o.exists +} + +func (o Int64) MustGet() int64 { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o Int64) Unwrap() int64 { + return o.value +} + +func (o Int64) UnwrapOr(defaultValue int64) int64 { + if o.exists { + return o.value + } + return defaultValue +} + +func (o Int64) UnwrapOrElse(defaultValue func() int64) int64 { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o Int64) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return encodeInt64(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *Int64) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case checkNumber(code): + o.exists = true + o.value, err = decodeInt64(decoder) + return err + default: + return newFailedToDecodeError("Int64", code) + } +} diff --git a/int8.go b/int8.go new file mode 100644 index 0000000..55442cf --- /dev/null +++ b/int8.go @@ -0,0 +1,90 @@ +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type Int8 struct { + value int8 + exists bool +} + +func SomeInt8(value int8) Int8 { + return Int8{ + value: value, + exists: true, + } +} + +func NoneInt8() Int8 { + return Int8{ + exists: false, + value: zero[int8](), + } +} + +func (o Int8) IsSome() bool { + return o.exists +} + +func (o Int8) IsZero() bool { + return !o.exists +} + +func (o Int8) Get() (int8, bool) { + return o.value, o.exists +} + +func (o Int8) MustGet() int8 { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o Int8) Unwrap() int8 { + return o.value +} + +func (o Int8) UnwrapOr(defaultValue int8) int8 { + if o.exists { + return o.value + } + return defaultValue +} + +func (o Int8) UnwrapOrElse(defaultValue func() int8) int8 { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o Int8) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return encodeInt8(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *Int8) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case checkNumber(code): + o.exists = true + o.value, err = decodeInt8(decoder) + return err + default: + return newFailedToDecodeError("Int8", code) + } +} diff --git a/number_test.go b/number_test.go new file mode 100644 index 0000000..771c429 --- /dev/null +++ b/number_test.go @@ -0,0 +1,272 @@ +package option_test + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/vmihailenco/msgpack/v5" + + "github.com/tarantool/go-option" +) + +func TestOptionalInt(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + + enc := msgpack.NewEncoder(&buf) + dec := msgpack.NewDecoder(&buf) + + someInt := option.SomeInt(123) + assert.True(t, someInt.IsSome(), "Expected IsPresent() to return true") + require.NoError(t, someInt.EncodeMsgpack(enc)) + + var shouldBeSomeInt option.Int + require.NoError(t, shouldBeSomeInt.DecodeMsgpack(dec)) + assert.True(t, shouldBeSomeInt.IsSome(), "Expected IsPresent() to return true") + assert.Equal(t, someInt.Unwrap(), shouldBeSomeInt.Unwrap(), "Expected Value() to return the same value") + + emptyInt := option.NoneInt() + assert.False(t, emptyInt.IsSome(), "Expected IsPresent() to return false") + require.NoError(t, emptyInt.EncodeMsgpack(enc)) + + var shouldBeEmptyInt option.Int + require.NoError(t, shouldBeEmptyInt.DecodeMsgpack(dec)) + assert.False(t, shouldBeEmptyInt.IsSome(), "Expected IsPresent() to return false") +} + +func TestOptionalInt8(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + + enc := msgpack.NewEncoder(&buf) + dec := msgpack.NewDecoder(&buf) + + someInt8 := option.SomeInt8(123) + assert.True(t, someInt8.IsSome(), "Expected IsPresent() to return true") + require.NoError(t, someInt8.EncodeMsgpack(enc)) + + var shouldBeSomeInt8 option.Int8 + require.NoError(t, shouldBeSomeInt8.DecodeMsgpack(dec)) + assert.True(t, shouldBeSomeInt8.IsSome(), "Expected IsPresent() to return true") + assert.Equal(t, someInt8.Unwrap(), shouldBeSomeInt8.Unwrap(), "Expected Value() to return the same value") + + emptyInt8 := option.NoneInt8() + assert.False(t, emptyInt8.IsSome(), "Expected IsPresent() to return false") + require.NoError(t, emptyInt8.EncodeMsgpack(enc)) + + var shouldBeEmptyInt8 option.Int8 + require.NoError(t, shouldBeEmptyInt8.DecodeMsgpack(dec)) + assert.False(t, shouldBeEmptyInt8.IsSome(), "Expected IsPresent() to return false") +} + +func TestOptionalInt16(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + + enc := msgpack.NewEncoder(&buf) + dec := msgpack.NewDecoder(&buf) + + someInt16 := option.SomeInt16(123) + assert.True(t, someInt16.IsSome(), "Expected IsPresent() to return true") + require.NoError(t, someInt16.EncodeMsgpack(enc)) + + var shouldBeSomeInt16 option.Int16 + require.NoError(t, shouldBeSomeInt16.DecodeMsgpack(dec)) + assert.True(t, shouldBeSomeInt16.IsSome(), "Expected IsPresent() to return true") + assert.Equal(t, someInt16.Unwrap(), shouldBeSomeInt16.Unwrap(), "Expected Value() to return the same value") + + emptyInt16 := option.NoneInt16() + assert.False(t, emptyInt16.IsSome(), "Expected IsPresent() to return false") + require.NoError(t, emptyInt16.EncodeMsgpack(enc)) + + var shouldBeEmptyInt16 option.Int16 + require.NoError(t, shouldBeEmptyInt16.DecodeMsgpack(dec)) + assert.False(t, shouldBeEmptyInt16.IsSome(), "Expected IsPresent() to return false") +} + +func TestOptionalInt32(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + + enc := msgpack.NewEncoder(&buf) + dec := msgpack.NewDecoder(&buf) + + someInt32 := option.SomeInt32(123) + assert.True(t, someInt32.IsSome(), "Expected IsPresent() to return true") + require.NoError(t, someInt32.EncodeMsgpack(enc)) + + var shouldBeSomeInt32 option.Int32 + require.NoError(t, shouldBeSomeInt32.DecodeMsgpack(dec)) + assert.True(t, shouldBeSomeInt32.IsSome(), "Expected IsPresent() to return true") + assert.Equal(t, someInt32.Unwrap(), shouldBeSomeInt32.Unwrap(), "Expected Value() to return the same value") + + emptyInt32 := option.NoneInt32() + assert.False(t, emptyInt32.IsSome(), "Expected IsPresent() to return false") + require.NoError(t, emptyInt32.EncodeMsgpack(enc)) + + var shouldBeEmptyInt32 option.Int32 + require.NoError(t, shouldBeEmptyInt32.DecodeMsgpack(dec)) + assert.False(t, shouldBeEmptyInt32.IsSome(), "Expected IsPresent() to return false") +} + +func TestOptionalInt64(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + + enc := msgpack.NewEncoder(&buf) + dec := msgpack.NewDecoder(&buf) + + someInt64 := option.SomeInt64(123) + assert.True(t, someInt64.IsSome(), "Expected IsPresent() to return true") + require.NoError(t, someInt64.EncodeMsgpack(enc)) + + var shouldBeSomeInt64 option.Int64 + require.NoError(t, shouldBeSomeInt64.DecodeMsgpack(dec)) + assert.True(t, shouldBeSomeInt64.IsSome(), "Expected IsPresent() to return true") + assert.Equal(t, someInt64.Unwrap(), shouldBeSomeInt64.Unwrap(), "Expected Value() to return the same value") + + emptyInt64 := option.NoneInt64() + assert.False(t, emptyInt64.IsSome(), "Expected IsPresent() to return false") + require.NoError(t, emptyInt64.EncodeMsgpack(enc)) + + var shouldBeEmptyInt64 option.Int64 + require.NoError(t, shouldBeEmptyInt64.DecodeMsgpack(dec)) + assert.False(t, shouldBeEmptyInt64.IsSome(), "Expected IsPresent() to return false") +} + +func TestOptionalUint(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + + enc := msgpack.NewEncoder(&buf) + dec := msgpack.NewDecoder(&buf) + + someUint := option.SomeUint(123) + assert.True(t, someUint.IsSome(), "Expected IsPresent() to return true") + require.NoError(t, someUint.EncodeMsgpack(enc)) + + var shouldBeSomeUint option.Uint + require.NoError(t, shouldBeSomeUint.DecodeMsgpack(dec)) + assert.True(t, shouldBeSomeUint.IsSome(), "Expected IsPresent() to return true") + assert.Equal(t, someUint.Unwrap(), shouldBeSomeUint.Unwrap(), "Expected Value() to return the same value") + + emptyUint := option.NoneUint() + assert.False(t, emptyUint.IsSome(), "Expected IsPresent() to return false") + require.NoError(t, emptyUint.EncodeMsgpack(enc)) + + var shouldBeEmptyUint option.Uint + require.NoError(t, shouldBeEmptyUint.DecodeMsgpack(dec)) + assert.False(t, shouldBeEmptyUint.IsSome(), "Expected IsPresent() to return false") +} + +func TestOptionalUint8(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + + enc := msgpack.NewEncoder(&buf) + dec := msgpack.NewDecoder(&buf) + + someUint8 := option.SomeUint8(123) + assert.True(t, someUint8.IsSome(), "Expected IsPresent() to return true") + require.NoError(t, someUint8.EncodeMsgpack(enc)) + + var shouldBeSomeUint8 option.Uint8 + require.NoError(t, shouldBeSomeUint8.DecodeMsgpack(dec)) + assert.True(t, shouldBeSomeUint8.IsSome(), "Expected IsPresent() to return true") + assert.Equal(t, someUint8.Unwrap(), shouldBeSomeUint8.Unwrap(), "Expected Value() to return the same value") + + emptyUint8 := option.NoneUint8() + assert.False(t, emptyUint8.IsSome(), "Expected IsPresent() to return false") + require.NoError(t, emptyUint8.EncodeMsgpack(enc)) + + var shouldBeEmptyUint8 option.Uint8 + require.NoError(t, shouldBeEmptyUint8.DecodeMsgpack(dec)) + assert.False(t, shouldBeEmptyUint8.IsSome(), "Expected IsPresent() to return false") +} + +func TestOptionalUint16(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + + enc := msgpack.NewEncoder(&buf) + dec := msgpack.NewDecoder(&buf) + + someUint16 := option.SomeUint16(123) + assert.True(t, someUint16.IsSome(), "Expected IsPresent() to return true") + require.NoError(t, someUint16.EncodeMsgpack(enc)) + + var shouldBeSomeUint16 option.Uint16 + require.NoError(t, shouldBeSomeUint16.DecodeMsgpack(dec)) + assert.True(t, shouldBeSomeUint16.IsSome(), "Expected IsPresent() to return true") + assert.Equal(t, someUint16.Unwrap(), shouldBeSomeUint16.Unwrap(), "Expected Value() to return the same value") + + emptyUint16 := option.NoneUint16() + assert.False(t, emptyUint16.IsSome(), "Expected IsPresent() to return false") + require.NoError(t, emptyUint16.EncodeMsgpack(enc)) + + var shouldBeEmptyUint16 option.Uint16 + require.NoError(t, shouldBeEmptyUint16.DecodeMsgpack(dec)) + assert.False(t, shouldBeEmptyUint16.IsSome(), "Expected IsPresent() to return false") +} + +func TestOptionalUint32(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + + enc := msgpack.NewEncoder(&buf) + dec := msgpack.NewDecoder(&buf) + + someUint32 := option.SomeUint32(123) + assert.True(t, someUint32.IsSome(), "Expected IsPresent() to return true") + require.NoError(t, someUint32.EncodeMsgpack(enc)) + + var shouldBeSomeUint32 option.Uint32 + require.NoError(t, shouldBeSomeUint32.DecodeMsgpack(dec)) + assert.True(t, shouldBeSomeUint32.IsSome(), "Expected IsPresent() to return true") + assert.Equal(t, someUint32.Unwrap(), shouldBeSomeUint32.Unwrap(), "Expected Value() to return the same value") + + emptyUint32 := option.NoneUint32() + assert.False(t, emptyUint32.IsSome(), "Expected IsPresent() to return false") + require.NoError(t, emptyUint32.EncodeMsgpack(enc)) + + var shouldBeEmptyUint32 option.Uint32 + require.NoError(t, shouldBeEmptyUint32.DecodeMsgpack(dec)) + assert.False(t, shouldBeEmptyUint32.IsSome(), "Expected IsPresent() to return false") +} + +func TestOptionalUint64(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + + enc := msgpack.NewEncoder(&buf) + dec := msgpack.NewDecoder(&buf) + + someUint64 := option.SomeUint64(123) + assert.True(t, someUint64.IsSome(), "Expected IsPresent() to return true") + require.NoError(t, someUint64.EncodeMsgpack(enc)) + + var shouldBeSomeUint64 option.Uint64 + require.NoError(t, shouldBeSomeUint64.DecodeMsgpack(dec)) + assert.True(t, shouldBeSomeUint64.IsSome(), "Expected IsPresent() to return true") + assert.Equal(t, someUint64.Unwrap(), shouldBeSomeUint64.Unwrap(), "Expected Value() to return the same value") + + emptyUint64 := option.NoneUint64() + assert.False(t, emptyUint64.IsSome(), "Expected IsPresent() to return false") + require.NoError(t, emptyUint64.EncodeMsgpack(enc)) + + var shouldBeEmptyUint64 option.Uint64 + require.NoError(t, shouldBeEmptyUint64.DecodeMsgpack(dec)) + assert.False(t, shouldBeEmptyUint64.IsSome(), "Expected IsPresent() to return false") +} diff --git a/string.go b/string.go new file mode 100644 index 0000000..9c715ae --- /dev/null +++ b/string.go @@ -0,0 +1,90 @@ +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type String struct { + value string + exists bool +} + +func SomeString(value string) String { + return String{ + value: value, + exists: true, + } +} + +func NoneString() String { + return String{ + exists: false, + value: zero[string](), + } +} + +func (o String) IsSome() bool { + return o.exists +} + +func (o String) IsZero() bool { + return !o.exists +} + +func (o String) Get() (string, bool) { + return o.value, o.exists +} + +func (o String) MustGet() string { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o String) Unwrap() string { + return o.value +} + +func (o String) UnwrapOr(defaultValue string) string { + if o.exists { + return o.value + } + return defaultValue +} + +func (o String) UnwrapOrElse(defaultValue func() string) string { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o String) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return encodeString(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *String) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case checkString(code): + o.exists = true + o.value, err = decodeString(decoder) + return err + default: + return newFailedToDecodeError("String", code) + } +} diff --git a/string_test.go b/string_test.go new file mode 100644 index 0000000..1ee6a4c --- /dev/null +++ b/string_test.go @@ -0,0 +1,38 @@ +package option_test + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/vmihailenco/msgpack/v5" + + "github.com/tarantool/go-option" +) + +func TestOptionalString(t *testing.T) { + t.Parallel() + + var buf bytes.Buffer + + enc := msgpack.NewEncoder(&buf) + dec := msgpack.NewDecoder(&buf) + + someString := option.SomeString("value-string") + assert.True(t, someString.IsSome(), "Expected IsPresent() to return true") + require.NoError(t, someString.EncodeMsgpack(enc)) + + var shouldBeSomeString option.String + require.NoError(t, shouldBeSomeString.DecodeMsgpack(dec)) + assert.True(t, shouldBeSomeString.IsSome(), "Expected IsPresent() to return true") + assert.Equal(t, someString.Unwrap(), shouldBeSomeString.Unwrap(), "Expected Value() to return the same value") + + emptyString := option.NoneString() + assert.False(t, emptyString.IsSome(), "Expected IsPresent() to return false") + require.NoError(t, emptyString.EncodeMsgpack(enc)) + + var shouldBeEmptyString option.String + require.NoError(t, shouldBeEmptyString.DecodeMsgpack(dec)) + assert.False(t, shouldBeEmptyString.IsSome(), "Expected IsPresent() to return false") +} diff --git a/uint.go b/uint.go new file mode 100644 index 0000000..bee65e1 --- /dev/null +++ b/uint.go @@ -0,0 +1,90 @@ +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type Uint struct { + value uint + exists bool +} + +func SomeUint(value uint) Uint { + return Uint{ + value: value, + exists: true, + } +} + +func NoneUint() Uint { + return Uint{ + exists: false, + value: zero[uint](), + } +} + +func (o Uint) IsSome() bool { + return o.exists +} + +func (o Uint) IsZero() bool { + return !o.exists +} + +func (o Uint) Get() (uint, bool) { + return o.value, o.exists +} + +func (o Uint) MustGet() uint { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o Uint) Unwrap() uint { + return o.value +} + +func (o Uint) UnwrapOr(defaultValue uint) uint { + if o.exists { + return o.value + } + return defaultValue +} + +func (o Uint) UnwrapOrElse(defaultValue func() uint) uint { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o Uint) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return encodeUint(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *Uint) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case checkNumber(code): + o.exists = true + o.value, err = decodeUint(decoder) + return err + default: + return newFailedToDecodeError("Uint", code) + } +} diff --git a/uint16.go b/uint16.go new file mode 100644 index 0000000..6f30597 --- /dev/null +++ b/uint16.go @@ -0,0 +1,90 @@ +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type Uint16 struct { + value uint16 + exists bool +} + +func SomeUint16(value uint16) Uint16 { + return Uint16{ + value: value, + exists: true, + } +} + +func NoneUint16() Uint16 { + return Uint16{ + exists: false, + value: zero[uint16](), + } +} + +func (o Uint16) IsSome() bool { + return o.exists +} + +func (o Uint16) IsZero() bool { + return !o.exists +} + +func (o Uint16) Get() (uint16, bool) { + return o.value, o.exists +} + +func (o Uint16) MustGet() uint16 { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o Uint16) Unwrap() uint16 { + return o.value +} + +func (o Uint16) UnwrapOr(defaultValue uint16) uint16 { + if o.exists { + return o.value + } + return defaultValue +} + +func (o Uint16) UnwrapOrElse(defaultValue func() uint16) uint16 { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o Uint16) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return encodeUint16(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *Uint16) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case checkNumber(code): + o.exists = true + o.value, err = decodeUint16(decoder) + return err + default: + return newFailedToDecodeError("Uint16", code) + } +} diff --git a/uint32.go b/uint32.go new file mode 100644 index 0000000..b2da282 --- /dev/null +++ b/uint32.go @@ -0,0 +1,90 @@ +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type Uint32 struct { + value uint32 + exists bool +} + +func SomeUint32(value uint32) Uint32 { + return Uint32{ + value: value, + exists: true, + } +} + +func NoneUint32() Uint32 { + return Uint32{ + exists: false, + value: zero[uint32](), + } +} + +func (o Uint32) IsSome() bool { + return o.exists +} + +func (o Uint32) IsZero() bool { + return !o.exists +} + +func (o Uint32) Get() (uint32, bool) { + return o.value, o.exists +} + +func (o Uint32) MustGet() uint32 { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o Uint32) Unwrap() uint32 { + return o.value +} + +func (o Uint32) UnwrapOr(defaultValue uint32) uint32 { + if o.exists { + return o.value + } + return defaultValue +} + +func (o Uint32) UnwrapOrElse(defaultValue func() uint32) uint32 { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o Uint32) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return encodeUint32(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *Uint32) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case checkNumber(code): + o.exists = true + o.value, err = decodeUint32(decoder) + return err + default: + return newFailedToDecodeError("Uint32", code) + } +} diff --git a/uint64.go b/uint64.go new file mode 100644 index 0000000..38b5116 --- /dev/null +++ b/uint64.go @@ -0,0 +1,90 @@ +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type Uint64 struct { + value uint64 + exists bool +} + +func SomeUint64(value uint64) Uint64 { + return Uint64{ + value: value, + exists: true, + } +} + +func NoneUint64() Uint64 { + return Uint64{ + exists: false, + value: zero[uint64](), + } +} + +func (o Uint64) IsSome() bool { + return o.exists +} + +func (o Uint64) IsZero() bool { + return !o.exists +} + +func (o Uint64) Get() (uint64, bool) { + return o.value, o.exists +} + +func (o Uint64) MustGet() uint64 { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o Uint64) Unwrap() uint64 { + return o.value +} + +func (o Uint64) UnwrapOr(defaultValue uint64) uint64 { + if o.exists { + return o.value + } + return defaultValue +} + +func (o Uint64) UnwrapOrElse(defaultValue func() uint64) uint64 { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o Uint64) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return encodeUint64(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *Uint64) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case checkNumber(code): + o.exists = true + o.value, err = decodeUint64(decoder) + return err + default: + return newFailedToDecodeError("Uint64", code) + } +} diff --git a/uint8.go b/uint8.go new file mode 100644 index 0000000..9099dfc --- /dev/null +++ b/uint8.go @@ -0,0 +1,90 @@ +// Code generated by github.com/tarantool/go-option; DO NOT EDIT. + +package option + +import ( + "github.com/vmihailenco/msgpack/v5" + "github.com/vmihailenco/msgpack/v5/msgpcode" +) + +type Uint8 struct { + value uint8 + exists bool +} + +func SomeUint8(value uint8) Uint8 { + return Uint8{ + value: value, + exists: true, + } +} + +func NoneUint8() Uint8 { + return Uint8{ + exists: false, + value: zero[uint8](), + } +} + +func (o Uint8) IsSome() bool { + return o.exists +} + +func (o Uint8) IsZero() bool { + return !o.exists +} + +func (o Uint8) Get() (uint8, bool) { + return o.value, o.exists +} + +func (o Uint8) MustGet() uint8 { + if o.exists { + panic("optional value is not set") + } + return o.value +} + +func (o Uint8) Unwrap() uint8 { + return o.value +} + +func (o Uint8) UnwrapOr(defaultValue uint8) uint8 { + if o.exists { + return o.value + } + return defaultValue +} + +func (o Uint8) UnwrapOrElse(defaultValue func() uint8) uint8 { + if o.exists { + return o.value + } + return defaultValue() +} + +func (o Uint8) EncodeMsgpack(encoder *msgpack.Encoder) error { + if o.exists { + return encodeUint8(encoder, o.value) + } + return encoder.EncodeNil() +} + +func (o *Uint8) DecodeMsgpack(decoder *msgpack.Decoder) error { + code, err := decoder.PeekCode() + if err != nil { + return err + } + + switch { + case code == msgpcode.Nil: + o.exists = false + return decoder.Skip() + case checkNumber(code): + o.exists = true + o.value, err = decodeUint8(decoder) + return err + default: + return newFailedToDecodeError("Uint8", code) + } +}