ducky/devices

Paddy 2015-11-27 Parent:b6494e1a499e

11:683050b4546b Go to Latest

ducky/devices/vendor/golang.org/x/net/context/context.go

Return ErrDeviceNotFound when updating devices. If we can't find the Device we're supposed to update, return an ErrDeviceNotFound error. Write a unit test that tests for this behaviour.

History
paddy@0 1 // Copyright 2014 The Go Authors. All rights reserved.
paddy@0 2 // Use of this source code is governed by a BSD-style
paddy@0 3 // license that can be found in the LICENSE file.
paddy@0 4
paddy@0 5 // Package context defines the Context type, which carries deadlines,
paddy@0 6 // cancelation signals, and other request-scoped values across API boundaries
paddy@0 7 // and between processes.
paddy@0 8 //
paddy@0 9 // Incoming requests to a server should create a Context, and outgoing calls to
paddy@0 10 // servers should accept a Context. The chain of function calls between must
paddy@0 11 // propagate the Context, optionally replacing it with a modified copy created
paddy@0 12 // using WithDeadline, WithTimeout, WithCancel, or WithValue.
paddy@0 13 //
paddy@0 14 // Programs that use Contexts should follow these rules to keep interfaces
paddy@0 15 // consistent across packages and enable static analysis tools to check context
paddy@0 16 // propagation:
paddy@0 17 //
paddy@0 18 // Do not store Contexts inside a struct type; instead, pass a Context
paddy@0 19 // explicitly to each function that needs it. The Context should be the first
paddy@0 20 // parameter, typically named ctx:
paddy@0 21 //
paddy@0 22 // func DoSomething(ctx context.Context, arg Arg) error {
paddy@0 23 // // ... use ctx ...
paddy@0 24 // }
paddy@0 25 //
paddy@0 26 // Do not pass a nil Context, even if a function permits it. Pass context.TODO
paddy@0 27 // if you are unsure about which Context to use.
paddy@0 28 //
paddy@0 29 // Use context Values only for request-scoped data that transits processes and
paddy@0 30 // APIs, not for passing optional parameters to functions.
paddy@0 31 //
paddy@0 32 // The same Context may be passed to functions running in different goroutines;
paddy@0 33 // Contexts are safe for simultaneous use by multiple goroutines.
paddy@0 34 //
paddy@0 35 // See http://blog.golang.org/context for example code for a server that uses
paddy@0 36 // Contexts.
paddy@0 37 package context
paddy@0 38
paddy@0 39 import (
paddy@0 40 "errors"
paddy@0 41 "fmt"
paddy@0 42 "sync"
paddy@0 43 "time"
paddy@0 44 )
paddy@0 45
paddy@0 46 // A Context carries a deadline, a cancelation signal, and other values across
paddy@0 47 // API boundaries.
paddy@0 48 //
paddy@0 49 // Context's methods may be called by multiple goroutines simultaneously.
paddy@0 50 type Context interface {
paddy@0 51 // Deadline returns the time when work done on behalf of this context
paddy@0 52 // should be canceled. Deadline returns ok==false when no deadline is
paddy@0 53 // set. Successive calls to Deadline return the same results.
paddy@0 54 Deadline() (deadline time.Time, ok bool)
paddy@0 55
paddy@0 56 // Done returns a channel that's closed when work done on behalf of this
paddy@0 57 // context should be canceled. Done may return nil if this context can
paddy@0 58 // never be canceled. Successive calls to Done return the same value.
paddy@0 59 //
paddy@0 60 // WithCancel arranges for Done to be closed when cancel is called;
paddy@0 61 // WithDeadline arranges for Done to be closed when the deadline
paddy@0 62 // expires; WithTimeout arranges for Done to be closed when the timeout
paddy@0 63 // elapses.
paddy@0 64 //
paddy@0 65 // Done is provided for use in select statements:
paddy@0 66 //
paddy@0 67 // // Stream generates values with DoSomething and sends them to out
paddy@0 68 // // until DoSomething returns an error or ctx.Done is closed.
paddy@0 69 // func Stream(ctx context.Context, out <-chan Value) error {
paddy@0 70 // for {
paddy@0 71 // v, err := DoSomething(ctx)
paddy@0 72 // if err != nil {
paddy@0 73 // return err
paddy@0 74 // }
paddy@0 75 // select {
paddy@0 76 // case <-ctx.Done():
paddy@0 77 // return ctx.Err()
paddy@0 78 // case out <- v:
paddy@0 79 // }
paddy@0 80 // }
paddy@0 81 // }
paddy@0 82 //
paddy@0 83 // See http://blog.golang.org/pipelines for more examples of how to use
paddy@0 84 // a Done channel for cancelation.
paddy@0 85 Done() <-chan struct{}
paddy@0 86
paddy@0 87 // Err returns a non-nil error value after Done is closed. Err returns
paddy@0 88 // Canceled if the context was canceled or DeadlineExceeded if the
paddy@0 89 // context's deadline passed. No other values for Err are defined.
paddy@0 90 // After Done is closed, successive calls to Err return the same value.
paddy@0 91 Err() error
paddy@0 92
paddy@0 93 // Value returns the value associated with this context for key, or nil
paddy@0 94 // if no value is associated with key. Successive calls to Value with
paddy@0 95 // the same key returns the same result.
paddy@0 96 //
paddy@0 97 // Use context values only for request-scoped data that transits
paddy@0 98 // processes and API boundaries, not for passing optional parameters to
paddy@0 99 // functions.
paddy@0 100 //
paddy@0 101 // A key identifies a specific value in a Context. Functions that wish
paddy@0 102 // to store values in Context typically allocate a key in a global
paddy@0 103 // variable then use that key as the argument to context.WithValue and
paddy@0 104 // Context.Value. A key can be any type that supports equality;
paddy@0 105 // packages should define keys as an unexported type to avoid
paddy@0 106 // collisions.
paddy@0 107 //
paddy@0 108 // Packages that define a Context key should provide type-safe accessors
paddy@0 109 // for the values stores using that key:
paddy@0 110 //
paddy@0 111 // // Package user defines a User type that's stored in Contexts.
paddy@0 112 // package user
paddy@0 113 //
paddy@0 114 // import "golang.org/x/net/context"
paddy@0 115 //
paddy@0 116 // // User is the type of value stored in the Contexts.
paddy@0 117 // type User struct {...}
paddy@0 118 //
paddy@0 119 // // key is an unexported type for keys defined in this package.
paddy@0 120 // // This prevents collisions with keys defined in other packages.
paddy@0 121 // type key int
paddy@0 122 //
paddy@0 123 // // userKey is the key for user.User values in Contexts. It is
paddy@0 124 // // unexported; clients use user.NewContext and user.FromContext
paddy@0 125 // // instead of using this key directly.
paddy@0 126 // var userKey key = 0
paddy@0 127 //
paddy@0 128 // // NewContext returns a new Context that carries value u.
paddy@0 129 // func NewContext(ctx context.Context, u *User) context.Context {
paddy@0 130 // return context.WithValue(ctx, userKey, u)
paddy@0 131 // }
paddy@0 132 //
paddy@0 133 // // FromContext returns the User value stored in ctx, if any.
paddy@0 134 // func FromContext(ctx context.Context) (*User, bool) {
paddy@0 135 // u, ok := ctx.Value(userKey).(*User)
paddy@0 136 // return u, ok
paddy@0 137 // }
paddy@0 138 Value(key interface{}) interface{}
paddy@0 139 }
paddy@0 140
paddy@0 141 // Canceled is the error returned by Context.Err when the context is canceled.
paddy@0 142 var Canceled = errors.New("context canceled")
paddy@0 143
paddy@0 144 // DeadlineExceeded is the error returned by Context.Err when the context's
paddy@0 145 // deadline passes.
paddy@0 146 var DeadlineExceeded = errors.New("context deadline exceeded")
paddy@0 147
paddy@0 148 // An emptyCtx is never canceled, has no values, and has no deadline. It is not
paddy@0 149 // struct{}, since vars of this type must have distinct addresses.
paddy@0 150 type emptyCtx int
paddy@0 151
paddy@0 152 func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
paddy@0 153 return
paddy@0 154 }
paddy@0 155
paddy@0 156 func (*emptyCtx) Done() <-chan struct{} {
paddy@0 157 return nil
paddy@0 158 }
paddy@0 159
paddy@0 160 func (*emptyCtx) Err() error {
paddy@0 161 return nil
paddy@0 162 }
paddy@0 163
paddy@0 164 func (*emptyCtx) Value(key interface{}) interface{} {
paddy@0 165 return nil
paddy@0 166 }
paddy@0 167
paddy@0 168 func (e *emptyCtx) String() string {
paddy@0 169 switch e {
paddy@0 170 case background:
paddy@0 171 return "context.Background"
paddy@0 172 case todo:
paddy@0 173 return "context.TODO"
paddy@0 174 }
paddy@0 175 return "unknown empty Context"
paddy@0 176 }
paddy@0 177
paddy@0 178 var (
paddy@0 179 background = new(emptyCtx)
paddy@0 180 todo = new(emptyCtx)
paddy@0 181 )
paddy@0 182
paddy@0 183 // Background returns a non-nil, empty Context. It is never canceled, has no
paddy@0 184 // values, and has no deadline. It is typically used by the main function,
paddy@0 185 // initialization, and tests, and as the top-level Context for incoming
paddy@0 186 // requests.
paddy@0 187 func Background() Context {
paddy@0 188 return background
paddy@0 189 }
paddy@0 190
paddy@0 191 // TODO returns a non-nil, empty Context. Code should use context.TODO when
paddy@0 192 // it's unclear which Context to use or it's is not yet available (because the
paddy@0 193 // surrounding function has not yet been extended to accept a Context
paddy@0 194 // parameter). TODO is recognized by static analysis tools that determine
paddy@0 195 // whether Contexts are propagated correctly in a program.
paddy@0 196 func TODO() Context {
paddy@0 197 return todo
paddy@0 198 }
paddy@0 199
paddy@0 200 // A CancelFunc tells an operation to abandon its work.
paddy@0 201 // A CancelFunc does not wait for the work to stop.
paddy@0 202 // After the first call, subsequent calls to a CancelFunc do nothing.
paddy@0 203 type CancelFunc func()
paddy@0 204
paddy@0 205 // WithCancel returns a copy of parent with a new Done channel. The returned
paddy@0 206 // context's Done channel is closed when the returned cancel function is called
paddy@0 207 // or when the parent context's Done channel is closed, whichever happens first.
paddy@0 208 //
paddy@0 209 // Canceling this context releases resources associated with it, so code should
paddy@0 210 // call cancel as soon as the operations running in this Context complete.
paddy@0 211 func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
paddy@0 212 c := newCancelCtx(parent)
paddy@0 213 propagateCancel(parent, &c)
paddy@0 214 return &c, func() { c.cancel(true, Canceled) }
paddy@0 215 }
paddy@0 216
paddy@0 217 // newCancelCtx returns an initialized cancelCtx.
paddy@0 218 func newCancelCtx(parent Context) cancelCtx {
paddy@0 219 return cancelCtx{
paddy@0 220 Context: parent,
paddy@0 221 done: make(chan struct{}),
paddy@0 222 }
paddy@0 223 }
paddy@0 224
paddy@0 225 // propagateCancel arranges for child to be canceled when parent is.
paddy@0 226 func propagateCancel(parent Context, child canceler) {
paddy@0 227 if parent.Done() == nil {
paddy@0 228 return // parent is never canceled
paddy@0 229 }
paddy@0 230 if p, ok := parentCancelCtx(parent); ok {
paddy@0 231 p.mu.Lock()
paddy@0 232 if p.err != nil {
paddy@0 233 // parent has already been canceled
paddy@0 234 child.cancel(false, p.err)
paddy@0 235 } else {
paddy@0 236 if p.children == nil {
paddy@0 237 p.children = make(map[canceler]bool)
paddy@0 238 }
paddy@0 239 p.children[child] = true
paddy@0 240 }
paddy@0 241 p.mu.Unlock()
paddy@0 242 } else {
paddy@0 243 go func() {
paddy@0 244 select {
paddy@0 245 case <-parent.Done():
paddy@0 246 child.cancel(false, parent.Err())
paddy@0 247 case <-child.Done():
paddy@0 248 }
paddy@0 249 }()
paddy@0 250 }
paddy@0 251 }
paddy@0 252
paddy@0 253 // parentCancelCtx follows a chain of parent references until it finds a
paddy@0 254 // *cancelCtx. This function understands how each of the concrete types in this
paddy@0 255 // package represents its parent.
paddy@0 256 func parentCancelCtx(parent Context) (*cancelCtx, bool) {
paddy@0 257 for {
paddy@0 258 switch c := parent.(type) {
paddy@0 259 case *cancelCtx:
paddy@0 260 return c, true
paddy@0 261 case *timerCtx:
paddy@0 262 return &c.cancelCtx, true
paddy@0 263 case *valueCtx:
paddy@0 264 parent = c.Context
paddy@0 265 default:
paddy@0 266 return nil, false
paddy@0 267 }
paddy@0 268 }
paddy@0 269 }
paddy@0 270
paddy@0 271 // removeChild removes a context from its parent.
paddy@0 272 func removeChild(parent Context, child canceler) {
paddy@0 273 p, ok := parentCancelCtx(parent)
paddy@0 274 if !ok {
paddy@0 275 return
paddy@0 276 }
paddy@0 277 p.mu.Lock()
paddy@0 278 if p.children != nil {
paddy@0 279 delete(p.children, child)
paddy@0 280 }
paddy@0 281 p.mu.Unlock()
paddy@0 282 }
paddy@0 283
paddy@0 284 // A canceler is a context type that can be canceled directly. The
paddy@0 285 // implementations are *cancelCtx and *timerCtx.
paddy@0 286 type canceler interface {
paddy@0 287 cancel(removeFromParent bool, err error)
paddy@0 288 Done() <-chan struct{}
paddy@0 289 }
paddy@0 290
paddy@0 291 // A cancelCtx can be canceled. When canceled, it also cancels any children
paddy@0 292 // that implement canceler.
paddy@0 293 type cancelCtx struct {
paddy@0 294 Context
paddy@0 295
paddy@0 296 done chan struct{} // closed by the first cancel call.
paddy@0 297
paddy@0 298 mu sync.Mutex
paddy@0 299 children map[canceler]bool // set to nil by the first cancel call
paddy@0 300 err error // set to non-nil by the first cancel call
paddy@0 301 }
paddy@0 302
paddy@0 303 func (c *cancelCtx) Done() <-chan struct{} {
paddy@0 304 return c.done
paddy@0 305 }
paddy@0 306
paddy@0 307 func (c *cancelCtx) Err() error {
paddy@0 308 c.mu.Lock()
paddy@0 309 defer c.mu.Unlock()
paddy@0 310 return c.err
paddy@0 311 }
paddy@0 312
paddy@0 313 func (c *cancelCtx) String() string {
paddy@0 314 return fmt.Sprintf("%v.WithCancel", c.Context)
paddy@0 315 }
paddy@0 316
paddy@0 317 // cancel closes c.done, cancels each of c's children, and, if
paddy@0 318 // removeFromParent is true, removes c from its parent's children.
paddy@0 319 func (c *cancelCtx) cancel(removeFromParent bool, err error) {
paddy@0 320 if err == nil {
paddy@0 321 panic("context: internal error: missing cancel error")
paddy@0 322 }
paddy@0 323 c.mu.Lock()
paddy@0 324 if c.err != nil {
paddy@0 325 c.mu.Unlock()
paddy@0 326 return // already canceled
paddy@0 327 }
paddy@0 328 c.err = err
paddy@0 329 close(c.done)
paddy@0 330 for child := range c.children {
paddy@0 331 // NOTE: acquiring the child's lock while holding parent's lock.
paddy@0 332 child.cancel(false, err)
paddy@0 333 }
paddy@0 334 c.children = nil
paddy@0 335 c.mu.Unlock()
paddy@0 336
paddy@0 337 if removeFromParent {
paddy@0 338 removeChild(c.Context, c)
paddy@0 339 }
paddy@0 340 }
paddy@0 341
paddy@0 342 // WithDeadline returns a copy of the parent context with the deadline adjusted
paddy@0 343 // to be no later than d. If the parent's deadline is already earlier than d,
paddy@0 344 // WithDeadline(parent, d) is semantically equivalent to parent. The returned
paddy@0 345 // context's Done channel is closed when the deadline expires, when the returned
paddy@0 346 // cancel function is called, or when the parent context's Done channel is
paddy@0 347 // closed, whichever happens first.
paddy@0 348 //
paddy@0 349 // Canceling this context releases resources associated with it, so code should
paddy@0 350 // call cancel as soon as the operations running in this Context complete.
paddy@0 351 func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
paddy@0 352 if cur, ok := parent.Deadline(); ok && cur.Before(deadline) {
paddy@0 353 // The current deadline is already sooner than the new one.
paddy@0 354 return WithCancel(parent)
paddy@0 355 }
paddy@0 356 c := &timerCtx{
paddy@0 357 cancelCtx: newCancelCtx(parent),
paddy@0 358 deadline: deadline,
paddy@0 359 }
paddy@0 360 propagateCancel(parent, c)
paddy@0 361 d := deadline.Sub(time.Now())
paddy@0 362 if d <= 0 {
paddy@0 363 c.cancel(true, DeadlineExceeded) // deadline has already passed
paddy@0 364 return c, func() { c.cancel(true, Canceled) }
paddy@0 365 }
paddy@0 366 c.mu.Lock()
paddy@0 367 defer c.mu.Unlock()
paddy@0 368 if c.err == nil {
paddy@0 369 c.timer = time.AfterFunc(d, func() {
paddy@0 370 c.cancel(true, DeadlineExceeded)
paddy@0 371 })
paddy@0 372 }
paddy@0 373 return c, func() { c.cancel(true, Canceled) }
paddy@0 374 }
paddy@0 375
paddy@0 376 // A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
paddy@0 377 // implement Done and Err. It implements cancel by stopping its timer then
paddy@0 378 // delegating to cancelCtx.cancel.
paddy@0 379 type timerCtx struct {
paddy@0 380 cancelCtx
paddy@0 381 timer *time.Timer // Under cancelCtx.mu.
paddy@0 382
paddy@0 383 deadline time.Time
paddy@0 384 }
paddy@0 385
paddy@0 386 func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
paddy@0 387 return c.deadline, true
paddy@0 388 }
paddy@0 389
paddy@0 390 func (c *timerCtx) String() string {
paddy@0 391 return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now()))
paddy@0 392 }
paddy@0 393
paddy@0 394 func (c *timerCtx) cancel(removeFromParent bool, err error) {
paddy@0 395 c.cancelCtx.cancel(false, err)
paddy@0 396 if removeFromParent {
paddy@0 397 // Remove this timerCtx from its parent cancelCtx's children.
paddy@0 398 removeChild(c.cancelCtx.Context, c)
paddy@0 399 }
paddy@0 400 c.mu.Lock()
paddy@0 401 if c.timer != nil {
paddy@0 402 c.timer.Stop()
paddy@0 403 c.timer = nil
paddy@0 404 }
paddy@0 405 c.mu.Unlock()
paddy@0 406 }
paddy@0 407
paddy@0 408 // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
paddy@0 409 //
paddy@0 410 // Canceling this context releases resources associated with it, so code should
paddy@0 411 // call cancel as soon as the operations running in this Context complete:
paddy@0 412 //
paddy@0 413 // func slowOperationWithTimeout(ctx context.Context) (Result, error) {
paddy@0 414 // ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
paddy@0 415 // defer cancel() // releases resources if slowOperation completes before timeout elapses
paddy@0 416 // return slowOperation(ctx)
paddy@0 417 // }
paddy@0 418 func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
paddy@0 419 return WithDeadline(parent, time.Now().Add(timeout))
paddy@0 420 }
paddy@0 421
paddy@0 422 // WithValue returns a copy of parent in which the value associated with key is
paddy@0 423 // val.
paddy@0 424 //
paddy@0 425 // Use context Values only for request-scoped data that transits processes and
paddy@0 426 // APIs, not for passing optional parameters to functions.
paddy@0 427 func WithValue(parent Context, key interface{}, val interface{}) Context {
paddy@0 428 return &valueCtx{parent, key, val}
paddy@0 429 }
paddy@0 430
paddy@0 431 // A valueCtx carries a key-value pair. It implements Value for that key and
paddy@0 432 // delegates all other calls to the embedded Context.
paddy@0 433 type valueCtx struct {
paddy@0 434 Context
paddy@0 435 key, val interface{}
paddy@0 436 }
paddy@0 437
paddy@0 438 func (c *valueCtx) String() string {
paddy@0 439 return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val)
paddy@0 440 }
paddy@0 441
paddy@0 442 func (c *valueCtx) Value(key interface{}) interface{} {
paddy@0 443 if c.key == key {
paddy@0 444 return c.val
paddy@0 445 }
paddy@0 446 return c.Context.Value(key)
paddy@0 447 }