github.com/lovishpuri/go-40569/src@v0.0.0-20230519171745-f8623e7c56cf/sync/oncefunc.go (about)

     1  // Copyright 2022 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package sync
     6  
     7  // OnceFunc returns a function that invokes f only once. The returned function
     8  // may be called concurrently.
     9  //
    10  // If f panics, the returned function will panic with the same value on every call.
    11  func OnceFunc(f func()) func() {
    12  	var (
    13  		once  Once
    14  		valid bool
    15  		p     any
    16  	)
    17  	// Construct the inner closure just once to reduce costs on the fast path.
    18  	g := func() {
    19  		defer func() {
    20  			p = recover()
    21  			if !valid {
    22  				// Re-panic immediately so on the first call the user gets a
    23  				// complete stack trace into f.
    24  				panic(p)
    25  			}
    26  		}()
    27  		f()
    28  		valid = true // Set only if f does not panic
    29  	}
    30  	return func() {
    31  		once.Do(g)
    32  		if !valid {
    33  			panic(p)
    34  		}
    35  	}
    36  }
    37  
    38  // OnceValue returns a function that invokes f only once and returns the value
    39  // returned by f. The returned function may be called concurrently.
    40  //
    41  // If f panics, the returned function will panic with the same value on every call.
    42  func OnceValue[T any](f func() T) func() T {
    43  	var (
    44  		once   Once
    45  		valid  bool
    46  		p      any
    47  		result T
    48  	)
    49  	g := func() {
    50  		defer func() {
    51  			p = recover()
    52  			if !valid {
    53  				panic(p)
    54  			}
    55  		}()
    56  		result = f()
    57  		valid = true
    58  	}
    59  	return func() T {
    60  		once.Do(g)
    61  		if !valid {
    62  			panic(p)
    63  		}
    64  		return result
    65  	}
    66  }
    67  
    68  // OnceValues returns a function that invokes f only once and returns the values
    69  // returned by f. The returned function may be called concurrently.
    70  //
    71  // If f panics, the returned function will panic with the same value on every call.
    72  func OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2) {
    73  	var (
    74  		once  Once
    75  		valid bool
    76  		p     any
    77  		r1    T1
    78  		r2    T2
    79  	)
    80  	g := func() {
    81  		defer func() {
    82  			p = recover()
    83  			if !valid {
    84  				panic(p)
    85  			}
    86  		}()
    87  		r1, r2 = f()
    88  		valid = true
    89  	}
    90  	return func() (T1, T2) {
    91  		once.Do(g)
    92  		if !valid {
    93  			panic(p)
    94  		}
    95  		return r1, r2
    96  	}
    97  }