vendor
This commit is contained in:
parent
07ec5529ac
commit
f501abe660
532 changed files with 271781 additions and 0 deletions
399
vendor/github.com/samber/mo/option.go
generated
vendored
Normal file
399
vendor/github.com/samber/mo/option.go
generated
vendored
Normal file
|
|
@ -0,0 +1,399 @@
|
|||
package mo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var errOptionNoSuchElement = fmt.Errorf("no such element")
|
||||
|
||||
type zeroer interface {
|
||||
IsZero() bool
|
||||
}
|
||||
|
||||
// Some builds an Option when value is present.
|
||||
// Play: https://go.dev/play/p/iqz2n9n0tDM
|
||||
func Some[T any](value T) Option[T] {
|
||||
return Option[T]{
|
||||
isPresent: true,
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
// None builds an Option when value is absent.
|
||||
// Play: https://go.dev/play/p/yYQPsYCSYlD
|
||||
func None[T any]() Option[T] {
|
||||
return Option[T]{
|
||||
isPresent: false,
|
||||
}
|
||||
}
|
||||
|
||||
// TupleToOption builds a Some Option when second argument is true, or None.
|
||||
// Play: https://go.dev/play/p/gkrg2pZwOty
|
||||
func TupleToOption[T any](value T, ok bool) Option[T] {
|
||||
if ok {
|
||||
return Some(value)
|
||||
}
|
||||
return None[T]()
|
||||
}
|
||||
|
||||
// EmptyableToOption builds a Some Option when value is not empty, or None.
|
||||
// Play: https://go.dev/play/p/GSpQQ-q-UES
|
||||
func EmptyableToOption[T any](value T) Option[T] {
|
||||
// 🤮
|
||||
isZero := reflect.ValueOf(&value).Elem().IsZero()
|
||||
if isZero {
|
||||
return None[T]()
|
||||
}
|
||||
|
||||
return Some(value)
|
||||
}
|
||||
|
||||
// PointerToOption builds a Some Option when value is not nil, or None.
|
||||
// Play: https://go.dev/play/p/yPVMj4DUb-I
|
||||
func PointerToOption[T any](value *T) Option[T] {
|
||||
if value == nil {
|
||||
return None[T]()
|
||||
}
|
||||
|
||||
return Some(*value)
|
||||
}
|
||||
|
||||
// Option is a container for an optional value of type T. If value exists, Option is
|
||||
// of type Some. If the value is absent, Option is of type None.
|
||||
type Option[T any] struct {
|
||||
isPresent bool
|
||||
value T
|
||||
}
|
||||
|
||||
// IsPresent returns false when value is absent.
|
||||
// Play: https://go.dev/play/p/nDqIaiihyCA
|
||||
func (o Option[T]) IsPresent() bool {
|
||||
return o.isPresent
|
||||
}
|
||||
|
||||
// IsSome is an alias to IsPresent.
|
||||
// Play: https://go.dev/play/p/DyvGRy7fP9m
|
||||
func (o Option[T]) IsSome() bool {
|
||||
return o.IsPresent()
|
||||
}
|
||||
|
||||
// IsAbsent returns false when value is present.
|
||||
// Play: https://go.dev/play/p/23e2zqyVOQm
|
||||
func (o Option[T]) IsAbsent() bool {
|
||||
return !o.isPresent
|
||||
}
|
||||
|
||||
// IsNone is an alias to IsAbsent.
|
||||
// Play: https://go.dev/play/p/EdqxKhborIP
|
||||
func (o Option[T]) IsNone() bool {
|
||||
return o.IsAbsent()
|
||||
}
|
||||
|
||||
// Size returns 1 when value is present or 0 instead.
|
||||
// Play: https://go.dev/play/p/7ixCNG1E9l7
|
||||
func (o Option[T]) Size() int {
|
||||
if o.isPresent {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// Get returns value and presence.
|
||||
// Play: https://go.dev/play/p/0-JBa1usZRT
|
||||
func (o Option[T]) Get() (T, bool) {
|
||||
if !o.isPresent {
|
||||
return empty[T](), false
|
||||
}
|
||||
|
||||
return o.value, true
|
||||
}
|
||||
|
||||
// MustGet returns value if present or panics instead.
|
||||
// Play: https://go.dev/play/p/RVBckjdi5WR
|
||||
func (o Option[T]) MustGet() T {
|
||||
if !o.isPresent {
|
||||
panic(errOptionNoSuchElement)
|
||||
}
|
||||
|
||||
return o.value
|
||||
}
|
||||
|
||||
// OrElse returns value if present or default value.
|
||||
// Play: https://go.dev/play/p/TrGByFWCzXS
|
||||
func (o Option[T]) OrElse(fallback T) T {
|
||||
if !o.isPresent {
|
||||
return fallback
|
||||
}
|
||||
|
||||
return o.value
|
||||
}
|
||||
|
||||
// OrEmpty returns value if present or empty value.
|
||||
// Play: https://go.dev/play/p/SpSUJcE-tQm
|
||||
func (o Option[T]) OrEmpty() T {
|
||||
return o.value
|
||||
}
|
||||
|
||||
// ForEach executes the given side-effecting function of value is present.
|
||||
func (o Option[T]) ForEach(onValue func(value T)) {
|
||||
if o.isPresent {
|
||||
onValue(o.value)
|
||||
}
|
||||
}
|
||||
|
||||
// Match executes the first function if value is present and second function if absent.
|
||||
// It returns a new Option.
|
||||
// Play: https://go.dev/play/p/1V6st3LDJsM
|
||||
func (o Option[T]) Match(onValue func(value T) (T, bool), onNone func() (T, bool)) Option[T] {
|
||||
if o.isPresent {
|
||||
return TupleToOption(onValue(o.value))
|
||||
}
|
||||
return TupleToOption(onNone())
|
||||
}
|
||||
|
||||
// Map executes the mapper function if value is present or returns None if absent.
|
||||
// Play: https://go.dev/play/p/mvfP3pcP_eJ
|
||||
func (o Option[T]) Map(mapper func(value T) (T, bool)) Option[T] {
|
||||
if o.isPresent {
|
||||
return TupleToOption(mapper(o.value))
|
||||
}
|
||||
|
||||
return None[T]()
|
||||
}
|
||||
|
||||
// MapNone executes the mapper function if value is absent or returns Option.
|
||||
// Play: https://go.dev/play/p/_KaHWZ6Q17b
|
||||
func (o Option[T]) MapNone(mapper func() (T, bool)) Option[T] {
|
||||
if o.isPresent {
|
||||
return Some(o.value)
|
||||
}
|
||||
|
||||
return TupleToOption(mapper())
|
||||
}
|
||||
|
||||
// FlatMap executes the mapper function if value is present or returns None if absent.
|
||||
// Play: https://go.dev/play/p/OXO-zJx6n5r
|
||||
func (o Option[T]) FlatMap(mapper func(value T) Option[T]) Option[T] {
|
||||
if o.isPresent {
|
||||
return mapper(o.value)
|
||||
}
|
||||
|
||||
return None[T]()
|
||||
}
|
||||
|
||||
// MapValue executes the mapper function if value is present or returns None if absent.
|
||||
func (o Option[T]) MapValue(mapper func(value T) T) Option[T] {
|
||||
if o.isPresent {
|
||||
return Some(mapper(o.value))
|
||||
}
|
||||
|
||||
return None[T]()
|
||||
}
|
||||
|
||||
// ToPointer returns value if present or a nil pointer.
|
||||
// Play: https://go.dev/play/p/N43w92SM-Bs
|
||||
func (o Option[T]) ToPointer() *T {
|
||||
if !o.isPresent {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &o.value
|
||||
}
|
||||
|
||||
// MarshalJSON encodes Option into json.
|
||||
// Go 1.20+ relies on the IsZero method when the `omitempty` tag is used
|
||||
// unless a custom MarshalJSON method is defined. Then the IsZero method is ignored.
|
||||
// current best workaround is to instead use `omitzero` tag with Go 1.24+
|
||||
func (o Option[T]) MarshalJSON() ([]byte, error) {
|
||||
if o.isPresent {
|
||||
return json.Marshal(o.value)
|
||||
}
|
||||
|
||||
return json.Marshal(nil)
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes Option from json.
|
||||
func (o *Option[T]) UnmarshalJSON(b []byte) error {
|
||||
o.value = empty[T]() // reset the value if not set later.
|
||||
|
||||
// If user manually set the field to be `null`, then it either means the option is absent or present with a zero value.
|
||||
if bytes.Equal([]byte("null"), bytes.ToLower(b)) {
|
||||
// // If the type is a pointer, then it means the option is present with a zero value.
|
||||
// o.isPresent = reflect.TypeOf(o.value).Kind() == reflect.Ptr
|
||||
// return nil
|
||||
|
||||
o.isPresent = false
|
||||
return nil
|
||||
}
|
||||
|
||||
err := json.Unmarshal(b, &o.value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.isPresent = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsZero assists `omitzero` tag introduced in Go 1.24
|
||||
func (o Option[T]) IsZero() bool {
|
||||
if !o.isPresent {
|
||||
return true
|
||||
}
|
||||
|
||||
var v any = o.value
|
||||
if v, ok := v.(zeroer); ok {
|
||||
return v.IsZero()
|
||||
}
|
||||
|
||||
return reflect.ValueOf(o.value).IsZero()
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
func (o Option[T]) MarshalText() ([]byte, error) {
|
||||
return json.Marshal(o)
|
||||
}
|
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
func (o *Option[T]) UnmarshalText(data []byte) error {
|
||||
return json.Unmarshal(data, o)
|
||||
}
|
||||
|
||||
// MarshalBinary is the interface implemented by an object that can marshal itself into a binary form.
|
||||
func (o Option[T]) MarshalBinary() ([]byte, error) {
|
||||
if !o.isPresent {
|
||||
return []byte{0}, nil
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
enc := gob.NewEncoder(&buf)
|
||||
if err := enc.Encode(o.value); err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
return append([]byte{1}, buf.Bytes()...), nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary is the interface implemented by an object that can unmarshal a binary representation of itself.
|
||||
func (o *Option[T]) UnmarshalBinary(data []byte) error {
|
||||
if len(data) == 0 {
|
||||
return errors.New("Option[T].UnmarshalBinary: no data")
|
||||
}
|
||||
|
||||
if data[0] == 0 {
|
||||
o.isPresent = false
|
||||
o.value = empty[T]()
|
||||
return nil
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(data[1:])
|
||||
dec := gob.NewDecoder(buf)
|
||||
err := dec.Decode(&o.value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.isPresent = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// GobEncode implements the gob.GobEncoder interface.
|
||||
func (o Option[T]) GobEncode() ([]byte, error) {
|
||||
return o.MarshalBinary()
|
||||
}
|
||||
|
||||
// GobDecode implements the gob.GobDecoder interface.
|
||||
func (o *Option[T]) GobDecode(data []byte) error {
|
||||
return o.UnmarshalBinary(data)
|
||||
}
|
||||
|
||||
// Scan implements the SQL sql.Scanner interface.
|
||||
func (o *Option[T]) Scan(src any) error {
|
||||
if src == nil {
|
||||
o.isPresent = false
|
||||
o.value = empty[T]()
|
||||
return nil
|
||||
}
|
||||
|
||||
// is is only possible to assert interfaces, so convert first
|
||||
// https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#why-not-permit-type-assertions-on-values-whose-type-is-a-type-parameter
|
||||
var t T
|
||||
if tScanner, ok := interface{}(&t).(sql.Scanner); ok {
|
||||
if err := tScanner.Scan(src); err != nil {
|
||||
return fmt.Errorf("failed to scan: %w", err)
|
||||
}
|
||||
|
||||
o.isPresent = true
|
||||
o.value = t
|
||||
return nil
|
||||
}
|
||||
|
||||
if av, err := driver.DefaultParameterConverter.ConvertValue(src); err == nil {
|
||||
if v, ok := av.(T); ok {
|
||||
o.isPresent = true
|
||||
o.value = v
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return o.scanConvertValue(src)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (o Option[T]) Value() (driver.Value, error) {
|
||||
if !o.isPresent {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return driver.DefaultParameterConverter.ConvertValue(o.value)
|
||||
}
|
||||
|
||||
// Equal compares two Option[T] instances for equality
|
||||
func (o Option[T]) Equal(other Option[T]) bool {
|
||||
if !o.isPresent && !other.isPresent {
|
||||
return true
|
||||
}
|
||||
|
||||
if o.isPresent != other.isPresent {
|
||||
return false
|
||||
}
|
||||
|
||||
return reflect.DeepEqual(o.value, other.value)
|
||||
}
|
||||
|
||||
// leftValue returns an error if the Option is None, otherwise nil
|
||||
//
|
||||
//nolint:unused
|
||||
func (o Option[T]) leftValue() error {
|
||||
if !o.isPresent {
|
||||
return errOptionNoSuchElement
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// rightValue returns the value if the Option is Some, otherwise the zero value of T
|
||||
//
|
||||
//nolint:unused
|
||||
func (o Option[T]) rightValue() T {
|
||||
if !o.isPresent {
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
return o.value
|
||||
}
|
||||
|
||||
// hasLeftValue returns true if the Option represents a None state
|
||||
//
|
||||
//nolint:unused
|
||||
func (o Option[T]) hasLeftValue() bool {
|
||||
return !o.isPresent
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue