| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package gae | |
| 6 | |
| 7 import ( | |
| 8 "fmt" | |
| 9 "reflect" | |
| 10 "sync" | |
| 11 ) | |
| 12 | |
| 13 // MultiError is returned by batch operations when there are errors with | |
| 14 // particular elements. Errors will be in a one-to-one correspondence with | |
| 15 // the input elements; successful elements will have a nil entry. | |
| 16 type MultiError []error | |
| 17 | |
| 18 func (m MultiError) Error() string { | |
| 19 s, n := "", 0 | |
| 20 for _, e := range m { | |
| 21 if e != nil { | |
| 22 if n == 0 { | |
| 23 s = e.Error() | |
| 24 } | |
| 25 n++ | |
| 26 } | |
| 27 } | |
| 28 switch n { | |
| 29 case 0: | |
| 30 return "(0 errors)" | |
| 31 case 1: | |
| 32 return s | |
| 33 case 2: | |
| 34 return s + " (and 1 other error)" | |
| 35 } | |
| 36 return fmt.Sprintf("%s (and %d other errors)", s, n-1) | |
| 37 } | |
| 38 | |
| 39 // SingleError provides a simple way to uwrap a MultiError if you know that it | |
| 40 // could only ever contain one element. | |
| 41 // | |
| 42 // If err is a MultiError, return its first element. Otherwise, return err. | |
| 43 func SingleError(err error) error { | |
| 44 if me, ok := err.(MultiError); ok { | |
| 45 if len(me) == 0 { | |
| 46 return nil | |
| 47 } | |
| 48 return me[0] | |
| 49 } | |
| 50 return err | |
| 51 } | |
| 52 | |
| 53 var ( | |
| 54 multiErrorType = reflect.TypeOf(MultiError(nil)) | |
| 55 ) | |
| 56 | |
| 57 // FixError will convert a backend-specific non-plain error type to the | |
| 58 // corresponding gae wrapper type. This is intended to be used solely by | |
| 59 // implementations (not user code). A correct implementation of the gae wrapper | |
| 60 // should never return an SDK-specific error type if an alternate type appears | |
| 61 // in this file. | |
| 62 func FixError(err error) error { | |
| 63 if err != nil { | |
| 64 // we know that err already conforms to the error interface (or
the caller's | |
| 65 // method wouldn't compile), so check to see if the error's unde
rlying type | |
| 66 // looks like one of the special error types we implement. | |
| 67 v := reflect.ValueOf(err) | |
| 68 if v.Type().ConvertibleTo(multiErrorType) { | |
| 69 err = v.Convert(multiErrorType).Interface().(error) | |
| 70 } | |
| 71 } | |
| 72 return err | |
| 73 } | |
| 74 | |
| 75 // LazyMultiError is a lazily-constructed MultiError. You specify the target | |
| 76 // MultiError size up front (as Size), and then you call Assign for each error | |
| 77 // encountered, and it's potential index. The MultiError will only be allocated | |
| 78 // if one of the Assign'd errors is non-nil. Similarly, Get will retrieve either | |
| 79 // the allocated MultiError, or nil if no error was encountered. | |
| 80 type LazyMultiError struct { | |
| 81 sync.Mutex | |
| 82 | |
| 83 Size int | |
| 84 me MultiError | |
| 85 } | |
| 86 | |
| 87 // Assign semantically assigns the error to the given index in the MultiError. | |
| 88 // If the error is nil, no action is taken. Otherwise the MultiError is | |
| 89 // allocated to its full size (if not already), and the error assigned into it. | |
| 90 func (e *LazyMultiError) Assign(i int, err error) { | |
| 91 if err == nil { | |
| 92 return | |
| 93 } | |
| 94 e.Lock() | |
| 95 defer e.Unlock() | |
| 96 if e.me == nil { | |
| 97 e.me = make(MultiError, e.Size) | |
| 98 } | |
| 99 e.me[i] = err | |
| 100 } | |
| 101 | |
| 102 // Get returns the MultiError, or nil, if no non-nil error was Assign'd. | |
| 103 func (e *LazyMultiError) Get() error { | |
| 104 e.Lock() | |
| 105 defer e.Unlock() | |
| 106 if e.me == nil { | |
| 107 return nil | |
| 108 } | |
| 109 return e.me | |
| 110 } | |
| OLD | NEW |