-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtypes.go
More file actions
174 lines (147 loc) · 3.74 KB
/
types.go
File metadata and controls
174 lines (147 loc) · 3.74 KB
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package promise
import (
"fmt"
"sync"
"sync/atomic"
)
type State int
const (
Pending State = iota
Fulfilled
Rejected
)
type ErrorType int
const (
RejectionError ErrorType = iota // Promise rejected
PanicError // Panic occurred in callback
TimeoutError // Promise timeout
ManagerError // Manager-related errors
)
type PromiseError struct {
Message string // Human-readable error message
Cause error // Original error that caused this
Type ErrorType // Type of error
Value interface{} // Original panic value (for non-error panics)
OriginalError error // Original error being processed (for error callbacks)
}
// Error implements the error interface
func (e *PromiseError) Error() string {
if e.Cause != nil {
return fmt.Sprintf("%s: %v", e.Message, e.Cause)
}
if e.Value != nil {
return fmt.Sprintf("%s: %v", e.Message, e.Value)
}
return e.Message
}
// Unwrap returns the cause error for error wrapping
func (e *PromiseError) Unwrap() error {
return e.Cause
}
// Is implements error comparison
func (e *PromiseError) Is(target error) bool {
if target == nil {
return e == nil
}
if promiseErr, ok := target.(*PromiseError); ok {
return e.Type == promiseErr.Type
}
return false
}
// As implements error type assertion
func (e *PromiseError) As(target interface{}) bool {
if target == nil {
return false
}
switch t := target.(type) {
case **PromiseError:
*t = e
return true
case *ErrorType:
*t = e.Type
return true
}
return false
}
type Promise[T any] struct {
// Atomic state and value management
state atomic.Value // State
value atomic.Value // T
err atomic.Value // error
// Protected by mutex
handlers []*handler[T]
mu sync.RWMutex
done chan struct{} // Signal channel for completion
// Associated manager
manager *PromiseMgr
}
// Helper function: safely get state
func (p *Promise[T]) getState() State {
if state, ok := p.state.Load().(State); ok {
return state
}
return Pending
}
// Helper function: safely set state
func (p *Promise[T]) setState(state State) bool {
// Use atomic operation to ensure only one goroutine can set the state
// First, try to initialize to Pending if not already set
for {
currentState := p.state.Load()
if currentState == nil {
// Try to initialize to Pending
if p.state.CompareAndSwap(nil, Pending) {
break // Successfully initialized
}
continue // Another goroutine initialized, retry
}
break // Already initialized
}
// Now try to transition from Pending to target state
return p.state.CompareAndSwap(Pending, state)
}
// Helper function: safely get value
func (p *Promise[T]) getValue() (T, bool) {
if ptr, ok := p.value.Load().(*T); ok && ptr != nil {
return *ptr, true
}
var zero T
return zero, false
}
// Helper function: safely set value
func (p *Promise[T]) setValue(value T) {
// Use pointer wrapper to safely store nil values in atomic.Value
// Allocate a new value on heap to avoid issues with local variable addresses
ptr := new(T)
*ptr = value
p.value.Store(ptr)
}
// Helper function: safely get error
func (p *Promise[T]) getError() (error, bool) {
if err, ok := p.err.Load().(error); ok {
return err, true
}
return nil, false
}
// Helper function: safely set error
func (p *Promise[T]) setError(err error) {
p.err.Store(err)
}
type handler[T any] struct {
onFulfilled func(T) any
onRejected func(error) any
next *Promise[any]
}
type Result[T any] struct {
Value T
Error error
Index int
}
// Predefined errors for common scenarios
var (
// ErrManagerStopped is returned when trying to use a stopped manager
ErrManagerStopped = &PromiseError{
Message: "manager is stopped",
Type: ManagerError,
}
)