-
Notifications
You must be signed in to change notification settings - Fork 5
/
metadata.go
130 lines (114 loc) · 2.52 KB
/
metadata.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
// Package metadata is a way of defining message headers
package metadata
import (
"net/textproto"
"sort"
)
var (
// HeaderPrefix for all headers passed
HeaderPrefix = "Micro-"
)
// Metadata is our way of representing request headers internally.
// They're used at the RPC level and translate back and forth
// from Transport headers.
type Metadata map[string]string
type rawMetadata struct {
md Metadata
}
var (
// defaultMetadataSize used when need to init new Metadata
defaultMetadataSize = 2
)
// Iterator used to iterate over metadata with order
type Iterator struct {
md Metadata
keys []string
cur int
cnt int
}
// Next advance iterator to next element
func (iter *Iterator) Next(k, v *string) bool {
if iter.cur+1 > iter.cnt {
return false
}
*k = iter.keys[iter.cur]
*v = iter.md[*k]
iter.cur++
return true
}
// Iterator returns the itarator for metadata in sorted order
func (md Metadata) Iterator() *Iterator {
iter := &Iterator{md: md, cnt: len(md)}
iter.keys = make([]string, 0, iter.cnt)
for k := range md {
iter.keys = append(iter.keys, k)
}
sort.Strings(iter.keys)
return iter
}
// Get returns value from metadata by key
func (md Metadata) Get(key string) (string, bool) {
// fast path
val, ok := md[key]
if !ok {
// slow path
val, ok = md[textproto.CanonicalMIMEHeaderKey(key)]
}
return val, ok
}
// Set is used to store value in metadata
func (md Metadata) Set(key, val string) {
md[textproto.CanonicalMIMEHeaderKey(key)] = val
}
// Del is used to remove value from metadata
func (md Metadata) Del(key string) {
// fast path
delete(md, key)
// slow path
delete(md, textproto.CanonicalMIMEHeaderKey(key))
}
// Copy makes a copy of the metadata
func Copy(md Metadata) Metadata {
nmd := New(len(md))
for key, val := range md {
nmd.Set(key, val)
}
return nmd
}
// New return new sized metadata
func New(size int) Metadata {
if size == 0 {
size = defaultMetadataSize
}
return make(Metadata, size)
}
// Merge merges metadata to existing metadata, overwriting if specified
func Merge(omd Metadata, mmd Metadata, overwrite bool) Metadata {
nmd := Copy(omd)
for key, val := range mmd {
if _, ok := nmd[key]; ok && !overwrite {
// skip
} else if val != "" {
nmd.Set(key, val)
} else {
nmd.Del(key)
}
}
return nmd
}
// Pairs from which metadata created
func Pairs(kv ...string) (Metadata, bool) {
if len(kv)%2 == 1 {
return nil, false
}
md := New(len(kv) / 2)
var k string
for i, v := range kv {
if i%2 == 0 {
k = v
continue
}
md.Set(k, v)
}
return md, true
}