-
Notifications
You must be signed in to change notification settings - Fork 0
/
optional.go
116 lines (98 loc) · 2.17 KB
/
optional.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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package optional
import (
"encoding/json"
"errors"
)
type Type[T any] struct {
/** Why we use an interface{} type here? Why not a *T?
Both *T and interface{} type cloud represent a nil value. But if the real
content of wrapped is a nil value of an interface type, we want optional.Type to
be Nil. `*T` is hard to implement this behavior.
*/
wrapped interface{}
}
func (s Type[T]) IsNil() bool {
return s.wrapped == nil
}
// ForceValue returns the wrapped content if not nil, or it will panic
func (s Type[T]) ForceValue() T {
return s.wrapped.(T)
}
// Value is a golang style unwrapping method
func (s Type[T]) Value() (v T, ok bool) {
if s.IsNil() {
ok = false
} else {
ok = true
v = s.ForceValue()
}
return
}
// ValueOrDefault return d if IsNil
func (s Type[T]) ValueOrDefault(d T) T {
if w, ok := s.Value(); ok {
return w
} else {
return d
}
}
// ValueOrLazyDefault return f() if IsNil
func (s Type[T]) ValueOrLazyDefault(f func() T) T {
if w, ok := s.Value(); ok {
return w
} else {
return f()
}
}
// --- initializer ---
// New returns an optional.Type. It doesn't always return a non-nil value. If
// wrapped is a nil value of interface type, it will return Nil
func New[T any](wrapped T) Type[T] {
return Type[T]{wrapped: wrapped}
}
// Nil return a Nil optional.Type, whose IsNil() is true
func Nil[T any]() Type[T] {
return Type[T]{}
}
func Compact[T any](wrapped Type[Type[T]]) Type[T] {
if w, ok := wrapped.Value(); ok {
return w
} else {
return Nil[T]()
}
}
func Map[T, U any](v Type[T], f func(T) U) Type[U] {
if w, ok := v.Value(); ok {
return New(f(w))
} else {
return Nil[U]()
}
}
// ---
func FromPtr[T any](wrapped *T) Type[T] {
if wrapped == nil {
return Nil[T]()
} else {
return New[T](*wrapped)
}
}
// -- Marshaler and Unmarshaler ---
func (s Type[T]) MarshalJSON() ([]byte, error) {
if w, ok := s.Value(); ok {
return json.Marshal(w)
} else {
return json.Marshal(nil)
}
}
func (s *Type[T]) UnmarshalJSON(data []byte) error {
if s == nil {
return errors.New("optional.Type: UnmarshalJSON on nil pointer")
}
var w *T
err := json.Unmarshal(data, &w)
if err != nil {
return err
}
*s = FromPtr(w)
return nil
}