-
Notifications
You must be signed in to change notification settings - Fork 0
/
keys.go
332 lines (301 loc) · 10.6 KB
/
keys.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
package goip
import "fmt"
const (
adaptiveZeroScheme addressScheme = 0 // adaptiveZeroScheme needs to be zero, to coincide with the zero value for Address and IPAddress, which is a zero-length address
ipv4Scheme addressScheme = 1
ipv6Scheme addressScheme = 2
mac48Scheme addressScheme = 3
eui64Scheme addressScheme = 4
)
var (
_ Key[*MACAddress]
_ Key[*IPv4Address]
_ Key[*IPv6Address]
_ AddressKey
_ IPAddressKey
_ MACAddressKey
_ IPv4AddressKey
_ IPv6AddressKey
_ IPAddressSeqRangeKey
_ IPv4AddressSeqRangeKey
_ IPv6AddressSeqRangeKey
// ensure our 5 key types are indeed comparable
_ testComparableConstraint[MACAddressKey]
_ testComparableConstraint[Key[*Address]]
_ testComparableConstraint[IPv4AddressKey]
_ testComparableConstraint[IPv6AddressKey]
_ testComparableConstraint[Key[*IPAddress]]
)
// SequentialRangeKey is a representation of SequentialRange that is comparable as defined by the language specification.
//
// It can be used as a map key.
// The zero value is a range from a zero-length address to itself.
type SequentialRangeKey[T SequentialRangeConstraint[T]] struct {
vals [2]struct {
lower,
upper uint64
}
addrType addrType // only used when T is *IPAddress to indicate version for non-zero valued address
}
// ToSeqRange converts back to a sequential range instance.
func (key SequentialRangeKey[T]) ToSeqRange() *SequentialRange[T] {
var isMult bool
var lower, upper T
anyt := any(lower)
isIP, isIPv4, isIPv6 := false, false, false
if _, isIPv4 = anyt.(*IPv4Address); !isIPv4 {
if _, isIPv6 = anyt.(*IPv6Address); !isIPv6 {
if _, isIP = anyt.(*IPAddress); isIP {
addressType := key.addrType
if isIPv4 = addressType.isIPv4(); !isIPv4 {
if isIPv6 = addressType.isIPv6(); !isIPv6 {
if isNeither := addressType.isZeroSegments(); isNeither {
lower = any(zeroIPAddr).(T)
upper = lower
} else {
panic("supports only IP addresses")
}
}
}
} else {
panic("supports only IP addresses")
}
}
}
if isIPv6 {
lower6 := NewIPv6AddressFromVals(
func(segmentIndex int) IPv6SegInt {
valsIndex := segmentIndex >> 2
segIndex := ((IPv6SegmentCount - 1) - segmentIndex) & 0x3
return IPv6SegInt(key.vals[valsIndex].lower >> (segIndex << ipv6BitsToSegmentBitshift))
})
upper6 := NewIPv6AddressFromVals(
func(segmentIndex int) IPv6SegInt {
valsIndex := segmentIndex >> 2
segIndex := ((IPv6SegmentCount - 1) - segmentIndex) & 0x3
return IPv6SegInt(key.vals[valsIndex].upper >> (segIndex << ipv6BitsToSegmentBitshift))
})
isMult = key.vals[1].lower != key.vals[1].upper || key.vals[0].lower != key.vals[0].upper
if isIP {
lower = any(lower6.ToIP()).(T)
upper = any(upper6.ToIP()).(T)
} else {
lower = any(lower6).(T)
upper = any(upper6).(T)
}
} else if isIPv4 {
l := uint32(key.vals[0].lower)
u := uint32(key.vals[0].upper)
lower4 := NewIPv4AddressFromUint32(l)
upper4 := NewIPv4AddressFromUint32(u)
isMult = l != u
if isIP {
lower = any(lower4.ToIP()).(T)
upper = any(upper4.ToIP()).(T)
} else {
lower = any(lower4).(T)
upper = any(upper4).(T)
}
}
return newSequRangeUnchecked(lower, upper, isMult)
}
// String calls the String method in the corresponding sequential range.
func (key SequentialRangeKey[T]) String() string {
return key.ToSeqRange().String()
}
// IPv4AddressKey is a representation of an IPv4 address that is comparable as defined by the language specification.
//
// It can be used as a map key.
// It can be obtained from its originating address instances.
// The zero value corresponds to the zero-value for IPv4Address.
// Keys do not incorporate prefix length to ensure that all equal addresses have equal keys.
// To create a key that has prefix length, combine into a struct with
// the PrefixKey obtained by passing the address into PrefixKeyFrom.
// IPv4Address can be compared using the Compare or Equal methods, or using an AddressComparator.
type IPv4AddressKey struct {
vals uint64 // upper and lower combined into one uint64
}
// ToAddress converts back to an address instance.
func (key IPv4AddressKey) ToAddress() *IPv4Address {
return fromIPv4Key(key)
}
// String calls the String method in the corresponding address.
func (key IPv4AddressKey) String() string {
return key.ToAddress().String()
}
type testComparableConstraint[T comparable] struct{}
type keyContents struct {
vals [2]struct {
lower,
upper uint64
}
zone Zone
}
// IPv6AddressKey is a representation of an IPv6 address that is comparable as defined by the language specification.
//
// It can be used as a map key. It can be obtained from its originating address instances.
// The zero value corresponds to the zero-value for IPv6Address.
// Keys do not incorporate prefix length to ensure that all equal addresses have equal keys.
// To create a key that has prefix length,
// combine into a struct with the PrefixKey obtained by passing the address into PrefixKeyFrom.
// IPv6Address can be compared using the Compare or Equal methods, or using an AddressComparator.
type IPv6AddressKey struct {
keyContents
}
// ToAddress converts back to an address instance.
func (key IPv6AddressKey) ToAddress() *IPv6Address {
return fromIPv6Key(key)
}
// String calls the String method in the corresponding address.
func (key IPv6AddressKey) String() string {
return key.ToAddress().String()
}
// MACAddressKey is a representation of a MAC address that is comparable as defined by the language specification.
//
// It can be used as a map key. It can be obtained from its originating address instances.
// The zero value corresponds to the zero-value for MACAddress.
// Keys do not incorporate prefix length to ensure that all equal addresses have equal keys.
// To create a key that has prefix length,
// combine into a struct with the PrefixKey obtained by passing the address into PrefixKeyFrom.
// MACAddress can be compared using the Compare or Equal methods, or using an AddressComparator.
type MACAddressKey struct {
vals struct {
lower,
upper uint64
}
additionalByteCount uint8 // 0 for MediaAccessControlSegmentCount or 2 for ExtendedUniqueIdentifier64SegmentCount
}
// ToAddress converts back to an address instance.
func (key MACAddressKey) ToAddress() *MACAddress {
return fromMACKey(key)
}
// String calls the String method in the corresponding address.
func (key MACAddressKey) String() string {
return key.ToAddress().String()
}
type addressScheme byte
// KeyConstraint is the generic type constraint for
// an address type that can be generated from a generic address key.
type KeyConstraint[T any] interface {
fmt.Stringer
fromKey(addressScheme, *keyContents) T // implemented by IPAddress and Address
}
// KeyGeneratorConstraint is the generic type constraint for
// an address type that can generate a generic address key.
type KeyGeneratorConstraint[T KeyConstraint[T]] interface {
ToGenericKey() Key[T]
}
// GenericKeyConstraint is the generic type constraint for
// an address type that can generate and
// be generated from a generic address key.
type GenericKeyConstraint[T KeyConstraint[T]] interface {
KeyGeneratorConstraint[T]
KeyConstraint[T]
}
// Key is a representation of an address that is comparable as defined by the language specification.
//
// It can be used as a map key. It can be obtained from its originating address instances.
// The zero value corresponds to the zero-value for its generic address type.
// Keys do not incorporate prefix length to ensure that all equal addresses have equal keys.
// To create a key that has prefix length,
// combine into a struct with the PrefixKey obtained by passing the address into PrefixKeyFrom.
type Key[T KeyConstraint[T]] struct {
scheme addressScheme
keyContents
}
// ToAddress converts back to an address instance.
func (key Key[T]) ToAddress() T {
var t T
return t.fromKey(key.scheme, &key.keyContents)
}
// String calls the String method in the corresponding address.
func (key Key[T]) String() string {
return key.ToAddress().String()
}
type (
AddressKey = Key[*Address]
IPAddressKey = Key[*IPAddress]
IPAddressSeqRangeKey = SequentialRangeKey[*IPAddress]
IPv4AddressSeqRangeKey = SequentialRangeKey[*IPv4Address]
IPv6AddressSeqRangeKey = SequentialRangeKey[*IPv6Address]
)
// PrefixKey is a representation of a prefix length
// that is comparable as defined by the language specification.
//
// It can be used as a map key.
// The zero value is the absence of a prefix length.
type PrefixKey struct {
// If true, the prefix length is indicated by PrefixLen.
// If false, this indicates no prefix length for the associated address or subnet.
IsPrefixed bool
// If IsPrefixed is true, this holds the prefix length.
// Otherwise, this should be zero if you wish that each address has a unique key.
PrefixLen PrefixBitCount
}
// ToPrefixLen converts this key to its corresponding prefix length.
func (pref PrefixKey) ToPrefixLen() PrefixLen {
if pref.IsPrefixed {
return &pref.PrefixLen
}
return nil
}
func newSequentialRangeKey[T SequentialRangeConstraint[T]](rng *SequentialRange[T]) (key SequentialRangeKey[T]) {
lower := rng.GetLower()
upper := rng.GetUpper()
lowerIp := lower.ToIP()
upperIp := upper.ToIP()
var t T
anyt := any(t)
_, isIP := anyt.(*IPAddress)
if lowerIp.isIPv4() {
section := lowerIp.GetSection()
divs := section.getDivArray()
for _, div := range divs {
seg := div.ToIPv4()
val := &key.vals[0]
newLower := (val.lower << IPv4BitsPerSegment) | uint64(seg.GetIPv4SegmentValue())
val.lower = newLower
}
section = upperIp.GetSection()
divs = section.getDivArray()
for _, div := range divs {
seg := div.ToIPv4()
val := &key.vals[0]
newUpper := (val.upper << IPv4BitsPerSegment) | uint64(seg.GetIPv4SegmentValue())
val.upper = newUpper
}
if isIP {
key.addrType = ipv4Type
}
} else if lowerIp.isIPv6() {
section := lowerIp.GetSection()
divs := section.getDivArray()
for i, div := range divs {
seg := div.ToIPv6()
val := &key.vals[i>>2]
newLower := (val.lower << IPv6BitsPerSegment) | uint64(seg.GetIPv6SegmentValue())
val.lower = newLower
}
section = upperIp.GetSection()
divs = section.getDivArray()
for i, div := range divs {
seg := div.ToIPv6()
val := &key.vals[i>>2]
newUpper := (val.upper << IPv6BitsPerSegment) | uint64(seg.GetIPv6SegmentValue())
val.upper = newUpper
}
if isIP {
key.addrType = ipv6Type
}
}
return
}
func PrefixKeyFrom(addr AddressType) PrefixKey {
if addr.IsPrefixed() {
return PrefixKey{
IsPrefixed: true,
PrefixLen: *addr.ToAddressBase().getPrefixLen(), // doing this instead of calling GetPrefixLen() on AddressType avoids the prefix len copy
}
}
return PrefixKey{}
}