-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathoptions.go
More file actions
149 lines (135 loc) · 3.33 KB
/
Copy pathoptions.go
File metadata and controls
149 lines (135 loc) · 3.33 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
package options
import (
"context"
"maps"
"sync"
)
// SupportPackageIsVersion1 is a compile-time assertion constant.
// Downstream packages reference this to enforce version compatibility.
const SupportPackageIsVersion1 = true
type contextKey string
// Options are request options passed from ColdBrew to server.
// Uses RWMutex + map instead of sync.Map since Options is per-request
// and never shared across goroutines.
type Options struct {
mu sync.RWMutex
m map[string]any
}
// FromContext fetches options from provided context.
// If no options are found, it returns nil.
func FromContext(ctx context.Context) *Options {
if rc := RequestContextFromContext(ctx); rc != nil {
return rc.opts
}
return nil
}
// AddToOptions adds a key-value pair to the Options stored in ctx.
// If no Options exists in the context, a new one is created.
// Empty keys are silently ignored and do not allocate.
func AddToOptions(ctx context.Context, key string, value any) context.Context {
if key == "" {
return ctx
}
ctx, rc := getOrCreateRequestContext(ctx)
rc.Opts().Add(key, value)
return ctx
}
// Add adds a key-value pair to Options.
// Empty keys are silently ignored.
func (o *Options) Add(key string, value any) {
if key == "" {
return
}
o.mu.Lock()
if o.m == nil {
o.m = make(map[string]any, 2)
}
o.m[key] = value
o.mu.Unlock()
}
// Del deletes an option by key.
func (o *Options) Del(key string) {
o.mu.Lock()
if o.m != nil {
delete(o.m, key)
}
o.mu.Unlock()
}
// Get retrieves an option value by key.
func (o *Options) Get(key string) (any, bool) {
if o == nil {
return nil, false
}
o.mu.RLock()
if o.m == nil {
o.mu.RUnlock()
return nil, false
}
v, found := o.m[key]
o.mu.RUnlock()
return v, found
}
// Store is a sync.Map-compatible alias for Add.
// Only string keys are supported; non-string keys are silently ignored.
func (o *Options) Store(key, value any) {
if k, ok := key.(string); ok {
o.Add(k, value)
}
}
// Load is a sync.Map-compatible alias for Get.
// Only string keys are supported; non-string keys return (nil, false).
func (o *Options) Load(key any) (any, bool) {
if k, ok := key.(string); ok {
return o.Get(k)
}
return nil, false
}
// Delete is a sync.Map-compatible alias for Del.
// Only string keys are supported; non-string keys are silently ignored.
func (o *Options) Delete(key any) {
if k, ok := key.(string); ok {
o.Del(k)
}
}
// Range calls f sequentially for each key and value.
// If f returns false, Range stops the iteration.
// The callback may safely call Add/Del on the same Options instance.
func (o *Options) Range(f func(key, value any) bool) {
o.mu.RLock()
if len(o.m) == 0 {
o.mu.RUnlock()
return
}
snapshot := make(map[string]any, len(o.m))
maps.Copy(snapshot, o.m)
o.mu.RUnlock()
for k, v := range snapshot {
if !f(k, v) {
break
}
}
}
// RangeSlice calls f sequentially for each key and value, using a slice
// snapshot. This is more efficient than Range for small maps and matches
// the iteration pattern used by LogFields.
func (o *Options) RangeSlice(f func(key, value any) bool) {
o.mu.RLock()
if len(o.m) == 0 {
o.mu.RUnlock()
return
}
type kv struct {
k string
v any
}
entries := make([]kv, 0, len(o.m))
for k, v := range o.m {
entries = append(entries, kv{k, v})
}
o.mu.RUnlock()
for _, e := range entries {
if !f(e.k, e.v) {
break
}
}
}