diff --git a/util/cmpx/cmpx.go b/util/cmpx/cmpx.go new file mode 100644 index 000000000..d747f0a1d --- /dev/null +++ b/util/cmpx/cmpx.go @@ -0,0 +1,22 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +// Package cmpx has code that will likely land in a future version of Go, but +// we want sooner. +package cmpx + +// Or returns the first non-zero element of list, or else returns the zero T. +// +// This is the proposal from +// https://github.com/golang/go/issues/60204#issuecomment-1581245334. +func Or[T comparable](list ...T) T { + // TODO(bradfitz): remove the comparable constraint so we can use this + // with funcs too and use reflect to see whether they're non-zero? 🤷‍♂️ + var zero T + for _, v := range list { + if v != zero { + return v + } + } + return zero +} diff --git a/util/cmpx/cmpx_test.go b/util/cmpx/cmpx_test.go new file mode 100644 index 000000000..768492dd7 --- /dev/null +++ b/util/cmpx/cmpx_test.go @@ -0,0 +1,24 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +package cmpx + +import "testing" + +func TestOr(t *testing.T) { + if g, w := Or[string](), ""; g != w { + t.Errorf("got %v; want %v", g, w) + } + if g, w := Or[int](), 0; g != w { + t.Errorf("got %v; want %v", g, w) + } + if g, w := Or("", "foo", "bar"), "foo"; g != w { + t.Errorf("got %v; want %v", g, w) + } + if g, w := Or("foo", "bar"), "foo"; g != w { + t.Errorf("got %v; want %v", g, w) + } + if g, w := Or("", "", "bar"), "bar"; g != w { + t.Errorf("got %v; want %v", g, w) + } +}