package redis

import (
	
	

	
)

type pipelineExecer func(context.Context, []Cmder) error
Pipeliner is an mechanism to realise Redis Pipeline technique. Pipelining is a technique to extremely speed up processing by packing operations to batches, send them at once to Redis and read a replies in a singe step. See https://redis.io/topics/pipelining Pay attention, that Pipeline is not a transaction, so you can get unexpected results in case of big pipelines and small read/write timeouts. Redis client has retransmission logic in case of timeouts, pipeline can be retransmitted and commands can be executed more then once. To avoid this: it is good idea to use reasonable bigger read/write timeouts depends of your batch size and/or use TxPipeline.
type Pipeliner interface {
	StatefulCmdable
	Do(ctx context.Context, args ...interface{}) *Cmd
	Process(ctx context.Context, cmd Cmder) error
	Close() error
	Discard() error
	Exec(ctx context.Context) ([]Cmder, error)
}

var _ Pipeliner = (*Pipeline)(nil)
Pipeline implements pipelining as described in http://redis.io/topics/pipelining. It's safe for concurrent use by multiple goroutines.
type Pipeline struct {
	cmdable
	statefulCmdable

	ctx  context.Context
	exec pipelineExecer

	mu     sync.Mutex
	cmds   []Cmder
	closed bool
}

func ( *Pipeline) () {
	.cmdable = .Process
	.statefulCmdable = .Process
}

func ( *Pipeline) ( context.Context,  ...interface{}) *Cmd {
	 := NewCmd(, ...)
	_ = .Process(, )
	return 
}
Process queues the cmd for later execution.
func ( *Pipeline) ( context.Context,  Cmder) error {
	.mu.Lock()
	.cmds = append(.cmds, )
	.mu.Unlock()
	return nil
}
Close closes the pipeline, releasing any open resources.
func ( *Pipeline) () error {
	.mu.Lock()
	_ = .discard()
	.closed = true
	.mu.Unlock()
	return nil
}
Discard resets the pipeline and discards queued commands.
func ( *Pipeline) () error {
	.mu.Lock()
	 := .discard()
	.mu.Unlock()
	return 
}

func ( *Pipeline) () error {
	if .closed {
		return pool.ErrClosed
	}
	.cmds = .cmds[:0]
	return nil
}
Exec executes all previously queued commands using one client-server roundtrip. Exec always returns list of commands and error of the first failed command if any.
func ( *Pipeline) ( context.Context) ([]Cmder, error) {
	.mu.Lock()
	defer .mu.Unlock()

	if .closed {
		return nil, pool.ErrClosed
	}

	if len(.cmds) == 0 {
		return nil, nil
	}

	 := .cmds
	.cmds = nil

	return , .exec(, )
}

func ( *Pipeline) ( context.Context,  func(Pipeliner) error) ([]Cmder, error) {
	if  := ();  != nil {
		return nil, 
	}
	,  := .Exec()
	_ = .Close()
	return , 
}

func ( *Pipeline) () Pipeliner {
	return 
}

func ( *Pipeline) ( context.Context,  func(Pipeliner) error) ([]Cmder, error) {
	return .Pipelined(, )
}

func ( *Pipeline) () Pipeliner {
	return