// Copyright 2014 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 http2

import (
	
	
	
)

// pipe is a goroutine-safe io.Reader/io.Writer pair. It's like
// io.Pipe except there are no PipeReader/PipeWriter halves, and the
// underlying buffer is an interface. (io.Pipe is always unbuffered)
type pipe struct {
	mu       sync.Mutex
	c        sync.Cond     // c.L lazily initialized to &p.mu
	b        pipeBuffer    // nil when done reading
	unread   int           // bytes unread when done
	err      error         // read error once empty. non-nil means closed.
	breakErr error         // immediate read error (caller doesn't see rest of b)
	donec    chan struct{} // closed on error
	readFn   func()        // optional code to run in Read before error
}

type pipeBuffer interface {
	Len() int
	io.Writer
	io.Reader
}

// setBuffer initializes the pipe buffer.
// It has no effect if the pipe is already closed.
func ( *pipe) ( pipeBuffer) {
	.mu.Lock()
	defer .mu.Unlock()
	if .err != nil || .breakErr != nil {
		return
	}
	.b = 
}

func ( *pipe) () int {
	.mu.Lock()
	defer .mu.Unlock()
	if .b == nil {
		return .unread
	}
	return .b.Len()
}

// Read waits until data is available and copies bytes
// from the buffer into p.
func ( *pipe) ( []byte) ( int,  error) {
	.mu.Lock()
	defer .mu.Unlock()
	if .c.L == nil {
		.c.L = &.mu
	}
	for {
		if .breakErr != nil {
			return 0, .breakErr
		}
		if .b != nil && .b.Len() > 0 {
			return .b.Read()
		}
		if .err != nil {
			if .readFn != nil {
				.readFn()     // e.g. copy trailers
				.readFn = nil // not sticky like p.err
			}
			.b = nil
			return 0, .err
		}
		.c.Wait()
	}
}

var errClosedPipeWrite = errors.New("write on closed buffer")

// Write copies bytes from p into the buffer and wakes a reader.
// It is an error to write more data than the buffer can hold.
func ( *pipe) ( []byte) ( int,  error) {
	.mu.Lock()
	defer .mu.Unlock()
	if .c.L == nil {
		.c.L = &.mu
	}
	defer .c.Signal()
	if .err != nil {
		return 0, errClosedPipeWrite
	}
	if .breakErr != nil {
		.unread += len()
		return len(), nil // discard when there is no reader
	}
	return .b.Write()
}

// CloseWithError causes the next Read (waking up a current blocked
// Read if needed) to return the provided err after all data has been
// read.
//
// The error must be non-nil.
func ( *pipe) ( error) { .closeWithError(&.err, , nil) }

// BreakWithError causes the next Read (waking up a current blocked
// Read if needed) to return the provided err immediately, without
// waiting for unread data.
func ( *pipe) ( error) { .closeWithError(&.breakErr, , nil) }

// closeWithErrorAndCode is like CloseWithError but also sets some code to run
// in the caller's goroutine before returning the error.
func ( *pipe) ( error,  func()) { .closeWithError(&.err, , ) }

func ( *pipe) ( *error,  error,  func()) {
	if  == nil {
		panic("err must be non-nil")
	}
	.mu.Lock()
	defer .mu.Unlock()
	if .c.L == nil {
		.c.L = &.mu
	}
	defer .c.Signal()
	if * != nil {
		// Already been done.
		return
	}
	.readFn = 
	if  == &.breakErr {
		if .b != nil {
			.unread += .b.Len()
		}
		.b = nil
	}
	* = 
	.closeDoneLocked()
}

// requires p.mu be held.
func ( *pipe) () {
	if .donec == nil {
		return
	}
	// Close if unclosed. This isn't racy since we always
	// hold p.mu while closing.
	select {
	case <-.donec:
	default:
		close(.donec)
	}
}

// Err returns the error (if any) first set by BreakWithError or CloseWithError.
func ( *pipe) () error {
	.mu.Lock()
	defer .mu.Unlock()
	if .breakErr != nil {
		return .breakErr
	}
	return .err
}

// Done returns a channel which is closed if and when this pipe is closed
// with CloseWithError.
func ( *pipe) () <-chan struct{} {
	.mu.Lock()
	defer .mu.Unlock()
	if .donec == nil {
		.donec = make(chan struct{})
		if .err != nil || .breakErr != nil {
			// Already hit an error.
			.closeDoneLocked()
		}
	}
	return .donec
}