Vendor main dependencies.
This commit is contained in:
parent
49a09ab7dd
commit
dd5e3fba01
2738 changed files with 1045689 additions and 0 deletions
20
vendor/github.com/eapache/channels/LICENSE
generated
vendored
Normal file
20
vendor/github.com/eapache/channels/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Evan Huus
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
87
vendor/github.com/eapache/channels/batching_channel.go
generated
vendored
Normal file
87
vendor/github.com/eapache/channels/batching_channel.go
generated
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
package channels
|
||||
|
||||
// BatchingChannel implements the Channel interface, with the change that instead of producing individual elements
|
||||
// on Out(), it batches together the entire internal buffer each time. Trying to construct an unbuffered batching channel
|
||||
// will panic, that configuration is not supported (and provides no benefit over an unbuffered NativeChannel).
|
||||
type BatchingChannel struct {
|
||||
input, output chan interface{}
|
||||
length chan int
|
||||
buffer []interface{}
|
||||
size BufferCap
|
||||
}
|
||||
|
||||
func NewBatchingChannel(size BufferCap) *BatchingChannel {
|
||||
if size == None {
|
||||
panic("channels: BatchingChannel does not support unbuffered behaviour")
|
||||
}
|
||||
if size < 0 && size != Infinity {
|
||||
panic("channels: invalid negative size in NewBatchingChannel")
|
||||
}
|
||||
ch := &BatchingChannel{
|
||||
input: make(chan interface{}),
|
||||
output: make(chan interface{}),
|
||||
length: make(chan int),
|
||||
size: size,
|
||||
}
|
||||
go ch.batchingBuffer()
|
||||
return ch
|
||||
}
|
||||
|
||||
func (ch *BatchingChannel) In() chan<- interface{} {
|
||||
return ch.input
|
||||
}
|
||||
|
||||
// Out returns a <-chan interface{} in order that BatchingChannel conforms to the standard Channel interface provided
|
||||
// by this package, however each output value is guaranteed to be of type []interface{} - a slice collecting the most
|
||||
// recent batch of values sent on the In channel. The slice is guaranteed to not be empty or nil. In practice the net
|
||||
// result is that you need an additional type assertion to access the underlying values.
|
||||
func (ch *BatchingChannel) Out() <-chan interface{} {
|
||||
return ch.output
|
||||
}
|
||||
|
||||
func (ch *BatchingChannel) Len() int {
|
||||
return <-ch.length
|
||||
}
|
||||
|
||||
func (ch *BatchingChannel) Cap() BufferCap {
|
||||
return ch.size
|
||||
}
|
||||
|
||||
func (ch *BatchingChannel) Close() {
|
||||
close(ch.input)
|
||||
}
|
||||
|
||||
func (ch *BatchingChannel) batchingBuffer() {
|
||||
var input, output, nextInput chan interface{}
|
||||
nextInput = ch.input
|
||||
input = nextInput
|
||||
|
||||
for input != nil || output != nil {
|
||||
select {
|
||||
case elem, open := <-input:
|
||||
if open {
|
||||
ch.buffer = append(ch.buffer, elem)
|
||||
} else {
|
||||
input = nil
|
||||
nextInput = nil
|
||||
}
|
||||
case output <- ch.buffer:
|
||||
ch.buffer = nil
|
||||
case ch.length <- len(ch.buffer):
|
||||
}
|
||||
|
||||
if len(ch.buffer) == 0 {
|
||||
input = nextInput
|
||||
output = nil
|
||||
} else if ch.size != Infinity && len(ch.buffer) >= int(ch.size) {
|
||||
input = nil
|
||||
output = ch.output
|
||||
} else {
|
||||
input = nextInput
|
||||
output = ch.output
|
||||
}
|
||||
}
|
||||
|
||||
close(ch.output)
|
||||
close(ch.length)
|
||||
}
|
54
vendor/github.com/eapache/channels/black_hole.go
generated
vendored
Normal file
54
vendor/github.com/eapache/channels/black_hole.go
generated
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
package channels
|
||||
|
||||
// BlackHole implements the InChannel interface and provides an analogue for the "Discard" variable in
|
||||
// the ioutil package - it never blocks, and simply discards every value it reads. The number of items
|
||||
// discarded in this way is counted and returned from Len.
|
||||
type BlackHole struct {
|
||||
input chan interface{}
|
||||
length chan int
|
||||
count int
|
||||
}
|
||||
|
||||
func NewBlackHole() *BlackHole {
|
||||
ch := &BlackHole{
|
||||
input: make(chan interface{}),
|
||||
length: make(chan int),
|
||||
}
|
||||
go ch.discard()
|
||||
return ch
|
||||
}
|
||||
|
||||
func (ch *BlackHole) In() chan<- interface{} {
|
||||
return ch.input
|
||||
}
|
||||
|
||||
func (ch *BlackHole) Len() int {
|
||||
val, open := <-ch.length
|
||||
if open {
|
||||
return val
|
||||
} else {
|
||||
return ch.count
|
||||
}
|
||||
}
|
||||
|
||||
func (ch *BlackHole) Cap() BufferCap {
|
||||
return Infinity
|
||||
}
|
||||
|
||||
func (ch *BlackHole) Close() {
|
||||
close(ch.input)
|
||||
}
|
||||
|
||||
func (ch *BlackHole) discard() {
|
||||
for {
|
||||
select {
|
||||
case _, open := <-ch.input:
|
||||
if !open {
|
||||
close(ch.length)
|
||||
return
|
||||
}
|
||||
ch.count++
|
||||
case ch.length <- ch.count:
|
||||
}
|
||||
}
|
||||
}
|
277
vendor/github.com/eapache/channels/channels.go
generated
vendored
Normal file
277
vendor/github.com/eapache/channels/channels.go
generated
vendored
Normal file
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
Package channels provides a collection of helper functions, interfaces and implementations for
|
||||
working with and extending the capabilities of golang's existing channels. The main interface of
|
||||
interest is Channel, though sub-interfaces are also provided for cases where the full Channel interface
|
||||
cannot be met (for example, InChannel for write-only channels).
|
||||
|
||||
For integration with native typed golang channels, functions Wrap and Unwrap are provided which do the
|
||||
appropriate type conversions. The NativeChannel, NativeInChannel and NativeOutChannel type definitions
|
||||
are also provided for use with native channels which already carry values of type interface{}.
|
||||
|
||||
The heart of the package consists of several distinct implementations of the Channel interface, including
|
||||
channels backed by special buffers (resizable, infinite, ring buffers, etc) and other useful types. A
|
||||
"black hole" channel for discarding unwanted values (similar in purpose to ioutil.Discard or /dev/null)
|
||||
rounds out the set.
|
||||
|
||||
Helper functions for operating on Channels include Pipe and Tee (which behave much like their Unix
|
||||
namesakes), as well as Multiplex and Distribute. "Weak" versions of these functions also exist, which
|
||||
do not close their output channel(s) on completion.
|
||||
|
||||
Due to limitations of Go's type system, importing this library directly is often not practical for
|
||||
production code. It serves equally well, however, as a reference guide and template for implementing
|
||||
many common idioms; if you use it in this way I would appreciate the inclusion of some sort of credit
|
||||
in the resulting code.
|
||||
|
||||
Warning: several types in this package provide so-called "infinite" buffers. Be *very* careful using
|
||||
these, as no buffer is truly infinite - if such a buffer grows too large your program will run out of
|
||||
memory and crash. Caveat emptor.
|
||||
*/
|
||||
package channels
|
||||
|
||||
import "reflect"
|
||||
|
||||
// BufferCap represents the capacity of the buffer backing a channel. Valid values consist of all
|
||||
// positive integers, as well as the special values below.
|
||||
type BufferCap int
|
||||
|
||||
const (
|
||||
// None is the capacity for channels that have no buffer at all.
|
||||
None BufferCap = 0
|
||||
// Infinity is the capacity for channels with no limit on their buffer size.
|
||||
Infinity BufferCap = -1
|
||||
)
|
||||
|
||||
// Buffer is an interface for any channel that provides access to query the state of its buffer.
|
||||
// Even unbuffered channels can implement this interface by simply returning 0 from Len() and None from Cap().
|
||||
type Buffer interface {
|
||||
Len() int // The number of elements currently buffered.
|
||||
Cap() BufferCap // The maximum number of elements that can be buffered.
|
||||
}
|
||||
|
||||
// SimpleInChannel is an interface representing a writeable channel that does not necessarily
|
||||
// implement the Buffer interface.
|
||||
type SimpleInChannel interface {
|
||||
In() chan<- interface{} // The writeable end of the channel.
|
||||
Close() // Closes the channel. It is an error to write to In() after calling Close().
|
||||
}
|
||||
|
||||
// InChannel is an interface representing a writeable channel with a buffer.
|
||||
type InChannel interface {
|
||||
SimpleInChannel
|
||||
Buffer
|
||||
}
|
||||
|
||||
// SimpleOutChannel is an interface representing a readable channel that does not necessarily
|
||||
// implement the Buffer interface.
|
||||
type SimpleOutChannel interface {
|
||||
Out() <-chan interface{} // The readable end of the channel.
|
||||
}
|
||||
|
||||
// OutChannel is an interface representing a readable channel implementing the Buffer interface.
|
||||
type OutChannel interface {
|
||||
SimpleOutChannel
|
||||
Buffer
|
||||
}
|
||||
|
||||
// SimpleChannel is an interface representing a channel that is both readable and writeable,
|
||||
// but does not necessarily implement the Buffer interface.
|
||||
type SimpleChannel interface {
|
||||
SimpleInChannel
|
||||
SimpleOutChannel
|
||||
}
|
||||
|
||||
// Channel is an interface representing a channel that is readable, writeable and implements
|
||||
// the Buffer interface
|
||||
type Channel interface {
|
||||
SimpleChannel
|
||||
Buffer
|
||||
}
|
||||
|
||||
func pipe(input SimpleOutChannel, output SimpleInChannel, closeWhenDone bool) {
|
||||
for elem := range input.Out() {
|
||||
output.In() <- elem
|
||||
}
|
||||
if closeWhenDone {
|
||||
output.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func multiplex(output SimpleInChannel, inputs []SimpleOutChannel, closeWhenDone bool) {
|
||||
inputCount := len(inputs)
|
||||
cases := make([]reflect.SelectCase, inputCount)
|
||||
for i := range cases {
|
||||
cases[i].Dir = reflect.SelectRecv
|
||||
cases[i].Chan = reflect.ValueOf(inputs[i].Out())
|
||||
}
|
||||
for inputCount > 0 {
|
||||
chosen, recv, recvOK := reflect.Select(cases)
|
||||
if recvOK {
|
||||
output.In() <- recv.Interface()
|
||||
} else {
|
||||
cases[chosen].Chan = reflect.ValueOf(nil)
|
||||
inputCount--
|
||||
}
|
||||
}
|
||||
if closeWhenDone {
|
||||
output.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func tee(input SimpleOutChannel, outputs []SimpleInChannel, closeWhenDone bool) {
|
||||
cases := make([]reflect.SelectCase, len(outputs))
|
||||
for i := range cases {
|
||||
cases[i].Dir = reflect.SelectSend
|
||||
}
|
||||
for elem := range input.Out() {
|
||||
for i := range cases {
|
||||
cases[i].Chan = reflect.ValueOf(outputs[i].In())
|
||||
cases[i].Send = reflect.ValueOf(elem)
|
||||
}
|
||||
for _ = range cases {
|
||||
chosen, _, _ := reflect.Select(cases)
|
||||
cases[chosen].Chan = reflect.ValueOf(nil)
|
||||
}
|
||||
}
|
||||
if closeWhenDone {
|
||||
for i := range outputs {
|
||||
outputs[i].Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func distribute(input SimpleOutChannel, outputs []SimpleInChannel, closeWhenDone bool) {
|
||||
cases := make([]reflect.SelectCase, len(outputs))
|
||||
for i := range cases {
|
||||
cases[i].Dir = reflect.SelectSend
|
||||
cases[i].Chan = reflect.ValueOf(outputs[i].In())
|
||||
}
|
||||
for elem := range input.Out() {
|
||||
for i := range cases {
|
||||
cases[i].Send = reflect.ValueOf(elem)
|
||||
}
|
||||
reflect.Select(cases)
|
||||
}
|
||||
if closeWhenDone {
|
||||
for i := range outputs {
|
||||
outputs[i].Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pipe connects the input channel to the output channel so that
|
||||
// they behave as if a single channel.
|
||||
func Pipe(input SimpleOutChannel, output SimpleInChannel) {
|
||||
go pipe(input, output, true)
|
||||
}
|
||||
|
||||
// Multiplex takes an arbitrary number of input channels and multiplexes their output into a single output
|
||||
// channel. When all input channels have been closed, the output channel is closed. Multiplex with a single
|
||||
// input channel is equivalent to Pipe (though slightly less efficient).
|
||||
func Multiplex(output SimpleInChannel, inputs ...SimpleOutChannel) {
|
||||
if len(inputs) == 0 {
|
||||
panic("channels: Multiplex requires at least one input")
|
||||
}
|
||||
go multiplex(output, inputs, true)
|
||||
}
|
||||
|
||||
// Tee (like its Unix namesake) takes a single input channel and an arbitrary number of output channels
|
||||
// and duplicates each input into every output. When the input channel is closed, all outputs channels are closed.
|
||||
// Tee with a single output channel is equivalent to Pipe (though slightly less efficient).
|
||||
func Tee(input SimpleOutChannel, outputs ...SimpleInChannel) {
|
||||
if len(outputs) == 0 {
|
||||
panic("channels: Tee requires at least one output")
|
||||
}
|
||||
go tee(input, outputs, true)
|
||||
}
|
||||
|
||||
// Distribute takes a single input channel and an arbitrary number of output channels and duplicates each input
|
||||
// into *one* available output. If multiple outputs are waiting for a value, one is chosen at random. When the
|
||||
// input channel is closed, all outputs channels are closed. Distribute with a single output channel is
|
||||
// equivalent to Pipe (though slightly less efficient).
|
||||
func Distribute(input SimpleOutChannel, outputs ...SimpleInChannel) {
|
||||
if len(outputs) == 0 {
|
||||
panic("channels: Distribute requires at least one output")
|
||||
}
|
||||
go distribute(input, outputs, true)
|
||||
}
|
||||
|
||||
// WeakPipe behaves like Pipe (connecting the two channels) except that it does not close
|
||||
// the output channel when the input channel is closed.
|
||||
func WeakPipe(input SimpleOutChannel, output SimpleInChannel) {
|
||||
go pipe(input, output, false)
|
||||
}
|
||||
|
||||
// WeakMultiplex behaves like Multiplex (multiplexing multiple inputs into a single output) except that it does not close
|
||||
// the output channel when the input channels are closed.
|
||||
func WeakMultiplex(output SimpleInChannel, inputs ...SimpleOutChannel) {
|
||||
if len(inputs) == 0 {
|
||||
panic("channels: WeakMultiplex requires at least one input")
|
||||
}
|
||||
go multiplex(output, inputs, false)
|
||||
}
|
||||
|
||||
// WeakTee behaves like Tee (duplicating a single input into multiple outputs) except that it does not close
|
||||
// the output channels when the input channel is closed.
|
||||
func WeakTee(input SimpleOutChannel, outputs ...SimpleInChannel) {
|
||||
if len(outputs) == 0 {
|
||||
panic("channels: WeakTee requires at least one output")
|
||||
}
|
||||
go tee(input, outputs, false)
|
||||
}
|
||||
|
||||
// WeakDistribute behaves like Distribute (distributing a single input amongst multiple outputs) except that
|
||||
// it does not close the output channels when the input channel is closed.
|
||||
func WeakDistribute(input SimpleOutChannel, outputs ...SimpleInChannel) {
|
||||
if len(outputs) == 0 {
|
||||
panic("channels: WeakDistribute requires at least one output")
|
||||
}
|
||||
go distribute(input, outputs, false)
|
||||
}
|
||||
|
||||
// Wrap takes any readable channel type (chan or <-chan but not chan<-) and
|
||||
// exposes it as a SimpleOutChannel for easy integration with existing channel sources.
|
||||
// It panics if the input is not a readable channel.
|
||||
func Wrap(ch interface{}) SimpleOutChannel {
|
||||
t := reflect.TypeOf(ch)
|
||||
if t.Kind() != reflect.Chan || t.ChanDir()&reflect.RecvDir == 0 {
|
||||
panic("channels: input to Wrap must be readable channel")
|
||||
}
|
||||
realChan := make(chan interface{})
|
||||
|
||||
go func() {
|
||||
v := reflect.ValueOf(ch)
|
||||
for {
|
||||
x, ok := v.Recv()
|
||||
if !ok {
|
||||
close(realChan)
|
||||
return
|
||||
}
|
||||
realChan <- x.Interface()
|
||||
}
|
||||
}()
|
||||
|
||||
return NativeOutChannel(realChan)
|
||||
}
|
||||
|
||||
// Unwrap takes a SimpleOutChannel and uses reflection to pipe it to a typed native channel for
|
||||
// easy integration with existing channel sources. Output can be any writable channel type (chan or chan<-).
|
||||
// It panics if the output is not a writable channel, or if a value is received that cannot be sent on the
|
||||
// output channel.
|
||||
func Unwrap(input SimpleOutChannel, output interface{}) {
|
||||
t := reflect.TypeOf(output)
|
||||
if t.Kind() != reflect.Chan || t.ChanDir()&reflect.SendDir == 0 {
|
||||
panic("channels: input to Unwrap must be readable channel")
|
||||
}
|
||||
|
||||
go func() {
|
||||
v := reflect.ValueOf(output)
|
||||
for {
|
||||
x, ok := <-input.Out()
|
||||
if !ok {
|
||||
v.Close()
|
||||
return
|
||||
}
|
||||
v.Send(reflect.ValueOf(x))
|
||||
}
|
||||
}()
|
||||
}
|
72
vendor/github.com/eapache/channels/infinite_channel.go
generated
vendored
Normal file
72
vendor/github.com/eapache/channels/infinite_channel.go
generated
vendored
Normal file
|
@ -0,0 +1,72 @@
|
|||
package channels
|
||||
|
||||
import "github.com/eapache/queue"
|
||||
|
||||
// InfiniteChannel implements the Channel interface with an infinite buffer between the input and the output.
|
||||
type InfiniteChannel struct {
|
||||
input, output chan interface{}
|
||||
length chan int
|
||||
buffer *queue.Queue
|
||||
}
|
||||
|
||||
func NewInfiniteChannel() *InfiniteChannel {
|
||||
ch := &InfiniteChannel{
|
||||
input: make(chan interface{}),
|
||||
output: make(chan interface{}),
|
||||
length: make(chan int),
|
||||
buffer: queue.New(),
|
||||
}
|
||||
go ch.infiniteBuffer()
|
||||
return ch
|
||||
}
|
||||
|
||||
func (ch *InfiniteChannel) In() chan<- interface{} {
|
||||
return ch.input
|
||||
}
|
||||
|
||||
func (ch *InfiniteChannel) Out() <-chan interface{} {
|
||||
return ch.output
|
||||
}
|
||||
|
||||
func (ch *InfiniteChannel) Len() int {
|
||||
return <-ch.length
|
||||
}
|
||||
|
||||
func (ch *InfiniteChannel) Cap() BufferCap {
|
||||
return Infinity
|
||||
}
|
||||
|
||||
func (ch *InfiniteChannel) Close() {
|
||||
close(ch.input)
|
||||
}
|
||||
|
||||
func (ch *InfiniteChannel) infiniteBuffer() {
|
||||
var input, output chan interface{}
|
||||
var next interface{}
|
||||
input = ch.input
|
||||
|
||||
for input != nil || output != nil {
|
||||
select {
|
||||
case elem, open := <-input:
|
||||
if open {
|
||||
ch.buffer.Add(elem)
|
||||
} else {
|
||||
input = nil
|
||||
}
|
||||
case output <- next:
|
||||
ch.buffer.Remove()
|
||||
case ch.length <- ch.buffer.Length():
|
||||
}
|
||||
|
||||
if ch.buffer.Length() > 0 {
|
||||
output = ch.output
|
||||
next = ch.buffer.Peek()
|
||||
} else {
|
||||
output = nil
|
||||
next = nil
|
||||
}
|
||||
}
|
||||
|
||||
close(ch.output)
|
||||
close(ch.length)
|
||||
}
|
92
vendor/github.com/eapache/channels/native_channel.go
generated
vendored
Normal file
92
vendor/github.com/eapache/channels/native_channel.go
generated
vendored
Normal file
|
@ -0,0 +1,92 @@
|
|||
package channels
|
||||
|
||||
// NativeInChannel implements the InChannel interface by wrapping a native go write-only channel.
|
||||
type NativeInChannel chan<- interface{}
|
||||
|
||||
func (ch NativeInChannel) In() chan<- interface{} {
|
||||
return ch
|
||||
}
|
||||
|
||||
func (ch NativeInChannel) Len() int {
|
||||
return len(ch)
|
||||
}
|
||||
|
||||
func (ch NativeInChannel) Cap() BufferCap {
|
||||
return BufferCap(cap(ch))
|
||||
}
|
||||
|
||||
func (ch NativeInChannel) Close() {
|
||||
close(ch)
|
||||
}
|
||||
|
||||
// NativeOutChannel implements the OutChannel interface by wrapping a native go read-only channel.
|
||||
type NativeOutChannel <-chan interface{}
|
||||
|
||||
func (ch NativeOutChannel) Out() <-chan interface{} {
|
||||
return ch
|
||||
}
|
||||
|
||||
func (ch NativeOutChannel) Len() int {
|
||||
return len(ch)
|
||||
}
|
||||
|
||||
func (ch NativeOutChannel) Cap() BufferCap {
|
||||
return BufferCap(cap(ch))
|
||||
}
|
||||
|
||||
// NativeChannel implements the Channel interface by wrapping a native go channel.
|
||||
type NativeChannel chan interface{}
|
||||
|
||||
// NewNativeChannel makes a new NativeChannel with the given buffer size. Just a convenience wrapper
|
||||
// to avoid having to cast the result of make().
|
||||
func NewNativeChannel(size BufferCap) NativeChannel {
|
||||
return make(chan interface{}, size)
|
||||
}
|
||||
|
||||
func (ch NativeChannel) In() chan<- interface{} {
|
||||
return ch
|
||||
}
|
||||
|
||||
func (ch NativeChannel) Out() <-chan interface{} {
|
||||
return ch
|
||||
}
|
||||
|
||||
func (ch NativeChannel) Len() int {
|
||||
return len(ch)
|
||||
}
|
||||
|
||||
func (ch NativeChannel) Cap() BufferCap {
|
||||
return BufferCap(cap(ch))
|
||||
}
|
||||
|
||||
func (ch NativeChannel) Close() {
|
||||
close(ch)
|
||||
}
|
||||
|
||||
// DeadChannel is a placeholder implementation of the Channel interface with no buffer
|
||||
// that is never ready for reading or writing. Closing a dead channel is a no-op.
|
||||
// Behaves almost like NativeChannel(nil) except that closing a nil NativeChannel will panic.
|
||||
type DeadChannel struct{}
|
||||
|
||||
func NewDeadChannel() DeadChannel {
|
||||
return DeadChannel{}
|
||||
}
|
||||
|
||||
func (ch DeadChannel) In() chan<- interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ch DeadChannel) Out() <-chan interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ch DeadChannel) Len() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (ch DeadChannel) Cap() BufferCap {
|
||||
return BufferCap(0)
|
||||
}
|
||||
|
||||
func (ch DeadChannel) Close() {
|
||||
}
|
113
vendor/github.com/eapache/channels/overflowing_channel.go
generated
vendored
Normal file
113
vendor/github.com/eapache/channels/overflowing_channel.go
generated
vendored
Normal file
|
@ -0,0 +1,113 @@
|
|||
package channels
|
||||
|
||||
import "github.com/eapache/queue"
|
||||
|
||||
// OverflowingChannel implements the Channel interface in a way that never blocks the writer.
|
||||
// Specifically, if a value is written to an OverflowingChannel when its buffer is full
|
||||
// (or, in an unbuffered case, when the recipient is not ready) then that value is simply discarded.
|
||||
// Note that Go's scheduler can cause discarded values when they could be avoided, simply by scheduling
|
||||
// the writer before the reader, so caveat emptor.
|
||||
// For the opposite behaviour (discarding the oldest element, not the newest) see RingChannel.
|
||||
type OverflowingChannel struct {
|
||||
input, output chan interface{}
|
||||
length chan int
|
||||
buffer *queue.Queue
|
||||
size BufferCap
|
||||
}
|
||||
|
||||
func NewOverflowingChannel(size BufferCap) *OverflowingChannel {
|
||||
if size < 0 && size != Infinity {
|
||||
panic("channels: invalid negative size in NewOverflowingChannel")
|
||||
}
|
||||
ch := &OverflowingChannel{
|
||||
input: make(chan interface{}),
|
||||
output: make(chan interface{}),
|
||||
length: make(chan int),
|
||||
size: size,
|
||||
}
|
||||
if size == None {
|
||||
go ch.overflowingDirect()
|
||||
} else {
|
||||
ch.buffer = queue.New()
|
||||
go ch.overflowingBuffer()
|
||||
}
|
||||
return ch
|
||||
}
|
||||
|
||||
func (ch *OverflowingChannel) In() chan<- interface{} {
|
||||
return ch.input
|
||||
}
|
||||
|
||||
func (ch *OverflowingChannel) Out() <-chan interface{} {
|
||||
return ch.output
|
||||
}
|
||||
|
||||
func (ch *OverflowingChannel) Len() int {
|
||||
if ch.size == None {
|
||||
return 0
|
||||
} else {
|
||||
return <-ch.length
|
||||
}
|
||||
}
|
||||
|
||||
func (ch *OverflowingChannel) Cap() BufferCap {
|
||||
return ch.size
|
||||
}
|
||||
|
||||
func (ch *OverflowingChannel) Close() {
|
||||
close(ch.input)
|
||||
}
|
||||
|
||||
// for entirely unbuffered cases
|
||||
func (ch *OverflowingChannel) overflowingDirect() {
|
||||
for elem := range ch.input {
|
||||
// if we can't write it immediately, drop it and move on
|
||||
select {
|
||||
case ch.output <- elem:
|
||||
default:
|
||||
}
|
||||
}
|
||||
close(ch.output)
|
||||
}
|
||||
|
||||
// for all buffered cases
|
||||
func (ch *OverflowingChannel) overflowingBuffer() {
|
||||
var input, output chan interface{}
|
||||
var next interface{}
|
||||
input = ch.input
|
||||
|
||||
for input != nil || output != nil {
|
||||
select {
|
||||
// Prefer to write if possible, which is surprisingly effective in reducing
|
||||
// dropped elements due to overflow. The naive read/write select chooses randomly
|
||||
// when both channels are ready, which produces unnecessary drops 50% of the time.
|
||||
case output <- next:
|
||||
ch.buffer.Remove()
|
||||
default:
|
||||
select {
|
||||
case elem, open := <-input:
|
||||
if open {
|
||||
if ch.size == Infinity || ch.buffer.Length() < int(ch.size) {
|
||||
ch.buffer.Add(elem)
|
||||
}
|
||||
} else {
|
||||
input = nil
|
||||
}
|
||||
case output <- next:
|
||||
ch.buffer.Remove()
|
||||
case ch.length <- ch.buffer.Length():
|
||||
}
|
||||
}
|
||||
|
||||
if ch.buffer.Length() > 0 {
|
||||
output = ch.output
|
||||
next = ch.buffer.Peek()
|
||||
} else {
|
||||
output = nil
|
||||
next = nil
|
||||
}
|
||||
}
|
||||
|
||||
close(ch.output)
|
||||
close(ch.length)
|
||||
}
|
109
vendor/github.com/eapache/channels/resizable_channel.go
generated
vendored
Normal file
109
vendor/github.com/eapache/channels/resizable_channel.go
generated
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
package channels
|
||||
|
||||
import "github.com/eapache/queue"
|
||||
|
||||
// ResizableChannel implements the Channel interface with a resizable buffer between the input and the output.
|
||||
// The channel initially has a buffer size of 1, but can be resized by calling Resize().
|
||||
//
|
||||
// Resizing to a buffer capacity of None is, unfortunately, not supported and will panic
|
||||
// (see https://github.com/eapache/channels/issues/1).
|
||||
// Resizing back and forth between a finite and infinite buffer is fully supported.
|
||||
type ResizableChannel struct {
|
||||
input, output chan interface{}
|
||||
length chan int
|
||||
capacity, resize chan BufferCap
|
||||
size BufferCap
|
||||
buffer *queue.Queue
|
||||
}
|
||||
|
||||
func NewResizableChannel() *ResizableChannel {
|
||||
ch := &ResizableChannel{
|
||||
input: make(chan interface{}),
|
||||
output: make(chan interface{}),
|
||||
length: make(chan int),
|
||||
capacity: make(chan BufferCap),
|
||||
resize: make(chan BufferCap),
|
||||
size: 1,
|
||||
buffer: queue.New(),
|
||||
}
|
||||
go ch.magicBuffer()
|
||||
return ch
|
||||
}
|
||||
|
||||
func (ch *ResizableChannel) In() chan<- interface{} {
|
||||
return ch.input
|
||||
}
|
||||
|
||||
func (ch *ResizableChannel) Out() <-chan interface{} {
|
||||
return ch.output
|
||||
}
|
||||
|
||||
func (ch *ResizableChannel) Len() int {
|
||||
return <-ch.length
|
||||
}
|
||||
|
||||
func (ch *ResizableChannel) Cap() BufferCap {
|
||||
val, open := <-ch.capacity
|
||||
if open {
|
||||
return val
|
||||
} else {
|
||||
return ch.size
|
||||
}
|
||||
}
|
||||
|
||||
func (ch *ResizableChannel) Close() {
|
||||
close(ch.input)
|
||||
}
|
||||
|
||||
func (ch *ResizableChannel) Resize(newSize BufferCap) {
|
||||
if newSize == None {
|
||||
panic("channels: ResizableChannel does not support unbuffered behaviour")
|
||||
}
|
||||
if newSize < 0 && newSize != Infinity {
|
||||
panic("channels: invalid negative size trying to resize channel")
|
||||
}
|
||||
ch.resize <- newSize
|
||||
}
|
||||
|
||||
func (ch *ResizableChannel) magicBuffer() {
|
||||
var input, output, nextInput chan interface{}
|
||||
var next interface{}
|
||||
nextInput = ch.input
|
||||
input = nextInput
|
||||
|
||||
for input != nil || output != nil {
|
||||
select {
|
||||
case elem, open := <-input:
|
||||
if open {
|
||||
ch.buffer.Add(elem)
|
||||
} else {
|
||||
input = nil
|
||||
nextInput = nil
|
||||
}
|
||||
case output <- next:
|
||||
ch.buffer.Remove()
|
||||
case ch.size = <-ch.resize:
|
||||
case ch.length <- ch.buffer.Length():
|
||||
case ch.capacity <- ch.size:
|
||||
}
|
||||
|
||||
if ch.buffer.Length() == 0 {
|
||||
output = nil
|
||||
next = nil
|
||||
} else {
|
||||
output = ch.output
|
||||
next = ch.buffer.Peek()
|
||||
}
|
||||
|
||||
if ch.size != Infinity && ch.buffer.Length() >= int(ch.size) {
|
||||
input = nil
|
||||
} else {
|
||||
input = nextInput
|
||||
}
|
||||
}
|
||||
|
||||
close(ch.output)
|
||||
close(ch.resize)
|
||||
close(ch.length)
|
||||
close(ch.capacity)
|
||||
}
|
114
vendor/github.com/eapache/channels/ring_channel.go
generated
vendored
Normal file
114
vendor/github.com/eapache/channels/ring_channel.go
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
|||
package channels
|
||||
|
||||
import "github.com/eapache/queue"
|
||||
|
||||
// RingChannel implements the Channel interface in a way that never blocks the writer.
|
||||
// Specifically, if a value is written to a RingChannel when its buffer is full then the oldest
|
||||
// value in the buffer is discarded to make room (just like a standard ring-buffer).
|
||||
// Note that Go's scheduler can cause discarded values when they could be avoided, simply by scheduling
|
||||
// the writer before the reader, so caveat emptor.
|
||||
// For the opposite behaviour (discarding the newest element, not the oldest) see OverflowingChannel.
|
||||
type RingChannel struct {
|
||||
input, output chan interface{}
|
||||
length chan int
|
||||
buffer *queue.Queue
|
||||
size BufferCap
|
||||
}
|
||||
|
||||
func NewRingChannel(size BufferCap) *RingChannel {
|
||||
if size < 0 && size != Infinity {
|
||||
panic("channels: invalid negative size in NewRingChannel")
|
||||
}
|
||||
ch := &RingChannel{
|
||||
input: make(chan interface{}),
|
||||
output: make(chan interface{}),
|
||||
buffer: queue.New(),
|
||||
size: size,
|
||||
}
|
||||
if size == None {
|
||||
go ch.overflowingDirect()
|
||||
} else {
|
||||
ch.length = make(chan int)
|
||||
go ch.ringBuffer()
|
||||
}
|
||||
return ch
|
||||
}
|
||||
|
||||
func (ch *RingChannel) In() chan<- interface{} {
|
||||
return ch.input
|
||||
}
|
||||
|
||||
func (ch *RingChannel) Out() <-chan interface{} {
|
||||
return ch.output
|
||||
}
|
||||
|
||||
func (ch *RingChannel) Len() int {
|
||||
if ch.size == None {
|
||||
return 0
|
||||
} else {
|
||||
return <-ch.length
|
||||
}
|
||||
}
|
||||
|
||||
func (ch *RingChannel) Cap() BufferCap {
|
||||
return ch.size
|
||||
}
|
||||
|
||||
func (ch *RingChannel) Close() {
|
||||
close(ch.input)
|
||||
}
|
||||
|
||||
// for entirely unbuffered cases
|
||||
func (ch *RingChannel) overflowingDirect() {
|
||||
for elem := range ch.input {
|
||||
// if we can't write it immediately, drop it and move on
|
||||
select {
|
||||
case ch.output <- elem:
|
||||
default:
|
||||
}
|
||||
}
|
||||
close(ch.output)
|
||||
}
|
||||
|
||||
// for all buffered cases
|
||||
func (ch *RingChannel) ringBuffer() {
|
||||
var input, output chan interface{}
|
||||
var next interface{}
|
||||
input = ch.input
|
||||
|
||||
for input != nil || output != nil {
|
||||
select {
|
||||
// Prefer to write if possible, which is surprisingly effective in reducing
|
||||
// dropped elements due to overflow. The naive read/write select chooses randomly
|
||||
// when both channels are ready, which produces unnecessary drops 50% of the time.
|
||||
case output <- next:
|
||||
ch.buffer.Remove()
|
||||
default:
|
||||
select {
|
||||
case elem, open := <-input:
|
||||
if open {
|
||||
ch.buffer.Add(elem)
|
||||
if ch.size != Infinity && ch.buffer.Length() > int(ch.size) {
|
||||
ch.buffer.Remove()
|
||||
}
|
||||
} else {
|
||||
input = nil
|
||||
}
|
||||
case output <- next:
|
||||
ch.buffer.Remove()
|
||||
case ch.length <- ch.buffer.Length():
|
||||
}
|
||||
}
|
||||
|
||||
if ch.buffer.Length() > 0 {
|
||||
output = ch.output
|
||||
next = ch.buffer.Peek()
|
||||
} else {
|
||||
output = nil
|
||||
next = nil
|
||||
}
|
||||
}
|
||||
|
||||
close(ch.output)
|
||||
close(ch.length)
|
||||
}
|
167
vendor/github.com/eapache/channels/shared_buffer.go
generated
vendored
Normal file
167
vendor/github.com/eapache/channels/shared_buffer.go
generated
vendored
Normal file
|
@ -0,0 +1,167 @@
|
|||
package channels
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/eapache/queue"
|
||||
)
|
||||
|
||||
//sharedBufferChannel implements SimpleChannel and is created by the public
|
||||
//SharedBuffer type below
|
||||
type sharedBufferChannel struct {
|
||||
in chan interface{}
|
||||
out chan interface{}
|
||||
buf *queue.Queue
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (sch *sharedBufferChannel) In() chan<- interface{} {
|
||||
return sch.in
|
||||
}
|
||||
|
||||
func (sch *sharedBufferChannel) Out() <-chan interface{} {
|
||||
return sch.out
|
||||
}
|
||||
|
||||
func (sch *sharedBufferChannel) Close() {
|
||||
close(sch.in)
|
||||
}
|
||||
|
||||
//SharedBuffer implements the Buffer interface, and permits multiple SimpleChannel instances to "share" a single buffer.
|
||||
//Each channel spawned by NewChannel has its own internal queue (so values flowing through do not get mixed up with
|
||||
//other channels) but the total number of elements buffered by all spawned channels is limited to a single capacity. This
|
||||
//means *all* such channels block and unblock for writing together. The primary use case is for implementing pipeline-style
|
||||
//parallelism with goroutines, limiting the total number of elements in the pipeline without limiting the number of elements
|
||||
//at any particular step.
|
||||
type SharedBuffer struct {
|
||||
cases []reflect.SelectCase // 2n+1 of these; [0] is for control, [1,3,5...] for recv, [2,4,6...] for send
|
||||
chans []*sharedBufferChannel // n of these
|
||||
count int
|
||||
size BufferCap
|
||||
in chan *sharedBufferChannel
|
||||
}
|
||||
|
||||
func NewSharedBuffer(size BufferCap) *SharedBuffer {
|
||||
if size < 0 && size != Infinity {
|
||||
panic("channels: invalid negative size in NewSharedBuffer")
|
||||
} else if size == None {
|
||||
panic("channels: SharedBuffer does not support unbuffered behaviour")
|
||||
}
|
||||
|
||||
buf := &SharedBuffer{
|
||||
size: size,
|
||||
in: make(chan *sharedBufferChannel),
|
||||
}
|
||||
|
||||
buf.cases = append(buf.cases, reflect.SelectCase{
|
||||
Dir: reflect.SelectRecv,
|
||||
Chan: reflect.ValueOf(buf.in),
|
||||
})
|
||||
|
||||
go buf.mainLoop()
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
//NewChannel spawns and returns a new channel sharing the underlying buffer.
|
||||
func (buf *SharedBuffer) NewChannel() SimpleChannel {
|
||||
ch := &sharedBufferChannel{
|
||||
in: make(chan interface{}),
|
||||
out: make(chan interface{}),
|
||||
buf: queue.New(),
|
||||
}
|
||||
buf.in <- ch
|
||||
return ch
|
||||
}
|
||||
|
||||
//Close shuts down the SharedBuffer. It is an error to call Close while channels are still using
|
||||
//the buffer (I'm not really sure what would happen if you do so).
|
||||
func (buf *SharedBuffer) Close() {
|
||||
// TODO: what if there are still active channels using this buffer?
|
||||
close(buf.in)
|
||||
}
|
||||
|
||||
func (buf *SharedBuffer) mainLoop() {
|
||||
for {
|
||||
i, val, ok := reflect.Select(buf.cases)
|
||||
|
||||
if i == 0 {
|
||||
if !ok {
|
||||
//Close was called on the SharedBuffer itself
|
||||
return
|
||||
}
|
||||
|
||||
//NewChannel was called on the SharedBuffer
|
||||
ch := val.Interface().(*sharedBufferChannel)
|
||||
buf.chans = append(buf.chans, ch)
|
||||
buf.cases = append(buf.cases,
|
||||
reflect.SelectCase{Dir: reflect.SelectRecv},
|
||||
reflect.SelectCase{Dir: reflect.SelectSend},
|
||||
)
|
||||
if buf.size == Infinity || buf.count < int(buf.size) {
|
||||
buf.cases[len(buf.cases)-2].Chan = reflect.ValueOf(ch.in)
|
||||
}
|
||||
} else if i%2 == 0 {
|
||||
//Send
|
||||
if buf.count == int(buf.size) {
|
||||
//room in the buffer again, re-enable all recv cases
|
||||
for j := range buf.chans {
|
||||
if !buf.chans[j].closed {
|
||||
buf.cases[(j*2)+1].Chan = reflect.ValueOf(buf.chans[j].in)
|
||||
}
|
||||
}
|
||||
}
|
||||
buf.count--
|
||||
ch := buf.chans[(i-1)/2]
|
||||
if ch.buf.Length() > 0 {
|
||||
buf.cases[i].Send = reflect.ValueOf(ch.buf.Peek())
|
||||
ch.buf.Remove()
|
||||
} else {
|
||||
//nothing left for this channel to send, disable sending
|
||||
buf.cases[i].Chan = reflect.Value{}
|
||||
buf.cases[i].Send = reflect.Value{}
|
||||
if ch.closed {
|
||||
// and it was closed, so close the output channel
|
||||
//TODO: shrink slice
|
||||
close(ch.out)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ch := buf.chans[i/2]
|
||||
if ok {
|
||||
//Receive
|
||||
buf.count++
|
||||
if ch.buf.Length() == 0 && !buf.cases[i+1].Chan.IsValid() {
|
||||
//this channel now has something to send
|
||||
buf.cases[i+1].Chan = reflect.ValueOf(ch.out)
|
||||
buf.cases[i+1].Send = val
|
||||
} else {
|
||||
ch.buf.Add(val.Interface())
|
||||
}
|
||||
if buf.count == int(buf.size) {
|
||||
//buffer full, disable recv cases
|
||||
for j := range buf.chans {
|
||||
buf.cases[(j*2)+1].Chan = reflect.Value{}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Close
|
||||
buf.cases[i].Chan = reflect.Value{}
|
||||
ch.closed = true
|
||||
if ch.buf.Length() == 0 && !buf.cases[i+1].Chan.IsValid() {
|
||||
//nothing pending, close the out channel right away
|
||||
//TODO: shrink slice
|
||||
close(ch.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (buf *SharedBuffer) Len() int {
|
||||
return buf.count
|
||||
}
|
||||
|
||||
func (buf *SharedBuffer) Cap() BufferCap {
|
||||
return buf.size
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue