forked from tailscale/tailscale
/
views.go
337 lines (280 loc) · 9.59 KB
/
views.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
333
334
335
336
337
// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package views provides read-only accessors for commonly used
// value types.
package views
import (
"encoding/json"
"errors"
"net/netip"
"github.com/qwenode/tailscale/net/tsaddr"
)
func unmarshalJSON[T any](b []byte, x *[]T) error {
if *x != nil {
return errors.New("already initialized")
}
if len(b) == 0 {
return nil
}
return json.Unmarshal(b, x)
}
// StructView represents the corresponding StructView of a Viewable. The concrete types are
// typically generated by github.com/qwenode/tailscale/cmd/viewer.
type StructView[T any] interface {
// Valid reports whether the underlying Viewable is nil.
Valid() bool
// AsStruct returns a deep-copy of the underlying value.
// It returns nil, if Valid() is false.
AsStruct() T
}
// ViewCloner is any type that has had View and Clone funcs generated using
// github.com/qwenode/tailscale/cmd/viewer.
type ViewCloner[T any, V StructView[T]] interface {
// View returns a read-only view of Viewable.
// If Viewable is nil, View().Valid() reports false.
View() V
// Clone returns a deep-clone of Viewable.
// It returns nil, when Viewable is nil.
Clone() T
}
// SliceOfViews returns a ViewSlice for x.
func SliceOfViews[T ViewCloner[T, V], V StructView[T]](x []T) SliceView[T, V] {
return SliceView[T, V]{x}
}
// SliceView is a read-only wrapper around a struct which should only be exposed
// as a View.
type SliceView[T ViewCloner[T, V], V StructView[T]] struct {
// ж is the underlying mutable value, named with a hard-to-type
// character that looks pointy like a pointer.
// It is named distinctively to make you think of how dangerous it is to escape
// to callers. You must not let callers be able to mutate it.
ж []T
}
// MarshalJSON implements json.Marshaler.
func (v SliceView[T, V]) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) }
// UnmarshalJSON implements json.Unmarshaler.
func (v *SliceView[T, V]) UnmarshalJSON(b []byte) error { return unmarshalJSON(b, &v.ж) }
// IsNil reports whether the underlying slice is nil.
func (v SliceView[T, V]) IsNil() bool { return v.ж == nil }
// Len returns the length of the slice.
func (v SliceView[T, V]) Len() int { return len(v.ж) }
// At returns a View of the element at index `i` of the slice.
func (v SliceView[T, V]) At(i int) V { return v.ж[i].View() }
// AppendTo appends the underlying slice values to dst.
func (v SliceView[T, V]) AppendTo(dst []V) []V {
for _, x := range v.ж {
dst = append(dst, x.View())
}
return dst
}
// AsSlice returns a copy of underlying slice.
func (v SliceView[T, V]) AsSlice() []V {
return v.AppendTo(nil)
}
// Slice is a read-only accessor for a slice.
type Slice[T any] struct {
// ж is the underlying mutable value, named with a hard-to-type
// character that looks pointy like a pointer.
// It is named distinctively to make you think of how dangerous it is to escape
// to callers. You must not let callers be able to mutate it.
ж []T
}
// SliceOf returns a Slice for the provided slice for immutable values.
// It is the caller's responsibility to make sure V is immutable.
func SliceOf[T any](x []T) Slice[T] {
return Slice[T]{x}
}
// MarshalJSON implements json.Marshaler.
func (v Slice[T]) MarshalJSON() ([]byte, error) {
return json.Marshal(v.ж)
}
// UnmarshalJSON implements json.Unmarshaler.
func (v *Slice[T]) UnmarshalJSON(b []byte) error {
return unmarshalJSON(b, &v.ж)
}
// IsNil reports whether the underlying slice is nil.
func (v Slice[T]) IsNil() bool { return v.ж == nil }
// Len returns the length of the slice.
func (v Slice[T]) Len() int { return len(v.ж) }
// At returns the element at index `i` of the slice.
func (v Slice[T]) At(i int) T { return v.ж[i] }
// AppendTo appends the underlying slice values to dst.
func (v Slice[T]) AppendTo(dst []T) []T {
return append(dst, v.ж...)
}
// AsSlice returns a copy of underlying slice.
func (v Slice[T]) AsSlice() []T {
return v.AppendTo(v.ж[:0:0])
}
// IndexFunc returns the first index of an element in v satisfying f(e),
// or -1 if none do.
//
// As it runs in O(n) time, use with care.
func (v Slice[T]) IndexFunc(f func(T) bool) int {
for i := 0; i < v.Len(); i++ {
if f(v.At(i)) {
return i
}
}
return -1
}
// ContainsFunc reports whether any element in v satisfies f(e).
//
// As it runs in O(n) time, use with care.
func (v Slice[T]) ContainsFunc(f func(T) bool) bool {
for i := 0; i < v.Len(); i++ {
if f(v.At(i)) {
return true
}
}
return false
}
// SliceContains reports whether v contains element e.
//
// As it runs in O(n) time, use with care.
func SliceContains[T comparable](v Slice[T], e T) bool {
for i := 0; i < v.Len(); i++ {
if v.At(i) == e {
return true
}
}
return false
}
// IPPrefixSlice is a read-only accessor for a slice of netip.Prefix.
type IPPrefixSlice struct {
ж Slice[netip.Prefix]
}
// IPPrefixSliceOf returns a IPPrefixSlice for the provided slice.
func IPPrefixSliceOf(x []netip.Prefix) IPPrefixSlice { return IPPrefixSlice{SliceOf(x)} }
// IsNil reports whether the underlying slice is nil.
func (v IPPrefixSlice) IsNil() bool { return v.ж.IsNil() }
// Len returns the length of the slice.
func (v IPPrefixSlice) Len() int { return v.ж.Len() }
// At returns the IPPrefix at index `i` of the slice.
func (v IPPrefixSlice) At(i int) netip.Prefix { return v.ж.At(i) }
// AppendTo appends the underlying slice values to dst.
func (v IPPrefixSlice) AppendTo(dst []netip.Prefix) []netip.Prefix {
return v.ж.AppendTo(dst)
}
// Unwrap returns the underlying Slice[netip.Prefix].
func (v IPPrefixSlice) Unwrap() Slice[netip.Prefix] {
return v.ж
}
// AsSlice returns a copy of underlying slice.
func (v IPPrefixSlice) AsSlice() []netip.Prefix {
return v.ж.AsSlice()
}
// PrefixesContainsIP reports whether any IPPrefix contains IP.
func (v IPPrefixSlice) ContainsIP(ip netip.Addr) bool {
return tsaddr.PrefixesContainsIP(v.ж.ж, ip)
}
// PrefixesContainsFunc reports whether f is true for any IPPrefix in the slice.
func (v IPPrefixSlice) ContainsFunc(f func(netip.Prefix) bool) bool {
return tsaddr.PrefixesContainsFunc(v.ж.ж, f)
}
// ContainsExitRoutes reports whether v contains ExitNode Routes.
func (v IPPrefixSlice) ContainsExitRoutes() bool {
return tsaddr.ContainsExitRoutes(v.ж.ж)
}
// MarshalJSON implements json.Marshaler.
func (v IPPrefixSlice) MarshalJSON() ([]byte, error) {
return v.ж.MarshalJSON()
}
// UnmarshalJSON implements json.Unmarshaler.
func (v *IPPrefixSlice) UnmarshalJSON(b []byte) error {
return v.ж.UnmarshalJSON(b)
}
// MapOf returns a view over m. It is the caller's responsibility to make sure K
// and V is immutable, if this is being used to provide a read-only view over m.
func MapOf[K comparable, V comparable](m map[K]V) Map[K, V] {
return Map[K, V]{m}
}
// Map is a view over a map whose values are immutable.
type Map[K comparable, V any] struct {
// ж is the underlying mutable value, named with a hard-to-type
// character that looks pointy like a pointer.
// It is named distinctively to make you think of how dangerous it is to escape
// to callers. You must not let callers be able to mutate it.
ж map[K]V
}
// Has reports whether k has an entry in the map.
func (m Map[K, V]) Has(k K) bool {
_, ok := m.ж[k]
return ok
}
// IsNil reports whether the underlying map is nil.
func (m Map[K, V]) IsNil() bool {
return m.ж == nil
}
// Len returns the number of elements in the map.
func (m Map[K, V]) Len() int { return len(m.ж) }
// Get returns the element with key k.
func (m Map[K, V]) Get(k K) V {
return m.ж[k]
}
// GetOk returns the element with key k and a bool representing whether the key
// is in map.
func (m Map[K, V]) GetOk(k K) (V, bool) {
v, ok := m.ж[k]
return v, ok
}
// MapRangeFn is the func called from a Map.Range call.
// Implementations should return false to stop range.
type MapRangeFn[K comparable, V any] func(k K, v V) (cont bool)
// Range calls f for every k,v pair in the underlying map.
// It stops iteration immediately if f returns false.
func (m Map[K, V]) Range(f MapRangeFn[K, V]) {
for k, v := range m.ж {
if !f(k, v) {
return
}
}
}
// MapFnOf returns a MapFn for m.
func MapFnOf[K comparable, T any, V any](m map[K]T, f func(T) V) MapFn[K, T, V] {
return MapFn[K, T, V]{
ж: m,
wrapv: f,
}
}
// MapFn is like Map but with a func to convert values from T to V.
// It is used to provide map of slices and views.
type MapFn[K comparable, T any, V any] struct {
// ж is the underlying mutable value, named with a hard-to-type
// character that looks pointy like a pointer.
// It is named distinctively to make you think of how dangerous it is to escape
// to callers. You must not let callers be able to mutate it.
ж map[K]T
wrapv func(T) V
}
// Has reports whether k has an entry in the map.
func (m MapFn[K, T, V]) Has(k K) bool {
_, ok := m.ж[k]
return ok
}
// Get returns the element with key k.
func (m MapFn[K, T, V]) Get(k K) V {
return m.wrapv(m.ж[k])
}
// IsNil reports whether the underlying map is nil.
func (m MapFn[K, T, V]) IsNil() bool {
return m.ж == nil
}
// Len returns the number of elements in the map.
func (m MapFn[K, T, V]) Len() int { return len(m.ж) }
// GetOk returns the element with key k and a bool representing whether the key
// is in map.
func (m MapFn[K, T, V]) GetOk(k K) (V, bool) {
v, ok := m.ж[k]
return m.wrapv(v), ok
}
// Range calls f for every k,v pair in the underlying map.
// It stops iteration immediately if f returns false.
func (m MapFn[K, T, V]) Range(f MapRangeFn[K, V]) {
for k, v := range m.ж {
if !f(k, m.wrapv(v)) {
return
}
}
}