Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / internal / jsonrpc2 / handler.go
1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package jsonrpc2
6
7 import (
8         "context"
9         "fmt"
10         "sync"
11
12         "golang.org/x/tools/internal/event"
13 )
14
15 // Handler is invoked to handle incoming requests.
16 // The Replier sends a reply to the request and must be called exactly once.
17 type Handler func(ctx context.Context, reply Replier, req Request) error
18
19 // Replier is passed to handlers to allow them to reply to the request.
20 // If err is set then result will be ignored.
21 type Replier func(ctx context.Context, result interface{}, err error) error
22
23 // MethodNotFound is a Handler that replies to all call requests with the
24 // standard method not found response.
25 // This should normally be the final handler in a chain.
26 func MethodNotFound(ctx context.Context, reply Replier, req Request) error {
27         return reply(ctx, nil, fmt.Errorf("%w: %q", ErrMethodNotFound, req.Method()))
28 }
29
30 // MustReplyHandler creates a Handler that panics if the wrapped handler does
31 // not call Reply for every request that it is passed.
32 func MustReplyHandler(handler Handler) Handler {
33         return func(ctx context.Context, reply Replier, req Request) error {
34                 called := false
35                 err := handler(ctx, func(ctx context.Context, result interface{}, err error) error {
36                         if called {
37                                 panic(fmt.Errorf("request %q replied to more than once", req.Method()))
38                         }
39                         called = true
40                         return reply(ctx, result, err)
41                 }, req)
42                 if !called {
43                         panic(fmt.Errorf("request %q was never replied to", req.Method()))
44                 }
45                 return err
46         }
47 }
48
49 // CancelHandler returns a handler that supports cancellation, and a function
50 // that can be used to trigger canceling in progress requests.
51 func CancelHandler(handler Handler) (Handler, func(id ID)) {
52         var mu sync.Mutex
53         handling := make(map[ID]context.CancelFunc)
54         wrapped := func(ctx context.Context, reply Replier, req Request) error {
55                 if call, ok := req.(*Call); ok {
56                         cancelCtx, cancel := context.WithCancel(ctx)
57                         ctx = cancelCtx
58                         mu.Lock()
59                         handling[call.ID()] = cancel
60                         mu.Unlock()
61                         innerReply := reply
62                         reply = func(ctx context.Context, result interface{}, err error) error {
63                                 mu.Lock()
64                                 delete(handling, call.ID())
65                                 mu.Unlock()
66                                 return innerReply(ctx, result, err)
67                         }
68                 }
69                 return handler(ctx, reply, req)
70         }
71         return wrapped, func(id ID) {
72                 mu.Lock()
73                 cancel, found := handling[id]
74                 mu.Unlock()
75                 if found {
76                         cancel()
77                 }
78         }
79 }
80
81 // AsyncHandler returns a handler that processes each request goes in its own
82 // goroutine.
83 // The handler returns immediately, without the request being processed.
84 // Each request then waits for the previous request to finish before it starts.
85 // This allows the stream to unblock at the cost of unbounded goroutines
86 // all stalled on the previous one.
87 func AsyncHandler(handler Handler) Handler {
88         nextRequest := make(chan struct{})
89         close(nextRequest)
90         return func(ctx context.Context, reply Replier, req Request) error {
91                 waitForPrevious := nextRequest
92                 nextRequest = make(chan struct{})
93                 unlockNext := nextRequest
94                 innerReply := reply
95                 reply = func(ctx context.Context, result interface{}, err error) error {
96                         close(unlockNext)
97                         return innerReply(ctx, result, err)
98                 }
99                 _, queueDone := event.Start(ctx, "queued")
100                 go func() {
101                         <-waitForPrevious
102                         queueDone()
103                         if err := handler(ctx, reply, req); err != nil {
104                                 event.Error(ctx, "jsonrpc2 async message delivery failed", err)
105                         }
106                 }()
107                 return nil
108         }
109 }