package stackless

import (
	
	
	

	
)

// Writer is an interface stackless writer must conform to.
//
// The interface contains common subset for Writers from compress/* packages.
type Writer interface {
	Write(p []byte) (int, error)
	Flush() error
	Close() error
	Reset(w io.Writer)
}

// NewWriterFunc must return new writer that will be wrapped into
// stackless writer.
type NewWriterFunc func(w io.Writer) Writer

// NewWriter creates a stackless writer around a writer returned
// from newWriter.
//
// The returned writer writes data to dstW.
//
// Writers that use a lot of stack space may be wrapped into stackless writer,
// thus saving stack space for high number of concurrently running goroutines.
func ( io.Writer,  NewWriterFunc) Writer {
	 := &writer{
		dstW: ,
	}
	.zw = (&.xw)
	return 
}

type writer struct {
	dstW io.Writer
	zw   Writer
	xw   xWriter

	err error
	n   int

	p  []byte
	op op
}

type op int

const (
	opWrite op = iota
	opFlush
	opClose
	opReset
)

func ( *writer) ( []byte) (int, error) {
	.p = 
	 := .do(opWrite)
	.p = nil
	return .n, 
}

func ( *writer) () error {
	return .do(opFlush)
}

func ( *writer) () error {
	return .do(opClose)
}

func ( *writer) ( io.Writer) {
	.xw.Reset()
	.do(opReset) //nolint:errcheck
	.dstW = 
}

func ( *writer) ( op) error {
	.op = 
	if !stacklessWriterFunc() {
		return errHighLoad
	}
	 := .err
	if  != nil {
		return 
	}
	if .xw.bb != nil && len(.xw.bb.B) > 0 {
		_,  = .dstW.Write(.xw.bb.B)
	}
	.xw.Reset()

	return 
}

var errHighLoad = errors.New("cannot compress data due to high load")

var stacklessWriterFunc = NewFunc(writerFunc)

func writerFunc( interface{}) {
	 := .(*writer)
	switch .op {
	case opWrite:
		.n, .err = .zw.Write(.p)
	case opFlush:
		.err = .zw.Flush()
	case opClose:
		.err = .zw.Close()
	case opReset:
		.zw.Reset(&.xw)
		.err = nil
	default:
		panic(fmt.Sprintf("BUG: unexpected op: %d", .op))
	}
}

type xWriter struct {
	bb *bytebufferpool.ByteBuffer
}

func ( *xWriter) ( []byte) (int, error) {
	if .bb == nil {
		.bb = bufferPool.Get()
	}
	return .bb.Write()
}

func ( *xWriter) () {
	if .bb != nil {
		bufferPool.Put(.bb)
		.bb = nil
	}
}

var bufferPool bytebufferpool.Pool