-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathopzione.go
86 lines (74 loc) · 2.48 KB
/
opzione.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 opzione provides operations with optional values.
package opzione
import (
"errors"
"reflect"
)
var ErrNoneOptional = errors.New("optional value is none")
type Optional[T interface{}] interface {
// IsNone reports whether the current optional contains no meaningful value.
// A value is meaningful if it is not a nil pointer or nested pointers that
// ultimately dereference to nil.
IsNone() bool
// Value tries to obtain the contained value. If the optional contains
// no value, it returns ErrNoneOptional.
Value() (t T, err error)
// Unwrap obtains the contained value, and panics if the optional
// contains no value.
Unwrap() T
// Swap swaps value v with the optional's contained value. Swap returns
// the original value, with no guarantee that it will be present.
Swap(v T) T
// Take attempts to move out the optional's contained value.
// If the optional is None, it returns ErrNoneOptional.
Take() (*T, error)
// With accepts a closure which will be executed with the optional's
// contained value, only if it contains any.
With(func(T))
// WithNone executes the given closure if the optional currently contains
// no value.
WithNone(func())
// Assign assigns the optional's contained value to *p, if the optional
// is not None.
Assign(p **T) bool
}
// Some constructs an Option with value. It panics if v is a nil pointer
// or a nested pointer to nil, with nil slices being an exception.
func Some[T any](v T) *Option[T] {
val, ok := isptr(v)
if ok {
if isnil(val) {
panic("nil pointer cannot be used to construct Some")
}
switch val.Kind() {
case reflect.UnsafePointer:
// Only responsible for the topmost reference.
return &Option[T]{v: &v, ptrtyp: true, track: false}
case reflect.Pointer, reflect.Interface:
// If v is a simple pointer, there is no need to resort to
// reflection.
tr := isptrkind(val.Elem().Kind())
return &Option[T]{v: &v, ptrtyp: true, track: tr}
default:
return &Option[T]{v: &v, ptrtyp: true, track: true}
}
}
return &Option[T]{v: &v, ptrtyp: false, track: false}
}
// None constructs an Option with no value.
func None[T any]() *Option[T] {
var t T
val, ok := isptr(t)
if ok {
switch val.Kind() {
case reflect.UnsafePointer:
return &Option[T]{ptrtyp: true, track: false}
case reflect.Pointer, reflect.Interface:
tr := isptrkind(val.Elem().Kind())
return &Option[T]{ptrtyp: true, track: tr}
default:
return &Option[T]{ptrtyp: true, track: true}
}
}
return &Option[T]{track: false}
}