.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.0 / internal / fakenet / conn.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/internal/fakenet/conn.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.0/internal/fakenet/conn.go
new file mode 100644 (file)
index 0000000..c9cdaf2
--- /dev/null
@@ -0,0 +1,129 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fakenet
+
+import (
+       "io"
+       "net"
+       "sync"
+       "time"
+)
+
+// NewConn returns a net.Conn built on top of the supplied reader and writer.
+// It decouples the read and write on the conn from the underlying stream
+// to enable Close to abort ones that are in progress.
+// It's primary use is to fake a network connection from stdin and stdout.
+func NewConn(name string, in io.ReadCloser, out io.WriteCloser) net.Conn {
+       c := &fakeConn{
+               name:   name,
+               reader: newFeeder(in.Read),
+               writer: newFeeder(out.Write),
+               in:     in,
+               out:    out,
+       }
+       go c.reader.run()
+       go c.writer.run()
+       return c
+}
+
+type fakeConn struct {
+       name   string
+       reader *connFeeder
+       writer *connFeeder
+       in     io.ReadCloser
+       out    io.WriteCloser
+}
+
+type fakeAddr string
+
+// connFeeder serializes calls to the source function (io.Reader.Read or
+// io.Writer.Write) by delegating them to a channel. This also allows calls to
+// be intercepted when the connection is closed, and cancelled early if the
+// connection is closed while the calls are still outstanding.
+type connFeeder struct {
+       source func([]byte) (int, error)
+       input  chan []byte
+       result chan feedResult
+       mu     sync.Mutex
+       closed bool
+       done   chan struct{}
+}
+
+type feedResult struct {
+       n   int
+       err error
+}
+
+func (c *fakeConn) Close() error {
+       c.reader.close()
+       c.writer.close()
+       c.in.Close()
+       c.out.Close()
+       return nil
+}
+
+func (c *fakeConn) Read(b []byte) (n int, err error)   { return c.reader.do(b) }
+func (c *fakeConn) Write(b []byte) (n int, err error)  { return c.writer.do(b) }
+func (c *fakeConn) LocalAddr() net.Addr                { return fakeAddr(c.name) }
+func (c *fakeConn) RemoteAddr() net.Addr               { return fakeAddr(c.name) }
+func (c *fakeConn) SetDeadline(t time.Time) error      { return nil }
+func (c *fakeConn) SetReadDeadline(t time.Time) error  { return nil }
+func (c *fakeConn) SetWriteDeadline(t time.Time) error { return nil }
+func (a fakeAddr) Network() string                     { return "fake" }
+func (a fakeAddr) String() string                      { return string(a) }
+
+func newFeeder(source func([]byte) (int, error)) *connFeeder {
+       return &connFeeder{
+               source: source,
+               input:  make(chan []byte),
+               result: make(chan feedResult),
+               done:   make(chan struct{}),
+       }
+}
+
+func (f *connFeeder) close() {
+       f.mu.Lock()
+       if !f.closed {
+               f.closed = true
+               close(f.done)
+       }
+       f.mu.Unlock()
+}
+
+func (f *connFeeder) do(b []byte) (n int, err error) {
+       // send the request to the worker
+       select {
+       case f.input <- b:
+       case <-f.done:
+               return 0, io.EOF
+       }
+       // get the result from the worker
+       select {
+       case r := <-f.result:
+               return r.n, r.err
+       case <-f.done:
+               return 0, io.EOF
+       }
+}
+
+func (f *connFeeder) run() {
+       var b []byte
+       for {
+               // wait for an input request
+               select {
+               case b = <-f.input:
+               case <-f.done:
+                       return
+               }
+               // invoke the underlying method
+               n, err := f.source(b)
+               // send the result back to the requester
+               select {
+               case f.result <- feedResult{n: n, err: err}:
+               case <-f.done:
+                       return
+               }
+       }
+}