Pārlūkot izejas kodu

util/slicesx: add FirstElementEqual and LastElementEqual

And update a few callers as examples of motivation. (there are a
couple others, but these are the ones where it's prettier)

Updates #cleanup

Change-Id: Ic8c5cb7af0a59c6e790a599136b591ebe16d38eb
Signed-off-by: Brad Fitzpatrick <[email protected]>
Brad Fitzpatrick 1 gadu atpakaļ
vecāks
revīzija
cec779e771

+ 2 - 1
derp/derp_server.go

@@ -47,6 +47,7 @@ import (
 	"tailscale.com/types/key"
 	"tailscale.com/types/logger"
 	"tailscale.com/util/set"
+	"tailscale.com/util/slicesx"
 	"tailscale.com/version"
 )
 
@@ -1323,7 +1324,7 @@ func (s *Server) noteClientActivity(c *sclient) {
 		cs.activeClient.Store(c)
 	}
 
-	if sh := dup.sendHistory; len(sh) != 0 && sh[len(sh)-1] == c {
+	if slicesx.LastEqual(dup.sendHistory, c) {
 		// The client c was the last client to make activity
 		// in this set and it was already recorded. Nothing to
 		// do.

+ 2 - 1
ssh/tailssh/tailssh.go

@@ -45,6 +45,7 @@ import (
 	"tailscale.com/util/clientmetric"
 	"tailscale.com/util/httpm"
 	"tailscale.com/util/mak"
+	"tailscale.com/util/slicesx"
 )
 
 var (
@@ -330,7 +331,7 @@ func (c *conn) nextAuthMethodCallback(cm gossh.ConnMetadata, prevErrors []error)
 	switch {
 	case c.anyPasswordIsOkay:
 		nextMethod = append(nextMethod, "password")
-	case len(prevErrors) > 0 && prevErrors[len(prevErrors)-1] == errPubKeyRequired:
+	case slicesx.LastEqual(prevErrors, errPubKeyRequired):
 		nextMethod = append(nextMethod, "publickey")
 	}
 

+ 4 - 2
util/linuxfw/helpers.go

@@ -10,11 +10,13 @@ import (
 	"fmt"
 	"strings"
 	"unicode"
+
+	"tailscale.com/util/slicesx"
 )
 
 func formatMaybePrintable(b []byte) string {
-	// Remove a single trailing null, if any
-	if len(b) > 0 && b[len(b)-1] == 0 {
+	// Remove a single trailing null, if any.
+	if slicesx.LastEqual(b, 0) {
 		b = b[:len(b)-1]
 	}
 

+ 12 - 0
util/slicesx/slicesx.go

@@ -136,3 +136,15 @@ func CutSuffix[E comparable](s, suffix []E) (after []E, found bool) {
 	}
 	return s[:len(s)-len(suffix)], true
 }
+
+// FirstEqual reports whether len(s) > 0 and
+// its first element == v.
+func FirstEqual[T comparable](s []T, v T) bool {
+	return len(s) > 0 && s[0] == v
+}
+
+// LastEqual reports whether len(s) > 0 and
+// its last element == v.
+func LastEqual[T comparable](s []T, v T) bool {
+	return len(s) > 0 && s[len(s)-1] == v
+}

+ 25 - 0
util/slicesx/slicesx_test.go

@@ -197,3 +197,28 @@ func TestCutSuffix(t *testing.T) {
 		})
 	}
 }
+
+func TestFirstLastEqual(t *testing.T) {
+	tests := []struct {
+		name string
+		in   string
+		v    byte
+		f    func([]byte, byte) bool
+		want bool
+	}{
+		{"first-empty", "", 'f', FirstEqual[byte], false},
+		{"first-true", "foo", 'f', FirstEqual[byte], true},
+		{"first-false", "foo", 'b', FirstEqual[byte], false},
+		{"last-empty", "", 'f', LastEqual[byte], false},
+		{"last-true", "bar", 'r', LastEqual[byte], true},
+		{"last-false", "bar", 'o', LastEqual[byte], false},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.f([]byte(tt.in), tt.v); got != tt.want {
+				t.Errorf("got %v; want %v", got, tt.want)
+			}
+		})
+	}
+
+}