func (s *streamMap) creatableLocalStreamUni() bool {
	return s.openedStreams.localUni < s.maxStreams.peerUni
}
creatablePeerStreamBidi returns true if it can create a new local uni stream.
package transport
import (
	"fmt"
	"io"
)
const (
	maxStreams = 1 << 60
	minStreamBufferWritable = 8 << 10
	maxStreamBuffer         = 128 << 10
)
type deliveryState uint8
const (
	deliveryNone deliveryState = iota
	deliveryReady
	deliverySending
	deliveryConfirmed
)
type Stream struct {
	recv recvStream
	send sendStream
	flow flowControl
	connFlow *flowControl
	updateMaxData bool
	local bool
	bidi  bool
}
func (s *Stream) init(local, bidi bool) {
	s.local = local
	s.bidi = bidi
	if !bidi {
		if local {
			s.recv.setClosed()  
		} else {
			s.send.setClosed()  
		}
	}
}
func (s *Stream) pushRecv(data []byte, offset uint64, fin bool) error {
	if offset+uint64(len(data)) > s.flow.recvMax {
		return newError(FlowControlError, sprint("stream: data exceeded limit ", s.flow.recvMax))
	}
	err := s.recv.push(data, offset, fin)
	if err == nil {
		s.flow.setRecv(s.recv.length)
	}
	return err
}
func (s *Stream) Read(b []byte) (int, error) {
	if s.recv.closed {
		return 0, io.EOF
	}
	n, err := s.recv.Read(b)
	if n > 0 {
		s.consumeRecv(uint64(n))
	}
	return n, err
}
func (s *Stream) Write(b []byte) (int, error) {
	if s.send.closed {
		return 0, io.EOF
	}
	if s.send.stopReceived {
		s.send.setClosed()  
		return 0, newAppError(s.send.resetError, "stop_sending")
	}
	if s.send.buf.size() > maxStreamBuffer {
		return 0, nil
	}
	n := int(s.flow.availSend())
	if n <= 0 {
		return 0, nil
	}
	if n < len(b) {
		b = b[:n]
	}
	n, err := s.send.Write(b)
	if n > 0 {
		s.flow.setSend(s.send.length)
		if s.isSendBlocked() {
			s.flow.setSendBlocked(true)
		}
	}
	return n, err
}
func (s *Stream) WriteString(b string) (int, error) {
	return s.Write([]byte(b))
}
func (s *Stream) WriteTo(w io.Writer) (int64, error) {
	if s.recv.closed {
		return 0, io.EOF
	}
	n, err := s.recv.WriteTo(w)
	if n > 0 {
		s.consumeRecv(uint64(n))
	}
	return n, err
}
func (s *Stream) isReadable() bool {
	if s.recv.closed {
		return false
	}
	if s.recv.resetReceived {
		return true
	}
	return (s.recv.ready() || s.recv.fin) && s.recv.stopSending == deliveryNone
}
func (s *Stream) updateStopSending() (uint64, bool) {
	if s.recv.stopSending == deliveryReady {
		return s.recv.stopError, true
	}
	return 0, false
}
func (s *Stream) setStopSending(state deliveryState) {
	s.recv.stopSending = state
	if state == deliveryConfirmed && !s.recv.resetReceived {
		s.recv.setClosed()
	}
}
func (s *Stream) resetRecv(finalSize, errorCode uint64) error {
	return s.recv.reset(finalSize, errorCode)
}
func (s *Stream) isWritable() bool {
	if s.send.closed {
		return false
	}
	if s.send.stopReceived {
		return true
	}
	return s.flow.availSend() > 0 && s.send.buf.size() < minStreamBufferWritable &&
		!s.send.fin && s.send.resetStream == deliveryNone
}
func (s *Stream) isFlushable() bool {
	if s.send.closed || s.send.stopReceived {
		return false
	}
	return s.send.ready(s.flow.sendMax) || (s.send.fin && !s.send.finSent)
}
func (s *Stream) isSendBlocked() bool {
	if s.send.closed || s.send.stopReceived || s.send.fin || s.send.resetStream != deliveryNone {
		return false
	}
	return s.flow.availSend() == 0
}
func (s *Stream) popSend(max int) (data []byte, offset uint64, fin bool) {
	if s.isFlushable() {
		return s.send.pop(max)
	}
	return nil, 0, false
}
func (s *Stream) pushSend(data []byte, offset uint64, fin bool) error {
	if s.send.stopReceived || s.send.resetStream != deliveryNone {
		return nil
	}
	return s.send.push(data, offset, fin)
}
func (s *Stream) ackSend(offset, length uint64) bool {
	return s.send.ack(offset, length)
}
func (s *Stream) consumeRecv(n uint64) {
	s.flow.addRecvMaxNext(n)
	if s.connFlow != nil {
		s.connFlow.addRecvMaxNext(n)
	}
	if !s.recv.fin && s.flow.shouldUpdateRecvMax() {
		s.updateMaxData = true
	}
}
func (s *Stream) setUpdateMaxData(update bool) {
	s.updateMaxData = update
}
func (s *Stream) updateResetStream() (uint64, bool) {
	if s.send.resetStream == deliveryReady && (s.send.stopReceived || s.send.buf.isEmpty()) {
		return s.send.resetError, true
	}
	return 0, false
}
func (s *Stream) setResetStream(state deliveryState) {
	s.send.resetStream = state
	if state == deliveryConfirmed && !s.send.stopReceived {
		s.send.setClosed()
	}
}
func (s *Stream) stopSend(errorCode uint64) {
	s.send.stop(errorCode)
	if s.flow.sendBlocked {
		s.flow.setSendBlocked(false)
	}
}
func (s *Stream) isClosed() bool {
	return s.recv.closed && s.send.closed
}
func (s *Stream) CloseWrite(errorCode uint64) error {
	if !s.bidi && !s.local {
		return newError(StreamStateError, "cannot close writing of receive-only stream")
	}
	s.send.terminate(errorCode)
	return nil
}
func (s *Stream) CloseRead(errorCode uint64) error {
	if !s.bidi && s.local {
		return newError(StreamStateError, "cannot close reading of send-only stream")
	}
	s.recv.terminate(errorCode)
	return nil
}
func (s *Stream) Close() error {
	if s.bidi || s.local {
		s.send.fin = true
		if s.flow.sendBlocked {
			s.flow.setSendBlocked(false)
		}
	}
	return nil
}
func (s *Stream) String() string {
	return fmt.Sprintf("recv(%s) send(%s)", &s.recv, &s.send)
}
type recvStream struct {
	buf rangeBufferList  
	offset uint64  
	length uint64  
	stopError     uint64         
	stopSending   deliveryState  
	resetReceived bool           
	fin bool
	closed bool
}
func (s *recvStream) push(data []byte, offset uint64, fin bool) error {
	end := offset + uint64(len(data))
	if s.fin {
		if end > s.length {
			return errFinalSize
		}
	}
	if fin {
		if end < s.length {
			return errFinalSize
		}
		s.fin = true
	}
	if end <= s.offset {
		return nil
	}
	if offset < s.offset {
		data = data[s.offset-offset:]
		offset = s.offset
	}
	s.buf.write(data, offset)
	if end > s.length {
		s.length = end
	}
	return nil
}
func (s *recvStream) Read(b []byte) (n int, err error) {
	n = s.buf.read(b, s.offset)
	s.offset += uint64(n)
	if s.resetReceived {
		s.setClosed()  
		err = newAppError(s.stopError, "reset_stream")
	} else if s.fin && s.offset >= s.length {
		s.setClosed()  
		err = io.EOF
	}
	return n, err
}
func (s *recvStream) WriteTo(w io.Writer) (int64, error) {
	n, err := s.buf.consume(s.offset, w.Write)
	s.offset += uint64(n)
	if err == nil {
		if s.resetReceived {
			s.setClosed()  
			err = newAppError(s.stopError, "reset_stream")
		} else if s.fin && s.offset >= s.length {
			s.setClosed()  
			err = io.EOF
		}
	}
	return int64(n), err
}
func (s *recvStream) ready() bool {
	if s.offset < s.length {
		r := s.buf.first()
		return r != nil && r.offset == s.offset
	}
	return false
}
func (s *recvStream) reset(finalSize, errorCode uint64) error {
	if !s.resetReceived {
		if (s.fin && finalSize != s.length) || finalSize < s.length {
			return errFinalSize
		}
		s.resetReceived = true
		s.fin = true
		s.length = finalSize
		if s.stopSending == deliveryNone {
			s.stopError = errorCode
			s.stopSending = deliveryConfirmed
		}
	}
	return nil
}
func (s *recvStream) terminate(errorCode uint64) {
	if s.stopSending == deliveryNone && !s.resetReceived {
		s.stopError = errorCode
		s.stopSending = deliveryReady
	}
}
func (s *recvStream) setClosed() {
	s.closed = true
}
func (s *recvStream) String() string {
	return fmt.Sprintf("offset=%v length=%v fin=%v size=%v %v", s.offset, s.length, s.fin, s.buf.size(), &s.buf)
}
type sendStream struct {
	buf   rangeBufferList  
	acked rangeSet         
	offset uint64  
	length uint64  
	resetError   uint64         
	resetStream  deliveryState  
	stopReceived bool           
	fin     bool
	finSent bool  
	closed bool
}
func (s *sendStream) push(data []byte, offset uint64, fin bool) error {
	end := offset + uint64(len(data))
	if s.fin {
		if end > s.length {
			return errFinalSize
		}
	}
	if fin {
		if end < s.length {
			return errFinalSize
		}
		s.fin = true
		s.finSent = false  
	}
	s.buf.write(data, offset)
	if end > s.length {
		s.length = end
	}
	return nil
}
func (s *sendStream) pop(max int) (data []byte, offset uint64, fin bool) {
	data, offset = s.buf.pop(max)
	if len(data) == 0 {
		offset = s.offset
	}
	end := offset + uint64(len(data))
	fin = s.fin && end >= s.length
	if fin {
		s.finSent = true
	}
	if end > s.offset {
		s.offset = end
	}
	return
}
func (s *sendStream) ready(maxOffset uint64) bool {
	r := s.buf.first()
	return r != nil && r.offset < maxOffset
}
func (s *sendStream) Write(b []byte) (int, error) {
	maxSize := dataBufferSizes[2]  
	n := len(b)
	for len(b) > maxSize {
		err := s.push(b[:maxSize], s.length, false)
		if err != nil {
			return 0, err
		}
		b = b[maxSize:]
	}
	err := s.push(b, s.length, false)
	if err != nil {
		return 0, err
	}
	return n, nil
}
func (s *sendStream) ack(offset, length uint64) bool {
	s.acked.push(offset, offset+length)
	complete := s.complete()
	if complete && s.resetStream == deliveryNone && !s.stopReceived {
		s.setClosed()
	}
	return complete
}
func (s *sendStream) complete() bool {
	return s.fin && s.finSent && s.offset >= s.length && s.acked.equals(0, s.length)
}
func (s *sendStream) stop(errorCode uint64) {
	if !s.stopReceived {
		s.stopReceived = true
		if s.resetStream == deliveryNone {
			s.resetError = errorCode
			if s.fin {
				s.resetStream = deliveryConfirmed
			} else {
				s.resetStream = deliveryReady
			}
		}
	}
}
func (s *sendStream) terminate(errorCode uint64) {
	if s.resetStream == deliveryNone {
		s.fin = true
		if !s.stopReceived {
			s.resetError = errorCode
			s.resetStream = deliveryReady
		}
	}
}
func (s *sendStream) setClosed() {
	s.closed = true
}
func (s *sendStream) String() string {
	return fmt.Sprintf("offset=%v length=%v fin=%v size=%v %v", s.offset, s.length, s.fin, s.buf.size(), &s.buf)
}
type streamMap struct {
	streams map[uint64]*Stream
	closedStreams map[uint64]struct{}
	closedStream Stream
	openedStreams struct {
		peerBidi  uint64
		peerUni   uint64
		localBidi uint64
		localUni  uint64
	}
	maxStreams struct {
		peerBidi  uint64
		peerUni   uint64
		localBidi uint64
		localUni  uint64
	}
	maxStreamsNext struct {
		localBidi uint64
		localUni  uint64
	}
	updateMaxStreamsBidi bool
	updateMaxStreamsUni  bool
}
func (s *streamMap) init(maxBidi, maxUni uint64) {
	s.streams = make(map[uint64]*Stream)
	s.closedStreams = make(map[uint64]struct{})
	s.maxStreams.localBidi = maxBidi
	s.maxStreams.localUni = maxUni
	s.maxStreamsNext.localBidi = maxBidi
	s.maxStreamsNext.localUni = maxUni
	s.closedStream = Stream{
		recv: recvStream{
			fin:           true,
			stopSending:   deliveryConfirmed,
			resetReceived: true,
			closed:        true,
		},
		send: sendStream{
			fin:          true,
			finSent:      true,
			resetStream:  deliveryConfirmed,
			stopReceived: true,
			closed:       true,
		},
		bidi: true,
	}
}
func (s *streamMap) get(id uint64) *Stream {
	if _, ok := s.closedStreams[id]; ok {
		return &s.closedStream
	}
	return s.streams[id]
}
func (s *streamMap) getOpen(id uint64) *Stream {
	return s.streams[id]
}
func (s *streamMap) create(id uint64, isClient bool) (*Stream, error) {
	local := isStreamLocal(id, isClient)
	bidi := isStreamBidi(id)
	if local {
		if bidi {
			if s.openedStreams.localBidi >= s.maxStreams.peerBidi || id > s.maxStreams.peerBidi*4 {
				return nil, newError(StreamLimitError, sprint("local bidirectional streams exceeded ", s.maxStreams.peerBidi))
			}
			s.openedStreams.localBidi++
		} else {
			if s.openedStreams.localUni >= s.maxStreams.peerUni || id > s.maxStreams.peerUni*4 {
				return nil, newError(StreamLimitError, sprint("local unidirectional streams exceeded ", s.maxStreams.peerUni))
			}
			s.openedStreams.localUni++
		}
	} else {
		if bidi {
			if s.openedStreams.peerBidi >= s.maxStreams.localBidi || id > s.maxStreams.localBidi*4 {
				return nil, newError(StreamLimitError, sprint("peer bidirectional streams exceeded ", s.maxStreams.localBidi))
			}
			s.openedStreams.peerBidi++
		} else {
			if s.openedStreams.peerUni >= s.maxStreams.localUni || id > s.maxStreams.localUni*4 {
				return nil, newError(StreamLimitError, sprint("peer unidirectional streams exceeded ", s.maxStreams.localUni))
			}
			s.openedStreams.peerUni++
		}
	}
	st := &Stream{}
	st.init(local, bidi)
	s.streams[id] = st
	return st, nil
}
func (s *streamMap) creatableLocalStreamBidi() bool {
	return s.openedStreams.localBidi < s.maxStreams.peerBidi
}