|  | // Copyright 2022 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package sync | 
|  |  | 
|  | // OnceFunc returns a function that invokes f only once. The returned function | 
|  | // may be called concurrently. | 
|  | // | 
|  | // If f panics, the returned function will panic with the same value on every call. | 
|  | func OnceFunc(f func()) func() { | 
|  | var ( | 
|  | once  Once | 
|  | valid bool | 
|  | p     any | 
|  | ) | 
|  | // Construct the inner closure just once to reduce costs on the fast path. | 
|  | g := func() { | 
|  | defer func() { | 
|  | p = recover() | 
|  | if !valid { | 
|  | // Re-panic immediately so on the first call the user gets a | 
|  | // complete stack trace into f. | 
|  | panic(p) | 
|  | } | 
|  | }() | 
|  | f() | 
|  | f = nil      // Do not keep f alive after invoking it. | 
|  | valid = true // Set only if f does not panic. | 
|  | } | 
|  | return func() { | 
|  | once.Do(g) | 
|  | if !valid { | 
|  | panic(p) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // OnceValue returns a function that invokes f only once and returns the value | 
|  | // returned by f. The returned function may be called concurrently. | 
|  | // | 
|  | // If f panics, the returned function will panic with the same value on every call. | 
|  | func OnceValue[T any](f func() T) func() T { | 
|  | var ( | 
|  | once   Once | 
|  | valid  bool | 
|  | p      any | 
|  | result T | 
|  | ) | 
|  | g := func() { | 
|  | defer func() { | 
|  | p = recover() | 
|  | if !valid { | 
|  | panic(p) | 
|  | } | 
|  | }() | 
|  | result = f() | 
|  | f = nil | 
|  | valid = true | 
|  | } | 
|  | return func() T { | 
|  | once.Do(g) | 
|  | if !valid { | 
|  | panic(p) | 
|  | } | 
|  | return result | 
|  | } | 
|  | } | 
|  |  | 
|  | // OnceValues returns a function that invokes f only once and returns the values | 
|  | // returned by f. The returned function may be called concurrently. | 
|  | // | 
|  | // If f panics, the returned function will panic with the same value on every call. | 
|  | func OnceValues[T1, T2 any](f func() (T1, T2)) func() (T1, T2) { | 
|  | var ( | 
|  | once  Once | 
|  | valid bool | 
|  | p     any | 
|  | r1    T1 | 
|  | r2    T2 | 
|  | ) | 
|  | g := func() { | 
|  | defer func() { | 
|  | p = recover() | 
|  | if !valid { | 
|  | panic(p) | 
|  | } | 
|  | }() | 
|  | r1, r2 = f() | 
|  | f = nil | 
|  | valid = true | 
|  | } | 
|  | return func() (T1, T2) { | 
|  | once.Do(g) | 
|  | if !valid { | 
|  | panic(p) | 
|  | } | 
|  | return r1, r2 | 
|  | } | 
|  | } |