github.com/opentofu/opentofu@v1.7.1/internal/legacy/tofu/util.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package tofu 7 8 import ( 9 "sort" 10 ) 11 12 // Semaphore is a wrapper around a channel to provide 13 // utility methods to clarify that we are treating the 14 // channel as a semaphore 15 type Semaphore chan struct{} 16 17 // NewSemaphore creates a semaphore that allows up 18 // to a given limit of simultaneous acquisitions 19 func NewSemaphore(n int) Semaphore { 20 if n <= 0 { 21 panic("semaphore with limit <=0") 22 } 23 ch := make(chan struct{}, n) 24 return Semaphore(ch) 25 } 26 27 // Acquire is used to acquire an available slot. 28 // Blocks until available. 29 func (s Semaphore) Acquire() { 30 s <- struct{}{} 31 } 32 33 // TryAcquire is used to do a non-blocking acquire. 34 // Returns a bool indicating success 35 func (s Semaphore) TryAcquire() bool { 36 select { 37 case s <- struct{}{}: 38 return true 39 default: 40 return false 41 } 42 } 43 44 // Release is used to return a slot. Acquire must 45 // be called as a pre-condition. 46 func (s Semaphore) Release() { 47 select { 48 case <-s: 49 default: 50 panic("release without an acquire") 51 } 52 } 53 54 // deduplicate a slice of strings 55 func uniqueStrings(s []string) []string { 56 if len(s) < 2 { 57 return s 58 } 59 60 sort.Strings(s) 61 result := make([]string, 1, len(s)) 62 result[0] = s[0] 63 for i := 1; i < len(s); i++ { 64 if s[i] != result[len(result)-1] { 65 result = append(result, s[i]) 66 } 67 } 68 return result 69 }