func limit(r Rule, acquire func(_ context.Context, block bool) bool, over Overflow, otherwise Rule) Rule {
	if r == nil {
		return nil
	}
	if acquire == nil {
		panic("acquire func is not allowed to be nil")
	}
	blocking := false
	switch over {
	case OverflowOtherwise:
	case OverflowWait:
		blocking = true
	default:
		panic(fmt.Sprintf("unexpected Overflow type: %#v", over))
	}
	return func(ctx context.Context, e *executor.Call, z mesos.Response, err error, ch Chain) (context.Context, *executor.Call, mesos.Response, error) {
		if !acquire(ctx, blocking) {
			return otherwise.Eval(ctx, e, z, err, ch)
		}
		return r(ctx, e, z, err, ch)
	}
}
limit is a generic Rule decorator that limits invocations of said Rule.
The "acquire" func SHOULD NOT block if the supplied Context is Done.
MUST only invoke "acquire" once per event.
TODO(jdef): leaving this as internal for now because the interface still feels too messy.
package callrules
import (
	"context"
	"fmt"
	"sync"
	"github.com/mesos/mesos-go/api/v1/lib"
	"github.com/mesos/mesos-go/api/v1/lib/executor"
)
type (
	evaler interface {
		Eval(context.Context, *executor.Call, mesos.Response, error, Chain) (context.Context, *executor.Call, mesos.Response, error)
	}
	Rule func(context.Context, *executor.Call, mesos.Response, error, Chain) (context.Context, *executor.Call, mesos.Response, error)
	Chain func(context.Context, *executor.Call, mesos.Response, error) (context.Context, *executor.Call, mesos.Response, error)
	Rules []Rule
	ErrorList []error
)
var (
	_ = evaler(Rule(nil))
	_ = evaler(Rules{})
)
func ChainIdentity(ctx context.Context, e *executor.Call, z mesos.Response, err error) (context.Context, *executor.Call, mesos.Response, error) {
	return ctx, e, z, err
}
func (r Rule) Eval(ctx context.Context, e *executor.Call, z mesos.Response, err error, ch Chain) (context.Context, *executor.Call, mesos.Response, error) {
	if r != nil {
		return r(ctx, e, z, err, ch)
	}
	return ch(ctx, e, z, err)
}
func (rs Rules) Eval(ctx context.Context, e *executor.Call, z mesos.Response, err error, ch Chain) (context.Context, *executor.Call, mesos.Response, error) {
	return ch(rs.Chain()(ctx, e, z, err))
}
func (rs Rules) Chain() Chain {
	if len(rs) == 0 {
		return ChainIdentity
	}
	return func(ctx context.Context, e *executor.Call, z mesos.Response, err error) (context.Context, *executor.Call, mesos.Response, error) {
		return rs[0].Eval(ctx, e, z, err, rs[1:].Chain())
	}
}
func New(rs ...Rule) Rule { return Rules(rs).Eval }
const msgNoErrors = "no errors"
func (es ErrorList) Error() string {
	switch len(es) {
	case 0:
		return msgNoErrors
	case 1:
		return es[0].Error()
	default:
		return fmt.Sprintf("%s (and %d more errors)", es[0], len(es)-1)
	}
}
func Error2(a, b error) error {
	if a == nil {
		if b == nil {
			return nil
		}
		if list, ok := b.(ErrorList); ok {
			return flatten(list).Err()
		}
		return b
	}
	if b == nil {
		if list, ok := a.(ErrorList); ok {
			return flatten(list).Err()
		}
		return a
	}
	return Error(a, b)
}
func (es ErrorList) Err() error {
	switch len(es) {
	case 0:
		return nil
	case 1:
		return es[0]
	default:
		return es
	}
}
func IsErrorList(err error) bool {
	if err != nil {
		_, ok := err.(ErrorList)
		return ok
	}
	return false
}
func Error(es ...error) error {
	return flatten(es).Err()
}
func flatten(errors []error) ErrorList {
	if errors == nil || len(errors) == 0 {
		return nil
	}
	result := make([]error, 0, len(errors))
	for _, err := range errors {
		if err != nil {
			if multi, ok := err.(ErrorList); ok {
				result = append(result, flatten(multi)...)
			} else {
				result = append(result, err)
			}
		}
	}
	return ErrorList(result)
}
func (r Rule) If(b bool) Rule {
	if b {
		return r
	}
	return nil
}
func (r Rule) Unless(b bool) Rule {
	if !b {
		return r
	}
	return nil
}
func (r Rule) Once() Rule {
	if r == nil {
		return nil
	}
	var once sync.Once
	return func(ctx context.Context, e *executor.Call, z mesos.Response, err error, ch Chain) (context.Context, *executor.Call, mesos.Response, error) {
		ruleInvoked := false
		once.Do(func() {
			ctx, e, z, err = r(ctx, e, z, err, ch)
			ruleInvoked = true
		})
		if !ruleInvoked {
			ctx, e, z, err = ch(ctx, e, z, err)
		}
		return ctx, e, z, err
	}
}
func (r Rule) UnlessDone() Rule {
	if r == nil {
		return nil
	}
	return func(ctx context.Context, e *executor.Call, z mesos.Response, err error, ch Chain) (context.Context, *executor.Call, mesos.Response, error) {
		select {
		case <-ctx.Done():
			return ctx, e, z, Error2(err, ctx.Err())
		default:
			return r(ctx, e, z, err, ch)
		}
	}
}
type Overflow int
const (
	OverflowWait Overflow = iota
	OverflowOtherwise
)
func (r Rule) RateLimit(p <-chan struct{}, over Overflow, otherwise Rule) Rule {
	return limit(r, acquireChan(p), over, otherwise)
}
func acquireChan(tokenCh <-chan struct{}) func(context.Context, bool) bool {
	if tokenCh == nil {
		return func(ctx context.Context, block bool) bool {
			if block {
				select {
				case <-ctx.Done():
				default:
					panic("deadlock detected: block should never be true when the token chan is nil")
				}
			}
			return false
		}
	}
	return func(ctx context.Context, block bool) bool {
		if block {
			select {
			case <-tokenCh:
				select {
				case <-ctx.Done():
				default:
					return true
				}
			case <-ctx.Done():
			}
			return false
		}
		select {
		case <-tokenCh:
			return true
		default:
			return false
		}
	}
}