-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathoption.go
155 lines (130 loc) · 3.11 KB
/
option.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package goption
import "iter"
// Option represents a value whose presence is optional.
type Option[T any] struct {
t T
ok bool
}
// Unwrap forcefully unwraps the Optional value.
// If the optional is not ok this function will panic.
func (o Option[T]) Unwrap() T {
return o.Expect("Unwrapped empty optional")
}
// UnwrapRef returns a reference to the underlying T.
func (o *Option[T]) UnwrapRef() *T {
return o.ExpectRef("Unwrapped empty optional")
}
// Expect unwraps o and panics with msg if it's empty.
func (o Option[T]) Expect(msg string) T {
if !o.ok {
panic(msg)
}
return o.t
}
// ExpectRef unwraps o and panics with msg if it's empty.
func (o *Option[T]) ExpectRef(msg string) *T {
if !o.ok {
panic(msg)
}
return &o.t
}
// UnwrapOr unwraps the optional if it's present, otherwise it returns default.
func (o Option[T]) UnwrapOr(def T) T {
if !o.ok {
return def
}
return o.t
}
// UnwrapOrDefault unwraps T if it's present, otherwise it returns the default
// value for T.
func (o Option[T]) UnwrapOrDefault() T {
var def T
return o.UnwrapOr(def)
}
// UnwrapRefOr returns a reference if optional is present, otherwise it returns default.
func (o *Option[T]) UnwrapRefOr(def *T) *T {
if !o.ok {
return def
}
return &o.t
}
// UnwrapRefOrNil returns a reference if optional is present, otherwise it returns nil.
func (o *Option[T]) UnwrapRefOrNil() *T {
var def *T
return o.UnwrapRefOr(def)
}
// Ok returns if the optional is present.
func (o Option[T]) Ok() bool {
return o.ok
}
// Get returns the underlying value and a boolean indicating if it's present.
func (o Option[T]) Get() (T, bool) {
return o.t, o.ok
}
// Some returns an Option whose underlying value is present.
func Some[T any](t T) Option[T] {
return Option[T]{
t: t,
ok: true,
}
}
// None returns an empty optional value.
func None[T any]() Option[T] {
return Option[T]{
ok: false,
}
}
// FromRef returns an Option whose underlying value is present if t is not nil.
// Otherwise, it returns an empty optional value.
func FromRef[T any](t *T) Option[T] {
if t == nil {
return None[T]()
}
return Some(*t)
}
// Apply f to the optional value.
func Apply[In, Out any](in Option[In], f func(In) Out) Option[Out] {
if !in.ok {
return None[Out]()
}
return Some(f(in.t))
}
// Do runs the function f which may panic.
// If f does not panic Some(f()) is returned.
// Otherwise none is returned.
func Do[T any](f func() T) (o Option[T]) {
defer func() {
if r := recover(); r != nil {
o = None[T]()
}
}()
o = Some(f())
return
}
// With allows you to use the optional value in it's own scope.
// For example:
//
// opt := Some(3)
//
// for range value := opt.With() {
// fmt.Println(value)
// }
//
// This is a hack on the iter.Seq interface.
func (o *Option[T]) With() iter.Seq[T] {
return func(yield func(T) bool) {
if o.ok {
yield(o.t)
}
}
}
// IsZero returns true if o is not present.
// This is for use with encoding/json in go1.24+.
func (o *Option[T]) IsZero() bool {
if o.ok {
if isZeroer, wrapsIsZeroer := (any(o.t)).(interface{ IsZero() bool }); wrapsIsZeroer {
return isZeroer.IsZero()
}
}
return false
}