Browse Source

types/views: add SliceView.All iterator (#13536)

And convert a all relevant usages.

Updates #12912

Signed-off-by: Joe Tsai <[email protected]>
Joe Tsai 1 year ago
parent
commit
dc86d3589c
4 changed files with 50 additions and 10 deletions
  1. 3 6
      ipn/ipnlocal/drive.go
  2. 4 4
      ipn/ipnlocal/local.go
  3. 11 0
      types/views/views.go
  4. 32 0
      types/views/views_test.go

+ 3 - 6
ipn/ipnlocal/drive.go

@@ -93,8 +93,7 @@ func (b *LocalBackend) driveSetShareLocked(share *drive.Share) (views.SliceView[
 
 	addedShare := false
 	var shares []*drive.Share
-	for i := range existingShares.Len() {
-		existing := existingShares.At(i)
+	for _, existing := range existingShares.All() {
 		if existing.Name() != share.Name {
 			if !addedShare && existing.Name() > share.Name {
 				// Add share in order
@@ -152,8 +151,7 @@ func (b *LocalBackend) driveRenameShareLocked(oldName, newName string) (views.Sl
 
 	found := false
 	var shares []*drive.Share
-	for i := range existingShares.Len() {
-		existing := existingShares.At(i)
+	for _, existing := range existingShares.All() {
 		if existing.Name() == newName {
 			return existingShares, os.ErrExist
 		}
@@ -213,8 +211,7 @@ func (b *LocalBackend) driveRemoveShareLocked(name string) (views.SliceView[*dri
 
 	found := false
 	var shares []*drive.Share
-	for i := range existingShares.Len() {
-		existing := existingShares.At(i)
+	for _, existing := range existingShares.All() {
 		if existing.Name() != name {
 			shares = append(shares, existing.AsStruct())
 		} else {

+ 4 - 4
ipn/ipnlocal/local.go

@@ -511,8 +511,8 @@ func NewLocalBackend(logf logger.Logf, logID logid.PublicID, sys *tsd.System, lo
 		currentShares := b.pm.prefs.DriveShares()
 		if currentShares.Len() > 0 {
 			var shares []*drive.Share
-			for i := range currentShares.Len() {
-				shares = append(shares, currentShares.At(i).AsStruct())
+			for _, share := range currentShares.All() {
+				shares = append(shares, share.AsStruct())
 			}
 			fs.SetShares(shares)
 		}
@@ -6184,8 +6184,8 @@ func wireguardExitNodeDNSResolvers(nm *netmap.NetworkMap, peers map[tailcfg.Node
 				resolvers := p.ExitNodeDNSResolvers()
 				if !resolvers.IsNil() && resolvers.Len() > 0 {
 					copies := make([]*dnstype.Resolver, resolvers.Len())
-					for i := range resolvers.Len() {
-						copies[i] = resolvers.At(i).AsStruct()
+					for i, r := range resolvers.All() {
+						copies[i] = r.AsStruct()
 					}
 					return copies, true
 				}

+ 11 - 0
types/views/views.go

@@ -147,6 +147,17 @@ type SliceView[T ViewCloner[T, V], V StructView[T]] struct {
 	ж []T
 }
 
+// All returns an iterator over v.
+func (v SliceView[T, V]) All() iter.Seq2[int, V] {
+	return func(yield func(int, V) bool) {
+		for i := range v.ж {
+			if !yield(i, v.ж[i].View()) {
+				return
+			}
+		}
+	}
+}
+
 // MarshalJSON implements json.Marshaler.
 func (v SliceView[T, V]) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) }
 

+ 32 - 0
types/views/views_test.go

@@ -426,3 +426,35 @@ func TestSliceRange(t *testing.T) {
 		t.Errorf("got %q; want %q", got, want)
 	}
 }
+
+type testStruct struct{ value string }
+
+func (p *testStruct) Clone() *testStruct {
+	if p == nil {
+		return p
+	}
+	return &testStruct{p.value}
+}
+func (p *testStruct) View() testStructView { return testStructView{p} }
+
+type testStructView struct{ p *testStruct }
+
+func (v testStructView) Valid() bool { return v.p != nil }
+func (v testStructView) AsStruct() *testStruct {
+	if v.p == nil {
+		return nil
+	}
+	return v.p.Clone()
+}
+
+func TestSliceViewRange(t *testing.T) {
+	vs := SliceOfViews([]*testStruct{{value: "foo"}, {value: "bar"}})
+	var got []string
+	for i, v := range vs.All() {
+		got = append(got, fmt.Sprintf("%d-%s", i, v.AsStruct().value))
+	}
+	want := []string{"0-foo", "1-bar"}
+	if !slices.Equal(got, want) {
+		t.Errorf("got %q; want %q", got, want)
+	}
+}