-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgoption.go
86 lines (72 loc) · 1.9 KB
/
goption.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package goption
import (
"errors"
"reflect"
)
var (
ErrNoSuchElement = errors.New("no value in this optional")
)
type Optional[T any] struct {
value T
isValidValue bool
}
// Empty returns an empty Optional instance.
func Empty[T any]() Optional[T] {
return Optional[T]{}
}
// Of returns an Optional with the specified present value. It does not matters if value is nil
func Of[T any](value T) Optional[T] {
return Optional[T]{value: value, isValidValue: getIsValidDataBool(value)}
}
// Get when a value is present returns the value, otherwise throws ErrNoSuchElement.
func (c Optional[T]) Get() (T, error) {
if !c.isValidValue {
return c.value, ErrNoSuchElement
}
return c.value, nil
}
// IsPresent returns true if there is a value present, otherwise false. It recognizes an empty slice as not present so it returns false
func (c Optional[T]) IsPresent() bool {
return c.isValidValue
}
// OrElseError return the contained value, if present, otherwise returns the given error.
func (c Optional[T]) OrElseError(err error) (T, error) {
if !c.isValidValue {
return c.value, err
}
return c.value, nil
}
// OrElse returns the value if present, otherwise return other.
func (c Optional[T]) OrElse(other T) T {
if !c.isValidValue {
return other
}
return c.value
}
// MustGet retrieves only a valid value. If is not present it panics with ErrNoSuchElement
func (c Optional[T]) MustGet() T {
val, err := c.Get()
if err != nil {
panic(err)
}
return val
}
func isValidData[T any](value T) (reflect.Value, bool) {
typeOfValue := reflect.TypeOf(value)
if typeOfValue == nil {
return reflect.Value{}, false
}
val := reflect.ValueOf(value)
switch typeOfValue.Kind() {
case reflect.Pointer:
return val, !val.IsNil()
case reflect.Slice:
return val, val.Len() != 0
default:
return val, !val.IsZero()
}
}
func getIsValidDataBool[T any](value T) bool {
_, is := isValidData(value)
return is
}