Skip to content

Commit

Permalink
Merge pull request hashicorp#13308 from hashicorp/f-generic-helpers
Browse files Browse the repository at this point in the history
helpers: provide a few generic helper functions
  • Loading branch information
shoenig authored Jun 9, 2022
2 parents dd1bbbe + 109f25f commit 2697e63
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 14 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ require (
github.com/ryanuber/go-glob v1.0.0
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529
github.com/shirou/gopsutil/v3 v3.21.12
github.com/shoenig/test v0.2.5
github.com/shoenig/test v0.2.6
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c
github.com/stretchr/testify v1.7.1
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
Expand All @@ -118,6 +118,7 @@ require (
go.etcd.io/bbolt v1.3.5
go.uber.org/goleak v1.1.12
golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167
golang.org/x/exp v0.0.0-20220609121020-a51bd0440498
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e
Expand Down Expand Up @@ -264,7 +265,6 @@ require (
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.10 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/api v0.60.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
Expand Down
7 changes: 4 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1166,8 +1166,8 @@ github.com/shirou/gopsutil v0.0.0-20181107111621-48177ef5f880/go.mod h1:5b4v6he4
github.com/shirou/gopsutil/v3 v3.21.12 h1:VoGxEW2hpmz0Vt3wUvHIl9fquzYLNpVpgNNB7pGJimA=
github.com/shirou/gopsutil/v3 v3.21.12/go.mod h1:BToYZVTlSVlfazpDDYFnsVZLaoRG+g8ufT6fPQLdJzA=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/shoenig/test v0.2.5 h1:CfxxPAhW9sJt9nVI39cOHrb4krmHd28SmU66oCXi6sY=
github.com/shoenig/test v0.2.5/go.mod h1:xYtyGBC5Q3kzCNyJg/SjgNpfAa2kvmgA0i5+lQso8x0=
github.com/shoenig/test v0.2.6 h1:G7QP1jygTmhhNc0TKZ5O87CvB919YjL8EXnsD1aiaHo=
github.com/shoenig/test v0.2.6/go.mod h1:xYtyGBC5Q3kzCNyJg/SjgNpfAa2kvmgA0i5+lQso8x0=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
Expand Down Expand Up @@ -1341,6 +1341,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220609121020-a51bd0440498 h1:TF0FvLUGEq/8wOt/9AV1nj6D4ViZGUIGCMQfCv7VRXY=
golang.org/x/exp v0.0.0-20220609121020-a51bd0440498/go.mod h1:yh0Ynu2b5ZUe3MQfp2nM0ecK7wsgouWTDN0FNeJuIys=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
Expand Down Expand Up @@ -1660,7 +1662,6 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
99 changes: 90 additions & 9 deletions helper/funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

multierror "github.com/hashicorp/go-multierror"
"github.com/hashicorp/hcl/hcl/ast"
"golang.org/x/exp/constraints"
)

// validUUID is used to check if a given string looks like a UUID
Expand Down Expand Up @@ -69,41 +70,57 @@ func HashUUID(input string) (output string, hashed bool) {
}

// BoolToPtr returns the pointer to a boolean.
//
// Deprecated; use pointer.Of instead.
func BoolToPtr(b bool) *bool {
return &b
}

// IntToPtr returns the pointer to an int
// IntToPtr returns the pointer to an int.
//
// Deprecated; use pointer.Of instead.
func IntToPtr(i int) *int {
return &i
}

// Int8ToPtr returns the pointer to an int8
// Int8ToPtr returns the pointer to an int8.
//
// Deprecated; use pointer.Of instead.
func Int8ToPtr(i int8) *int8 {
return &i
}

// Int32ToPtr returns the pointer to an int32
// Int32ToPtr returns the pointer to an int32.
//
// Deprecated; use pointer.Of instead.
func Int32ToPtr(i int32) *int32 {
return &i
}

// Int64ToPtr returns the pointer to an int64
// Int64ToPtr returns the pointer to an int64.
//
// Deprecated; use pointer.Of instead.
func Int64ToPtr(i int64) *int64 {
return &i
}

// Uint64ToPtr returns the pointer to an uint64
// Uint64ToPtr returns the pointer to an uint64.
//
// Deprecated; use pointer.Of instead.
func Uint64ToPtr(u uint64) *uint64 {
return &u
}

// UintToPtr returns the pointer to an uint
// UintToPtr returns the pointer to an uint.
//
// Deprecated; use pointer.Of instead.
func UintToPtr(u uint) *uint {
return &u
}

// StringToPtr returns the pointer to a string
// StringToPtr returns the pointer to a string.
//
// Deprecated; use pointer.Of instead.
func StringToPtr(str string) *string {
return &str
}
Expand All @@ -121,25 +138,52 @@ func CompareTimePtrs(a, b *time.Duration) bool {
return *a == *b
}

// Float64ToPtr returns the pointer to an float64
// Float64ToPtr returns the pointer to an float64.
//
// Deprecated; use pointer.Of instead.
func Float64ToPtr(f float64) *float64 {
return &f
}

// Min returns the minimum of a and b.
func Min[T constraints.Ordered](a, b T) T {
if a < b {
return a
}
return b
}

// Max returns the maximum of a and b.
func Max[T constraints.Ordered](a, b T) T {
if a > b {
return a
}
return b
}

// IntMin returns the minimum of a and b.
//
// Deprecated; use Min instead.
func IntMin(a, b int) int {
if a < b {
return a
}
return b
}

// IntMax returns the maximum of a and b.
//
// Deprecated; use Max instead.
func IntMax(a, b int) int {
if a > b {
return a
}
return b
}

// Uint64Max returns the maximum of a and b.
//
// Deprecated; use Max instead.
func Uint64Max(a, b uint64) uint64 {
if a > b {
return a
Expand Down Expand Up @@ -311,8 +355,24 @@ func CompareMapStringString(a, b map[string]string) bool {
return true
}

// Below is helpers for copying generic structures.
// CopyMap creates a copy of m. Struct values are not deep copies.
//
// If m is nil or contains no elements, the return value is nil.
func CopyMap[M ~map[K]V, K comparable, V any](m M) M {
if len(m) == 0 {
return nil
}

result := make(M, len(m))
for k, v := range m {
result[k] = v
}
return result
}

// CopyMapStringString creates a copy of m.
//
// Deprecated; use CopyMap instead.
func CopyMapStringString(m map[string]string) map[string]string {
l := len(m)
if l == 0 {
Expand All @@ -326,6 +386,9 @@ func CopyMapStringString(m map[string]string) map[string]string {
return c
}

// CopyMapStringStruct creates a copy of m.
//
// Deprecated; use CopyMap instead.
func CopyMapStringStruct(m map[string]struct{}) map[string]struct{} {
l := len(m)
if l == 0 {
Expand All @@ -339,6 +402,9 @@ func CopyMapStringStruct(m map[string]struct{}) map[string]struct{} {
return c
}

// CopyMapStringInterface creates a copy of m.
//
// Deprecated; use CopyMap instead.
func CopyMapStringInterface(m map[string]interface{}) map[string]interface{} {
l := len(m)
if l == 0 {
Expand Down Expand Up @@ -375,6 +441,9 @@ func MergeMapStringString(m map[string]string, n map[string]string) map[string]s
return result
}

// CopyMapStringInt creates a copy of m.
//
// Deprecated; use CopyMap instead.
func CopyMapStringInt(m map[string]int) map[string]int {
l := len(m)
if l == 0 {
Expand All @@ -388,6 +457,9 @@ func CopyMapStringInt(m map[string]int) map[string]int {
return c
}

// CopyMapStringFloat64 creates a copy of m.
//
// Deprecated; use CopyMap instead.
func CopyMapStringFloat64(m map[string]float64) map[string]float64 {
l := len(m)
if l == 0 {
Expand All @@ -401,6 +473,9 @@ func CopyMapStringFloat64(m map[string]float64) map[string]float64 {
return c
}

// CopyMapStringSliceString creates a copy of m.
//
// todo: a deep value copy version of CopyMap.
func CopyMapStringSliceString(m map[string][]string) map[string][]string {
l := len(m)
if l == 0 {
Expand All @@ -414,6 +489,9 @@ func CopyMapStringSliceString(m map[string][]string) map[string][]string {
return c
}

// CopySliceString creates a copy of s.
//
// Deprecated; use slices.Clone instead.
func CopySliceString(s []string) []string {
l := len(s)
if l == 0 {
Expand All @@ -425,6 +503,9 @@ func CopySliceString(s []string) []string {
return c
}

// CopySliceInt creates a copy of s.
//
// Deprecated; use slices.Clone instead.
func CopySliceInt(s []int) []int {
l := len(s)
if l == 0 {
Expand Down
69 changes: 69 additions & 0 deletions helper/funcs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,78 @@ import (
"testing"
"time"

"github.com/shoenig/test/must"
"github.com/stretchr/testify/require"
)

func Test_Min(t *testing.T) {
t.Run("int", func(t *testing.T) {
a := 1
b := 2
must.Eq(t, 1, Min(a, b))
must.Eq(t, 1, Min(b, a))
})

t.Run("float64", func(t *testing.T) {
a := 1.1
b := 2.2
must.Eq(t, 1.1, Min(a, b))
must.Eq(t, 1.1, Min(b, a))
})

t.Run("string", func(t *testing.T) {
a := "cat"
b := "dog"
must.Eq(t, "cat", Min(a, b))
must.Eq(t, "cat", Min(b, a))
})
}

func Test_Max(t *testing.T) {
t.Run("int", func(t *testing.T) {
a := 1
b := 2
must.Eq(t, 2, Max(a, b))
must.Eq(t, 2, Max(b, a))
})

t.Run("float64", func(t *testing.T) {
a := 1.1
b := 2.2
must.Eq(t, 2.2, Max(a, b))
must.Eq(t, 2.2, Max(b, a))
})

t.Run("string", func(t *testing.T) {
a := "cat"
b := "dog"
must.Eq(t, "dog", Max(a, b))
must.Eq(t, "dog", Max(b, a))
})
}

func Test_CopyMap(t *testing.T) {
t.Run("nil", func(t *testing.T) {
var m map[string]int
result := CopyMap(m)
must.Nil(t, result)
})

t.Run("empty", func(t *testing.T) {
m := make(map[string]int, 10)
result := CopyMap(m)
must.Nil(t, result)
})

t.Run("elements", func(t *testing.T) {
m := map[string]int{"a": 1, "b": 2}
result := CopyMap(m)
result["a"] = -1
must.MapEq(t, map[string]int{"a": -1, "b": 2}, result)
must.MapEq(t, map[string]int{"a": 1, "b": 2}, m) // not modified
})
}

func TestSliceStringIsSubset(t *testing.T) {
l := []string{"a", "b", "c"}
s := []string{"d"}
Expand Down
7 changes: 7 additions & 0 deletions helper/pointer/pointer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Package pointer provides helper functions related to Go pointers.
package pointer

// Of returns a pointer to a.
func Of[A any](a A) *A {
return &a
}
18 changes: 18 additions & 0 deletions helper/pointer/pointer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package pointer

import (
"testing"

"github.com/shoenig/test/must"
)

func Test_Of(t *testing.T) {
s := "hello"
sPtr := Of(s)

must.Eq(t, s, *sPtr)

b := "bye"
sPtr = &b
must.NotEq(t, s, *sPtr)
}

0 comments on commit 2697e63

Please sign in to comment.