go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/errors/lazymultierror.go (about)

     1  // Copyright 2015 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package errors
    16  
    17  import (
    18  	"sync"
    19  )
    20  
    21  // LazyMultiError is a lazily-constructed MultiError.
    22  //
    23  // LazyMultiError is like MultiError, except that you know the ultimate size up
    24  // front, and then you call Assign for each error encountered, and it's
    25  // potential index. The underlying MultiError will only be allocated if one of
    26  // the Assign'd errors is non-nil. Similarly, Get will retrieve either the
    27  // allocated MultiError, or nil if no error was encountered.
    28  // Build one with NewLazyMultiError.
    29  type LazyMultiError interface {
    30  	// Assign semantically assigns the error to the given index in the MultiError.
    31  	// If the error is nil, no action is taken. Otherwise the MultiError is
    32  	// allocated to its full size (if not already), and the error assigned into
    33  	// it.
    34  	//
    35  	// Returns true iff err != nil (i.e. "was it assigned?"), so you can use this
    36  	// like:
    37  	//   if !lme.Assign(i, err) {
    38  	//     // stuff requiring err == nil
    39  	//   }
    40  	Assign(int, error) bool
    41  
    42  	// GetOne returns the error at the given index (which may be nil)
    43  	GetOne(int) error
    44  
    45  	// Get returns the MultiError, or nil, if no non-nil error was Assign'd.
    46  	Get() error
    47  }
    48  
    49  type lazyMultiError struct {
    50  	sync.Mutex
    51  
    52  	size int
    53  	me   MultiError
    54  }
    55  
    56  // NewLazyMultiError makes a new LazyMultiError of the provided size.
    57  func NewLazyMultiError(size int) LazyMultiError {
    58  	return &lazyMultiError{size: size}
    59  }
    60  
    61  func (e *lazyMultiError) Assign(i int, err error) bool {
    62  	if err == nil {
    63  		return false
    64  	}
    65  	e.Lock()
    66  	defer e.Unlock()
    67  	if e.me == nil {
    68  		e.me = make(MultiError, e.size)
    69  	}
    70  	e.me[i] = err
    71  	return true
    72  }
    73  
    74  func (e *lazyMultiError) GetOne(i int) error {
    75  	e.Lock()
    76  	defer e.Unlock()
    77  	if e.me == nil {
    78  		return nil
    79  	}
    80  	return e.me[i]
    81  }
    82  
    83  func (e *lazyMultiError) Get() error {
    84  	e.Lock()
    85  	defer e.Unlock()
    86  	if e.me == nil {
    87  		return nil
    88  	}
    89  	return e.me
    90  }