Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1520)

Side by Side Diff: common/errors/multierror.go

Issue 1249933002: Move multierror logic into luci-go. (Closed) Base URL: https://github.com/luci/luci-go@add_mathrand
Patch Set: rename Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « common/errors/markederror_test.go ('k') | common/errors/multierror_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package errors 5 package errors
6 6
7 import ( 7 import (
8 "fmt" 8 "fmt"
9 "reflect"
10 "sync"
11 )
12
13 var (
14 multiErrorType = reflect.TypeOf(MultiError(nil))
9 ) 15 )
10 16
11 // MultiError is a simple `error` implementation which represents multiple 17 // MultiError is a simple `error` implementation which represents multiple
12 // `error` objects in one. 18 // `error` objects in one.
13 type MultiError []error 19 type MultiError []error
14 20
21 func (m MultiError) Error() string {
22 s, n := "", 0
23 for _, e := range m {
24 if e != nil {
25 if n == 0 {
26 s = e.Error()
27 }
28 n++
29 }
30 }
31 switch n {
32 case 0:
33 return "(0 errors)"
34 case 1:
35 return s
36 case 2:
37 return s + " (and 1 other error)"
38 }
39 return fmt.Sprintf("%s (and %d other errors)", s, n-1)
40 }
41
42 // SingleError provides a simple way to uwrap a MultiError if you know that it
43 // could only ever contain one element.
44 //
45 // If err is a MultiError, return its first element. Otherwise, return err.
46 func SingleError(err error) error {
47 if me, ok := err.(MultiError); ok {
48 if len(me) == 0 {
49 return nil
50 }
51 return me[0]
52 }
53 return err
54 }
55
15 // MultiErrorFromErrors takes an error-channel, blocks on it, and returns 56 // MultiErrorFromErrors takes an error-channel, blocks on it, and returns
16 // a MultiError for any errors pushed to it over the channel, or nil if 57 // a MultiError for any errors pushed to it over the channel, or nil if
17 // all the errors were nil. 58 // all the errors were nil.
18 func MultiErrorFromErrors(ch <-chan error) error { 59 func MultiErrorFromErrors(ch <-chan error) error {
19 if ch == nil { 60 if ch == nil {
20 return nil 61 return nil
21 } 62 }
22 ret := MultiError(nil) 63 ret := MultiError(nil)
23 for e := range ch { 64 for e := range ch {
24 if e == nil { 65 if e == nil {
25 continue 66 continue
26 } 67 }
27 ret = append(ret, e) 68 ret = append(ret, e)
28 } 69 }
29 if len(ret) == 0 { 70 if len(ret) == 0 {
30 return nil 71 return nil
31 } 72 }
32 return ret 73 return ret
33 } 74 }
34 75
35 func (m MultiError) Error() string { 76 // LazyMultiError is a lazily-constructed MultiError. You specify the target
36 » return fmt.Sprintf("%+q", []error(m)) 77 // MultiError size up front (as Size), and then you call Assign for each error
78 // encountered, and it's potential index. The MultiError will only be allocated
79 // if one of the Assign'd errors is non-nil. Similarly, Get will retrieve either
80 // the allocated MultiError, or nil if no error was encountered.
81 type LazyMultiError struct {
82 » sync.Mutex
83
84 » Size int
M-A Ruel 2015/08/10 19:00:21 I don't like that it is exported. I'd prefer to ha
85 » me MultiError
37 } 86 }
87
88 // Assign semantically assigns the error to the given index in the MultiError.
89 // If the error is nil, no action is taken. Otherwise the MultiError is
90 // allocated to its full size (if not already), and the error assigned into it.
91 func (e *LazyMultiError) Assign(i int, err error) {
M-A Ruel 2015/08/10 19:00:21 Why not Add(err error) instead?
92 if err == nil {
93 return
94 }
95 e.Lock()
96 defer e.Unlock()
97 if e.me == nil {
98 e.me = make(MultiError, e.Size)
99 }
100 e.me[i] = err
M-A Ruel 2015/08/10 19:00:21 That may crash quite unexpectedly at runtime, espe
101 }
102
103 // Get returns the MultiError, or nil, if no non-nil error was Assign'd.
104 func (e *LazyMultiError) Get() error {
105 e.Lock()
106 defer e.Unlock()
107 if e.me == nil {
108 return nil
109 }
110 return e.me
111 }
112
113 // Fix will convert a MultiError compatible type (e.g. []error) to this
114 // version of MultiError.
115 func Fix(err error) error {
M-A Ruel 2015/08/10 19:00:21 What's wrong with this instead? if e, ok := err.(
116 if err != nil {
117 // we know that err already conforms to the error interface (or the caller's
118 // method wouldn't compile), so check to see if the error's unde rlying type
119 // looks like one of the special error types we implement.
120 v := reflect.ValueOf(err)
121 if v.Type().ConvertibleTo(multiErrorType) {
122 err = v.Convert(multiErrorType).Interface().(error)
123 }
124 }
125 return err
126 }
OLDNEW
« no previous file with comments | « common/errors/markederror_test.go ('k') | common/errors/multierror_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698