main
1//go:build linux && !go1.21
2
3// Copyright (C) 2024 SUSE LLC. All rights reserved.
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file.
6
7package securejoin
8
9import (
10 "sync"
11)
12
13// These are very minimal implementations of functions that appear in Go 1.21's
14// stdlib, included so that we can build on older Go versions. Most are
15// borrowed directly from the stdlib, and a few are modified to be "obviously
16// correct" without needing to copy too many other helpers.
17
18// clearSlice is equivalent to the builtin clear from Go 1.21.
19// Copied from the Go 1.24 stdlib implementation.
20func clearSlice[S ~[]E, E any](slice S) {
21 var zero E
22 for i := range slice {
23 slice[i] = zero
24 }
25}
26
27// Copied from the Go 1.24 stdlib implementation.
28func slices_IndexFunc[S ~[]E, E any](s S, f func(E) bool) int {
29 for i := range s {
30 if f(s[i]) {
31 return i
32 }
33 }
34 return -1
35}
36
37// Copied from the Go 1.24 stdlib implementation.
38func slices_DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S {
39 i := slices_IndexFunc(s, del)
40 if i == -1 {
41 return s
42 }
43 // Don't start copying elements until we find one to delete.
44 for j := i + 1; j < len(s); j++ {
45 if v := s[j]; !del(v) {
46 s[i] = v
47 i++
48 }
49 }
50 clearSlice(s[i:]) // zero/nil out the obsolete elements, for GC
51 return s[:i]
52}
53
54// Similar to the stdlib slices.Contains, except that we don't have
55// slices.Index so we need to use slices.IndexFunc for this non-Func helper.
56func slices_Contains[S ~[]E, E comparable](s S, v E) bool {
57 return slices_IndexFunc(s, func(e E) bool { return e == v }) >= 0
58}
59
60// Copied from the Go 1.24 stdlib implementation.
61func slices_Clone[S ~[]E, E any](s S) S {
62 // Preserve nil in case it matters.
63 if s == nil {
64 return nil
65 }
66 return append(S([]E{}), s...)
67}
68
69// Copied from the Go 1.24 stdlib implementation.
70func sync_OnceValue[T any](f func() T) func() T {
71 var (
72 once sync.Once
73 valid bool
74 p any
75 result T
76 )
77 g := func() {
78 defer func() {
79 p = recover()
80 if !valid {
81 panic(p)
82 }
83 }()
84 result = f()
85 f = nil
86 valid = true
87 }
88 return func() T {
89 once.Do(g)
90 if !valid {
91 panic(p)
92 }
93 return result
94 }
95}
96
97// Copied from the Go 1.24 stdlib implementation.
98func sync_OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2) {
99 var (
100 once sync.Once
101 valid bool
102 p any
103 r1 T1
104 r2 T2
105 )
106 g := func() {
107 defer func() {
108 p = recover()
109 if !valid {
110 panic(p)
111 }
112 }()
113 r1, r2 = f()
114 f = nil
115 valid = true
116 }
117 return func() (T1, T2) {
118 once.Do(g)
119 if !valid {
120 panic(p)
121 }
122 return r1, r2
123 }
124}