mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-04 01:22:25 -06:00 
			
		
		
		
	
		
			
	
	
		
			647 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			647 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								// Copyright (c) 2017-2023 Uber Technologies, Inc.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Permission is hereby granted, free of charge, to any person obtaining a copy
							 | 
						||
| 
								 | 
							
								// of this software and associated documentation files (the "Software"), to deal
							 | 
						||
| 
								 | 
							
								// in the Software without restriction, including without limitation the rights
							 | 
						||
| 
								 | 
							
								// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
							 | 
						||
| 
								 | 
							
								// copies of the Software, and to permit persons to whom the Software is
							 | 
						||
| 
								 | 
							
								// furnished to do so, subject to the following conditions:
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The above copyright notice and this permission notice shall be included in
							 | 
						||
| 
								 | 
							
								// all copies or substantial portions of the Software.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
							 | 
						||
| 
								 | 
							
								// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
							 | 
						||
| 
								 | 
							
								// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
							 | 
						||
| 
								 | 
							
								// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
							 | 
						||
| 
								 | 
							
								// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
							 | 
						||
| 
								 | 
							
								// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
							 | 
						||
| 
								 | 
							
								// THE SOFTWARE.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Package multierr allows combining one or more errors together.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// # Overview
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Errors can be combined with the use of the Combine function.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	multierr.Combine(
							 | 
						||
| 
								 | 
							
								//		reader.Close(),
							 | 
						||
| 
								 | 
							
								//		writer.Close(),
							 | 
						||
| 
								 | 
							
								//		conn.Close(),
							 | 
						||
| 
								 | 
							
								//	)
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// If only two errors are being combined, the Append function may be used
							 | 
						||
| 
								 | 
							
								// instead.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	err = multierr.Append(reader.Close(), writer.Close())
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The underlying list of errors for a returned error object may be retrieved
							 | 
						||
| 
								 | 
							
								// with the Errors function.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	errors := multierr.Errors(err)
							 | 
						||
| 
								 | 
							
								//	if len(errors) > 0 {
							 | 
						||
| 
								 | 
							
								//		fmt.Println("The following errors occurred:", errors)
							 | 
						||
| 
								 | 
							
								//	}
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// # Appending from a loop
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// You sometimes need to append into an error from a loop.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	var err error
							 | 
						||
| 
								 | 
							
								//	for _, item := range items {
							 | 
						||
| 
								 | 
							
								//		err = multierr.Append(err, process(item))
							 | 
						||
| 
								 | 
							
								//	}
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Cases like this may require knowledge of whether an individual instance
							 | 
						||
| 
								 | 
							
								// failed. This usually requires introduction of a new variable.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	var err error
							 | 
						||
| 
								 | 
							
								//	for _, item := range items {
							 | 
						||
| 
								 | 
							
								//		if perr := process(item); perr != nil {
							 | 
						||
| 
								 | 
							
								//			log.Warn("skipping item", item)
							 | 
						||
| 
								 | 
							
								//			err = multierr.Append(err, perr)
							 | 
						||
| 
								 | 
							
								//		}
							 | 
						||
| 
								 | 
							
								//	}
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// multierr includes AppendInto to simplify cases like this.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	var err error
							 | 
						||
| 
								 | 
							
								//	for _, item := range items {
							 | 
						||
| 
								 | 
							
								//		if multierr.AppendInto(&err, process(item)) {
							 | 
						||
| 
								 | 
							
								//			log.Warn("skipping item", item)
							 | 
						||
| 
								 | 
							
								//		}
							 | 
						||
| 
								 | 
							
								//	}
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// This will append the error into the err variable, and return true if that
							 | 
						||
| 
								 | 
							
								// individual error was non-nil.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// See [AppendInto] for more information.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// # Deferred Functions
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Go makes it possible to modify the return value of a function in a defer
							 | 
						||
| 
								 | 
							
								// block if the function was using named returns. This makes it possible to
							 | 
						||
| 
								 | 
							
								// record resource cleanup failures from deferred blocks.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	func sendRequest(req Request) (err error) {
							 | 
						||
| 
								 | 
							
								//		conn, err := openConnection()
							 | 
						||
| 
								 | 
							
								//		if err != nil {
							 | 
						||
| 
								 | 
							
								//			return err
							 | 
						||
| 
								 | 
							
								//		}
							 | 
						||
| 
								 | 
							
								//		defer func() {
							 | 
						||
| 
								 | 
							
								//			err = multierr.Append(err, conn.Close())
							 | 
						||
| 
								 | 
							
								//		}()
							 | 
						||
| 
								 | 
							
								//		// ...
							 | 
						||
| 
								 | 
							
								//	}
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// multierr provides the Invoker type and AppendInvoke function to make cases
							 | 
						||
| 
								 | 
							
								// like the above simpler and obviate the need for a closure. The following is
							 | 
						||
| 
								 | 
							
								// roughly equivalent to the example above.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	func sendRequest(req Request) (err error) {
							 | 
						||
| 
								 | 
							
								//		conn, err := openConnection()
							 | 
						||
| 
								 | 
							
								//		if err != nil {
							 | 
						||
| 
								 | 
							
								//			return err
							 | 
						||
| 
								 | 
							
								//		}
							 | 
						||
| 
								 | 
							
								//		defer multierr.AppendInvoke(&err, multierr.Close(conn))
							 | 
						||
| 
								 | 
							
								//		// ...
							 | 
						||
| 
								 | 
							
								//	}
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// See [AppendInvoke] and [Invoker] for more information.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// NOTE: If you're modifying an error from inside a defer, you MUST use a named
							 | 
						||
| 
								 | 
							
								// return value for that function.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// # Advanced Usage
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Errors returned by Combine and Append MAY implement the following
							 | 
						||
| 
								 | 
							
								// interface.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	type errorGroup interface {
							 | 
						||
| 
								 | 
							
								//		// Returns a slice containing the underlying list of errors.
							 | 
						||
| 
								 | 
							
								//		//
							 | 
						||
| 
								 | 
							
								//		// This slice MUST NOT be modified by the caller.
							 | 
						||
| 
								 | 
							
								//		Errors() []error
							 | 
						||
| 
								 | 
							
								//	}
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Note that if you need access to list of errors behind a multierr error, you
							 | 
						||
| 
								 | 
							
								// should prefer using the Errors function. That said, if you need cheap
							 | 
						||
| 
								 | 
							
								// read-only access to the underlying errors slice, you can attempt to cast
							 | 
						||
| 
								 | 
							
								// the error to this interface. You MUST handle the failure case gracefully
							 | 
						||
| 
								 | 
							
								// because errors returned by Combine and Append are not guaranteed to
							 | 
						||
| 
								 | 
							
								// implement this interface.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	var errors []error
							 | 
						||
| 
								 | 
							
								//	group, ok := err.(errorGroup)
							 | 
						||
| 
								 | 
							
								//	if ok {
							 | 
						||
| 
								 | 
							
								//		errors = group.Errors()
							 | 
						||
| 
								 | 
							
								//	} else {
							 | 
						||
| 
								 | 
							
								//		errors = []error{err}
							 | 
						||
| 
								 | 
							
								//	}
							 | 
						||
| 
								 | 
							
								package multierr // import "go.uber.org/multierr"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"bytes"
							 | 
						||
| 
								 | 
							
									"errors"
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
									"io"
							 | 
						||
| 
								 | 
							
									"strings"
							 | 
						||
| 
								 | 
							
									"sync"
							 | 
						||
| 
								 | 
							
									"sync/atomic"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var (
							 | 
						||
| 
								 | 
							
									// Separator for single-line error messages.
							 | 
						||
| 
								 | 
							
									_singlelineSeparator = []byte("; ")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Prefix for multi-line messages
							 | 
						||
| 
								 | 
							
									_multilinePrefix = []byte("the following errors occurred:")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Prefix for the first and following lines of an item in a list of
							 | 
						||
| 
								 | 
							
									// multi-line error messages.
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									// For example, if a single item is:
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									// 	foo
							 | 
						||
| 
								 | 
							
									// 	bar
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									// It will become,
							 | 
						||
| 
								 | 
							
									//
							 | 
						||
| 
								 | 
							
									// 	 -  foo
							 | 
						||
| 
								 | 
							
									// 	    bar
							 | 
						||
| 
								 | 
							
									_multilineSeparator = []byte("\n -  ")
							 | 
						||
| 
								 | 
							
									_multilineIndent    = []byte("    ")
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// _bufferPool is a pool of bytes.Buffers.
							 | 
						||
| 
								 | 
							
								var _bufferPool = sync.Pool{
							 | 
						||
| 
								 | 
							
									New: func() interface{} {
							 | 
						||
| 
								 | 
							
										return &bytes.Buffer{}
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type errorGroup interface {
							 | 
						||
| 
								 | 
							
									Errors() []error
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Errors returns a slice containing zero or more errors that the supplied
							 | 
						||
| 
								 | 
							
								// error is composed of. If the error is nil, a nil slice is returned.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	err := multierr.Append(r.Close(), w.Close())
							 | 
						||
| 
								 | 
							
								//	errors := multierr.Errors(err)
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// If the error is not composed of other errors, the returned slice contains
							 | 
						||
| 
								 | 
							
								// just the error that was passed in.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Callers of this function are free to modify the returned slice.
							 | 
						||
| 
								 | 
							
								func Errors(err error) []error {
							 | 
						||
| 
								 | 
							
									return extractErrors(err)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// multiError is an error that holds one or more errors.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// An instance of this is guaranteed to be non-empty and flattened. That is,
							 | 
						||
| 
								 | 
							
								// none of the errors inside multiError are other multiErrors.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// multiError formats to a semi-colon delimited list of error messages with
							 | 
						||
| 
								 | 
							
								// %v and with a more readable multi-line format with %+v.
							 | 
						||
| 
								 | 
							
								type multiError struct {
							 | 
						||
| 
								 | 
							
									copyNeeded atomic.Bool
							 | 
						||
| 
								 | 
							
									errors     []error
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Errors returns the list of underlying errors.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// This slice MUST NOT be modified.
							 | 
						||
| 
								 | 
							
								func (merr *multiError) Errors() []error {
							 | 
						||
| 
								 | 
							
									if merr == nil {
							 | 
						||
| 
								 | 
							
										return nil
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return merr.errors
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (merr *multiError) Error() string {
							 | 
						||
| 
								 | 
							
									if merr == nil {
							 | 
						||
| 
								 | 
							
										return ""
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									buff := _bufferPool.Get().(*bytes.Buffer)
							 | 
						||
| 
								 | 
							
									buff.Reset()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									merr.writeSingleline(buff)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									result := buff.String()
							 | 
						||
| 
								 | 
							
									_bufferPool.Put(buff)
							 | 
						||
| 
								 | 
							
									return result
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Every compares every error in the given err against the given target error
							 | 
						||
| 
								 | 
							
								// using [errors.Is], and returns true only if every comparison returned true.
							 | 
						||
| 
								 | 
							
								func Every(err error, target error) bool {
							 | 
						||
| 
								 | 
							
									for _, e := range extractErrors(err) {
							 | 
						||
| 
								 | 
							
										if !errors.Is(e, target) {
							 | 
						||
| 
								 | 
							
											return false
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return true
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (merr *multiError) Format(f fmt.State, c rune) {
							 | 
						||
| 
								 | 
							
									if c == 'v' && f.Flag('+') {
							 | 
						||
| 
								 | 
							
										merr.writeMultiline(f)
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										merr.writeSingleline(f)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (merr *multiError) writeSingleline(w io.Writer) {
							 | 
						||
| 
								 | 
							
									first := true
							 | 
						||
| 
								 | 
							
									for _, item := range merr.errors {
							 | 
						||
| 
								 | 
							
										if first {
							 | 
						||
| 
								 | 
							
											first = false
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											w.Write(_singlelineSeparator)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										io.WriteString(w, item.Error())
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (merr *multiError) writeMultiline(w io.Writer) {
							 | 
						||
| 
								 | 
							
									w.Write(_multilinePrefix)
							 | 
						||
| 
								 | 
							
									for _, item := range merr.errors {
							 | 
						||
| 
								 | 
							
										w.Write(_multilineSeparator)
							 | 
						||
| 
								 | 
							
										writePrefixLine(w, _multilineIndent, fmt.Sprintf("%+v", item))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Writes s to the writer with the given prefix added before each line after
							 | 
						||
| 
								 | 
							
								// the first.
							 | 
						||
| 
								 | 
							
								func writePrefixLine(w io.Writer, prefix []byte, s string) {
							 | 
						||
| 
								 | 
							
									first := true
							 | 
						||
| 
								 | 
							
									for len(s) > 0 {
							 | 
						||
| 
								 | 
							
										if first {
							 | 
						||
| 
								 | 
							
											first = false
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											w.Write(prefix)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										idx := strings.IndexByte(s, '\n')
							 | 
						||
| 
								 | 
							
										if idx < 0 {
							 | 
						||
| 
								 | 
							
											idx = len(s) - 1
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										io.WriteString(w, s[:idx+1])
							 | 
						||
| 
								 | 
							
										s = s[idx+1:]
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type inspectResult struct {
							 | 
						||
| 
								 | 
							
									// Number of top-level non-nil errors
							 | 
						||
| 
								 | 
							
									Count int
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Total number of errors including multiErrors
							 | 
						||
| 
								 | 
							
									Capacity int
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Index of the first non-nil error in the list. Value is meaningless if
							 | 
						||
| 
								 | 
							
									// Count is zero.
							 | 
						||
| 
								 | 
							
									FirstErrorIdx int
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Whether the list contains at least one multiError
							 | 
						||
| 
								 | 
							
									ContainsMultiError bool
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Inspects the given slice of errors so that we can efficiently allocate
							 | 
						||
| 
								 | 
							
								// space for it.
							 | 
						||
| 
								 | 
							
								func inspect(errors []error) (res inspectResult) {
							 | 
						||
| 
								 | 
							
									first := true
							 | 
						||
| 
								 | 
							
									for i, err := range errors {
							 | 
						||
| 
								 | 
							
										if err == nil {
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										res.Count++
							 | 
						||
| 
								 | 
							
										if first {
							 | 
						||
| 
								 | 
							
											first = false
							 | 
						||
| 
								 | 
							
											res.FirstErrorIdx = i
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if merr, ok := err.(*multiError); ok {
							 | 
						||
| 
								 | 
							
											res.Capacity += len(merr.errors)
							 | 
						||
| 
								 | 
							
											res.ContainsMultiError = true
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											res.Capacity++
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// fromSlice converts the given list of errors into a single error.
							 | 
						||
| 
								 | 
							
								func fromSlice(errors []error) error {
							 | 
						||
| 
								 | 
							
									// Don't pay to inspect small slices.
							 | 
						||
| 
								 | 
							
									switch len(errors) {
							 | 
						||
| 
								 | 
							
									case 0:
							 | 
						||
| 
								 | 
							
										return nil
							 | 
						||
| 
								 | 
							
									case 1:
							 | 
						||
| 
								 | 
							
										return errors[0]
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									res := inspect(errors)
							 | 
						||
| 
								 | 
							
									switch res.Count {
							 | 
						||
| 
								 | 
							
									case 0:
							 | 
						||
| 
								 | 
							
										return nil
							 | 
						||
| 
								 | 
							
									case 1:
							 | 
						||
| 
								 | 
							
										// only one non-nil entry
							 | 
						||
| 
								 | 
							
										return errors[res.FirstErrorIdx]
							 | 
						||
| 
								 | 
							
									case len(errors):
							 | 
						||
| 
								 | 
							
										if !res.ContainsMultiError {
							 | 
						||
| 
								 | 
							
											// Error list is flat. Make a copy of it
							 | 
						||
| 
								 | 
							
											// Otherwise "errors" escapes to the heap
							 | 
						||
| 
								 | 
							
											// unconditionally for all other cases.
							 | 
						||
| 
								 | 
							
											// This lets us optimize for the "no errors" case.
							 | 
						||
| 
								 | 
							
											out := append(([]error)(nil), errors...)
							 | 
						||
| 
								 | 
							
											return &multiError{errors: out}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									nonNilErrs := make([]error, 0, res.Capacity)
							 | 
						||
| 
								 | 
							
									for _, err := range errors[res.FirstErrorIdx:] {
							 | 
						||
| 
								 | 
							
										if err == nil {
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if nested, ok := err.(*multiError); ok {
							 | 
						||
| 
								 | 
							
											nonNilErrs = append(nonNilErrs, nested.errors...)
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											nonNilErrs = append(nonNilErrs, err)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return &multiError{errors: nonNilErrs}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Combine combines the passed errors into a single error.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// If zero arguments were passed or if all items are nil, a nil error is
							 | 
						||
| 
								 | 
							
								// returned.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	Combine(nil, nil)  // == nil
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// If only a single error was passed, it is returned as-is.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	Combine(err)  // == err
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Combine skips over nil arguments so this function may be used to combine
							 | 
						||
| 
								 | 
							
								// together errors from operations that fail independently of each other.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	multierr.Combine(
							 | 
						||
| 
								 | 
							
								//		reader.Close(),
							 | 
						||
| 
								 | 
							
								//		writer.Close(),
							 | 
						||
| 
								 | 
							
								//		pipe.Close(),
							 | 
						||
| 
								 | 
							
								//	)
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// If any of the passed errors is a multierr error, it will be flattened along
							 | 
						||
| 
								 | 
							
								// with the other errors.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	multierr.Combine(multierr.Combine(err1, err2), err3)
							 | 
						||
| 
								 | 
							
								//	// is the same as
							 | 
						||
| 
								 | 
							
								//	multierr.Combine(err1, err2, err3)
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The returned error formats into a readable multi-line error message if
							 | 
						||
| 
								 | 
							
								// formatted with %+v.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	fmt.Sprintf("%+v", multierr.Combine(err1, err2))
							 | 
						||
| 
								 | 
							
								func Combine(errors ...error) error {
							 | 
						||
| 
								 | 
							
									return fromSlice(errors)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Append appends the given errors together. Either value may be nil.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// This function is a specialization of Combine for the common case where
							 | 
						||
| 
								 | 
							
								// there are only two errors.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	err = multierr.Append(reader.Close(), writer.Close())
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The following pattern may also be used to record failure of deferred
							 | 
						||
| 
								 | 
							
								// operations without losing information about the original error.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	func doSomething(..) (err error) {
							 | 
						||
| 
								 | 
							
								//		f := acquireResource()
							 | 
						||
| 
								 | 
							
								//		defer func() {
							 | 
						||
| 
								 | 
							
								//			err = multierr.Append(err, f.Close())
							 | 
						||
| 
								 | 
							
								//		}()
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Note that the variable MUST be a named return to append an error to it from
							 | 
						||
| 
								 | 
							
								// the defer statement. See also [AppendInvoke].
							 | 
						||
| 
								 | 
							
								func Append(left error, right error) error {
							 | 
						||
| 
								 | 
							
									switch {
							 | 
						||
| 
								 | 
							
									case left == nil:
							 | 
						||
| 
								 | 
							
										return right
							 | 
						||
| 
								 | 
							
									case right == nil:
							 | 
						||
| 
								 | 
							
										return left
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if _, ok := right.(*multiError); !ok {
							 | 
						||
| 
								 | 
							
										if l, ok := left.(*multiError); ok && !l.copyNeeded.Swap(true) {
							 | 
						||
| 
								 | 
							
											// Common case where the error on the left is constantly being
							 | 
						||
| 
								 | 
							
											// appended to.
							 | 
						||
| 
								 | 
							
											errs := append(l.errors, right)
							 | 
						||
| 
								 | 
							
											return &multiError{errors: errs}
							 | 
						||
| 
								 | 
							
										} else if !ok {
							 | 
						||
| 
								 | 
							
											// Both errors are single errors.
							 | 
						||
| 
								 | 
							
											return &multiError{errors: []error{left, right}}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Either right or both, left and right, are multiErrors. Rely on usual
							 | 
						||
| 
								 | 
							
									// expensive logic.
							 | 
						||
| 
								 | 
							
									errors := [2]error{left, right}
							 | 
						||
| 
								 | 
							
									return fromSlice(errors[0:])
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// AppendInto appends an error into the destination of an error pointer and
							 | 
						||
| 
								 | 
							
								// returns whether the error being appended was non-nil.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	var err error
							 | 
						||
| 
								 | 
							
								//	multierr.AppendInto(&err, r.Close())
							 | 
						||
| 
								 | 
							
								//	multierr.AppendInto(&err, w.Close())
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The above is equivalent to,
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	err := multierr.Append(r.Close(), w.Close())
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// As AppendInto reports whether the provided error was non-nil, it may be
							 | 
						||
| 
								 | 
							
								// used to build a multierr error in a loop more ergonomically. For example:
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	var err error
							 | 
						||
| 
								 | 
							
								//	for line := range lines {
							 | 
						||
| 
								 | 
							
								//		var item Item
							 | 
						||
| 
								 | 
							
								//		if multierr.AppendInto(&err, parse(line, &item)) {
							 | 
						||
| 
								 | 
							
								//			continue
							 | 
						||
| 
								 | 
							
								//		}
							 | 
						||
| 
								 | 
							
								//		items = append(items, item)
							 | 
						||
| 
								 | 
							
								//	}
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Compare this with a version that relies solely on Append:
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	var err error
							 | 
						||
| 
								 | 
							
								//	for line := range lines {
							 | 
						||
| 
								 | 
							
								//		var item Item
							 | 
						||
| 
								 | 
							
								//		if parseErr := parse(line, &item); parseErr != nil {
							 | 
						||
| 
								 | 
							
								//			err = multierr.Append(err, parseErr)
							 | 
						||
| 
								 | 
							
								//			continue
							 | 
						||
| 
								 | 
							
								//		}
							 | 
						||
| 
								 | 
							
								//		items = append(items, item)
							 | 
						||
| 
								 | 
							
								//	}
							 | 
						||
| 
								 | 
							
								func AppendInto(into *error, err error) (errored bool) {
							 | 
						||
| 
								 | 
							
									if into == nil {
							 | 
						||
| 
								 | 
							
										// We panic if 'into' is nil. This is not documented above
							 | 
						||
| 
								 | 
							
										// because suggesting that the pointer must be non-nil may
							 | 
						||
| 
								 | 
							
										// confuse users into thinking that the error that it points
							 | 
						||
| 
								 | 
							
										// to must be non-nil.
							 | 
						||
| 
								 | 
							
										panic("misuse of multierr.AppendInto: into pointer must not be nil")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if err == nil {
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									*into = Append(*into, err)
							 | 
						||
| 
								 | 
							
									return true
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Invoker is an operation that may fail with an error. Use it with
							 | 
						||
| 
								 | 
							
								// AppendInvoke to append the result of calling the function into an error.
							 | 
						||
| 
								 | 
							
								// This allows you to conveniently defer capture of failing operations.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// See also, [Close] and [Invoke].
							 | 
						||
| 
								 | 
							
								type Invoker interface {
							 | 
						||
| 
								 | 
							
									Invoke() error
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Invoke wraps a function which may fail with an error to match the Invoker
							 | 
						||
| 
								 | 
							
								// interface. Use it to supply functions matching this signature to
							 | 
						||
| 
								 | 
							
								// AppendInvoke.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// For example,
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	func processReader(r io.Reader) (err error) {
							 | 
						||
| 
								 | 
							
								//		scanner := bufio.NewScanner(r)
							 | 
						||
| 
								 | 
							
								//		defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
							 | 
						||
| 
								 | 
							
								//		for scanner.Scan() {
							 | 
						||
| 
								 | 
							
								//			// ...
							 | 
						||
| 
								 | 
							
								//		}
							 | 
						||
| 
								 | 
							
								//		// ...
							 | 
						||
| 
								 | 
							
								//	}
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// In this example, the following line will construct the Invoker right away,
							 | 
						||
| 
								 | 
							
								// but defer the invocation of scanner.Err() until the function returns.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Note that the error you're appending to from the defer statement MUST be a
							 | 
						||
| 
								 | 
							
								// named return.
							 | 
						||
| 
								 | 
							
								type Invoke func() error
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Invoke calls the supplied function and returns its result.
							 | 
						||
| 
								 | 
							
								func (i Invoke) Invoke() error { return i() }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Close builds an Invoker that closes the provided io.Closer. Use it with
							 | 
						||
| 
								 | 
							
								// AppendInvoke to close io.Closers and append their results into an error.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// For example,
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	func processFile(path string) (err error) {
							 | 
						||
| 
								 | 
							
								//		f, err := os.Open(path)
							 | 
						||
| 
								 | 
							
								//		if err != nil {
							 | 
						||
| 
								 | 
							
								//			return err
							 | 
						||
| 
								 | 
							
								//		}
							 | 
						||
| 
								 | 
							
								//		defer multierr.AppendInvoke(&err, multierr.Close(f))
							 | 
						||
| 
								 | 
							
								//		return processReader(f)
							 | 
						||
| 
								 | 
							
								//	}
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// In this example, multierr.Close will construct the Invoker right away, but
							 | 
						||
| 
								 | 
							
								// defer the invocation of f.Close until the function returns.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	defer multierr.AppendInvoke(&err, multierr.Close(f))
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Note that the error you're appending to from the defer statement MUST be a
							 | 
						||
| 
								 | 
							
								// named return.
							 | 
						||
| 
								 | 
							
								func Close(closer io.Closer) Invoker {
							 | 
						||
| 
								 | 
							
									return Invoke(closer.Close)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// AppendInvoke appends the result of calling the given Invoker into the
							 | 
						||
| 
								 | 
							
								// provided error pointer. Use it with named returns to safely defer
							 | 
						||
| 
								 | 
							
								// invocation of fallible operations until a function returns, and capture the
							 | 
						||
| 
								 | 
							
								// resulting errors.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	func doSomething(...) (err error) {
							 | 
						||
| 
								 | 
							
								//		// ...
							 | 
						||
| 
								 | 
							
								//		f, err := openFile(..)
							 | 
						||
| 
								 | 
							
								//		if err != nil {
							 | 
						||
| 
								 | 
							
								//			return err
							 | 
						||
| 
								 | 
							
								//		}
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//		// multierr will call f.Close() when this function returns and
							 | 
						||
| 
								 | 
							
								//		// if the operation fails, its append its error into the
							 | 
						||
| 
								 | 
							
								//		// returned error.
							 | 
						||
| 
								 | 
							
								//		defer multierr.AppendInvoke(&err, multierr.Close(f))
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//		scanner := bufio.NewScanner(f)
							 | 
						||
| 
								 | 
							
								//		// Similarly, this scheduled scanner.Err to be called and
							 | 
						||
| 
								 | 
							
								//		// inspected when the function returns and append its error
							 | 
						||
| 
								 | 
							
								//		// into the returned error.
							 | 
						||
| 
								 | 
							
								//		defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//		// ...
							 | 
						||
| 
								 | 
							
								//	}
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// NOTE: If used with a defer, the error variable MUST be a named return.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Without defer, AppendInvoke behaves exactly like AppendInto.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	err := // ...
							 | 
						||
| 
								 | 
							
								//	multierr.AppendInvoke(&err, mutltierr.Invoke(foo))
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	// ...is roughly equivalent to...
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	err := // ...
							 | 
						||
| 
								 | 
							
								//	multierr.AppendInto(&err, foo())
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// The advantage of the indirection introduced by Invoker is to make it easy
							 | 
						||
| 
								 | 
							
								// to defer the invocation of a function. Without this indirection, the
							 | 
						||
| 
								 | 
							
								// invoked function will be evaluated at the time of the defer block rather
							 | 
						||
| 
								 | 
							
								// than when the function returns.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	// BAD: This is likely not what the caller intended. This will evaluate
							 | 
						||
| 
								 | 
							
								//	// foo() right away and append its result into the error when the
							 | 
						||
| 
								 | 
							
								//	// function returns.
							 | 
						||
| 
								 | 
							
								//	defer multierr.AppendInto(&err, foo())
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	// GOOD: This will defer invocation of foo unutil the function returns.
							 | 
						||
| 
								 | 
							
								//	defer multierr.AppendInvoke(&err, multierr.Invoke(foo))
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// multierr provides a few Invoker implementations out of the box for
							 | 
						||
| 
								 | 
							
								// convenience. See [Invoker] for more information.
							 | 
						||
| 
								 | 
							
								func AppendInvoke(into *error, invoker Invoker) {
							 | 
						||
| 
								 | 
							
									AppendInto(into, invoker.Invoke())
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// AppendFunc is a shorthand for [AppendInvoke].
							 | 
						||
| 
								 | 
							
								// It allows using function or method value directly
							 | 
						||
| 
								 | 
							
								// without having to wrap it into an [Invoker] interface.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//	func doSomething(...) (err error) {
							 | 
						||
| 
								 | 
							
								//		w, err := startWorker(...)
							 | 
						||
| 
								 | 
							
								//		if err != nil {
							 | 
						||
| 
								 | 
							
								//			return err
							 | 
						||
| 
								 | 
							
								//		}
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//		// multierr will call w.Stop() when this function returns and
							 | 
						||
| 
								 | 
							
								//		// if the operation fails, it appends its error into the
							 | 
						||
| 
								 | 
							
								//		// returned error.
							 | 
						||
| 
								 | 
							
								//		defer multierr.AppendFunc(&err, w.Stop)
							 | 
						||
| 
								 | 
							
								//	}
							 | 
						||
| 
								 | 
							
								func AppendFunc(into *error, fn func() error) {
							 | 
						||
| 
								 | 
							
									AppendInvoke(into, Invoke(fn))
							 | 
						||
| 
								 | 
							
								}
							 |